From b363a93ea57d3a5c016bdb064fae8aac447c05f0 Mon Sep 17 00:00:00 2001 From: eof Date: Sun, 5 Apr 2026 17:51:45 +0500 Subject: [PATCH] Update 05.04.2026 --- .gitignore | 2 + README.md | 12 +- install.sh | 3 + tmux/plugins/tmux-battery/LICENSE.md | 19 - tmux/plugins/tmux-battery/README.md | 262 ---- tmux/plugins/tmux-battery/battery.tmux | 62 - .../tmux-battery/scripts/battery_color.sh | 23 - .../scripts/battery_color_charge.sh | 98 -- .../scripts/battery_color_status.sh | 74 -- .../tmux-battery/scripts/battery_graph.sh | 45 - .../tmux-battery/scripts/battery_icon.sh | 21 - .../scripts/battery_icon_charge.sh | 66 - .../scripts/battery_icon_status.sh | 61 - .../scripts/battery_percentage.sh | 41 - .../tmux-battery/scripts/battery_remain.sh | 128 -- .../tmux-battery/scripts/battery_status_bg.sh | 50 - .../tmux-battery/scripts/battery_status_fg.sh | 50 - tmux/plugins/tmux-battery/scripts/helpers.sh | 50 - tmux/plugins/tmux-continuum/LICENSE.md | 19 - tmux/plugins/tmux-continuum/README.md | 98 -- tmux/plugins/tmux-continuum/continuum.tmux | 87 -- .../scripts/check_tmux_version.sh | 33 - .../scripts/continuum_restore.sh | 29 - .../tmux-continuum/scripts/continuum_save.sh | 60 - .../scripts/continuum_status.sh | 25 - .../scripts/handle_tmux_automatic_start.sh | 36 - .../handle_tmux_automatic_start/README.md | 1 - .../osx_disable.sh | 10 - .../handle_tmux_automatic_start/osx_enable.sh | 66 - .../osx_iterm_start_tmux.sh | 66 - .../osx_terminal_start_tmux.sh | 52 - .../systemd_disable.sh | 10 - .../systemd_enable.sh | 56 - .../plugins/tmux-continuum/scripts/helpers.sh | 48 - tmux/plugins/tmux-continuum/scripts/shared.sh | 7 - .../tmux-continuum/scripts/variables.sh | 40 - tmux/plugins/tmux-copycat/LICENSE.md | 19 - tmux/plugins/tmux-copycat/README.md | 142 --- tmux/plugins/tmux-copycat/copycat.tmux | 70 -- .../scripts/check_tmux_version.sh | 78 -- .../scripts/copycat_generate_results.sh | 58 - .../scripts/copycat_git_special.sh | 58 - .../tmux-copycat/scripts/copycat_jump.sh | 289 ----- .../scripts/copycat_mode_bindings.sh | 55 - .../tmux-copycat/scripts/copycat_mode_quit.sh | 38 - .../scripts/copycat_mode_start.sh | 21 - .../tmux-copycat/scripts/copycat_search.sh | 8 - tmux/plugins/tmux-copycat/scripts/helpers.sh | 192 --- .../scripts/stored_search_helpers.sh | 23 - .../plugins/tmux-copycat/scripts/variables.sh | 26 - tmux/plugins/tmux-online-status/LICENSE.md | 19 - tmux/plugins/tmux-online-status/README.md | 92 -- .../tmux-online-status/online_status.tmux | 27 - .../scripts/online_status_icon.sh | 77 -- .../tmux-online-status/scripts/shared.sh | 16 - tmux/plugins/tmux-open/LICENSE.md | 19 - tmux/plugins/tmux-open/README.md | 95 -- tmux/plugins/tmux-open/open.tmux | 142 --- tmux/plugins/tmux-plugin-sysstat/LICENSE | 21 - tmux/plugins/tmux-plugin-sysstat/readme.md | 372 ------ .../tmux-plugin-sysstat/scripts/cpu.sh | 78 -- .../scripts/cpu_collect.sh | 53 - .../tmux-plugin-sysstat/scripts/helpers.sh | 76 -- .../tmux-plugin-sysstat/scripts/loadavg.sh | 28 - .../tmux-plugin-sysstat/scripts/mem.sh | 130 -- .../tmux-plugin-sysstat/scripts/swap.sh | 95 -- tmux/plugins/tmux-plugin-sysstat/sysstat.tmux | 43 - tmux/plugins/tmux-prefix-highlight/README.md | 111 -- .../prefix_highlight.tmux | 117 -- tmux/plugins/tmux-ressurect/LICENSE.md | 19 - tmux/plugins/tmux-ressurect/README.md | 133 -- .../docs/custom_key_bindings.md | 11 - tmux/plugins/tmux-ressurect/docs/hooks.md | 39 - .../docs/migrating_from_tmuxinator.md | 72 -- .../docs/restoring_pane_contents.md | 31 - .../tmux-ressurect/docs/restoring_programs.md | 179 --- .../docs/restoring_shell_history.md | 19 - .../docs/restoring_vim_and_neovim_sessions.md | 15 - tmux/plugins/tmux-ressurect/docs/save_dir.md | 15 - tmux/plugins/tmux-ressurect/resurrect.tmux | 40 - .../save_command_strategies/gdb.sh | 22 - .../save_command_strategies/pgrep.sh | 22 - .../save_command_strategies/ps.sh | 24 - .../scripts/check_tmux_version.sh | 78 -- .../plugins/tmux-ressurect/scripts/helpers.sh | 168 --- .../scripts/process_restore_helpers.sh | 172 --- .../tmux-ressurect/scripts/restore.exp | 14 - .../plugins/tmux-ressurect/scripts/restore.sh | 369 ------ tmux/plugins/tmux-ressurect/scripts/save.sh | 322 ----- .../tmux-ressurect/scripts/spinner_helpers.sh | 8 - .../tmux-ressurect/scripts/tmux_spinner.sh | 29 - .../tmux-ressurect/scripts/variables.sh | 47 - .../strategies/irb_default_strategy.sh | 23 - .../mosh-client_default_strategy.sh | 25 - .../tmux-ressurect/strategies/nvim_session.sh | 30 - .../tmux-ressurect/strategies/vim_session.sh | 32 - tmux/plugins/tmux-sidebar/LICENSE.md | 19 - tmux/plugins/tmux-sidebar/README.md | 74 -- tmux/plugins/tmux-sidebar/docs/options.md | 41 - .../scripts/check_tmux_version.sh | 78 -- .../tmux-sidebar/scripts/custom_tree.sh | 4 - tmux/plugins/tmux-sidebar/scripts/helpers.sh | 101 -- .../scripts/save_sidebar_width.sh | 33 - tmux/plugins/tmux-sidebar/scripts/toggle.sh | 204 ---- .../tmux-sidebar/scripts/tree_helpers.sh | 42 - .../plugins/tmux-sidebar/scripts/variables.sh | 26 - tmux/plugins/tmux-sidebar/sidebar.tmux | 38 - tmux/plugins/tmux-yank/LICENSE.md | 20 - tmux/plugins/tmux-yank/README.md | 288 ----- tmux/plugins/tmux-yank/scripts/copy_line.sh | 111 -- .../tmux-yank/scripts/copy_pane_pwd.sh | 28 - tmux/plugins/tmux-yank/scripts/helpers.sh | 208 ---- tmux/plugins/tmux-yank/yank.tmux | 92 -- tmux/tmux.conf | 64 +- zsh/.devcontainer/devcontainer.json | 20 + zsh/.editorconfig | 7 + zsh/.github/CODEOWNERS | 9 +- zsh/.github/FUNDING.yml | 6 +- zsh/.github/INCIDENT_RESPONSE_PLAN.md | 87 ++ zsh/.github/PULL_REQUEST_TEMPLATE.md | 1 + zsh/.github/dependabot.yml | 14 + zsh/.github/dependencies.yml | 56 + zsh/.github/workflows/dependencies.yml | 43 + zsh/.github/workflows/dependencies/.gitignore | 1 + .../workflows/dependencies/requirements.txt | 7 + zsh/.github/workflows/dependencies/updater.py | 619 ++++++++++ zsh/.github/workflows/installer.yml | 66 + zsh/.github/workflows/installer/.gitignore | 1 + zsh/.github/workflows/installer/.vercelignore | 2 + zsh/.github/workflows/installer/vercel.json | 23 + zsh/.github/workflows/main.yml | 17 +- zsh/.github/workflows/project.yml | 111 +- zsh/.github/workflows/scorecard.yml | 65 + zsh/.gitignore | 12 +- zsh/.gitpod.Dockerfile | 5 - zsh/.gitpod.yml | 9 - zsh/.prettierrc | 4 + zsh/CONTRIBUTING.md | 43 +- zsh/LICENSE.txt | 2 +- zsh/README.md | 349 ++++-- zsh/SECURITY.md | 5 +- zsh/custom/example.zsh | 16 +- zsh/custom/plugins/example/example.plugin.zsh | 1 + .../yandex-cloud/yandex-cloud.plugin.zsh | 5 - zsh/custom/themes/example.zsh-theme | 2 + zsh/lib/async_prompt.zsh | 145 +++ zsh/lib/bzr.zsh | 20 +- zsh/lib/cli.zsh | 168 ++- zsh/lib/clipboard.zsh | 20 +- zsh/lib/compfix.zsh | 2 +- zsh/lib/completion.zsh | 8 +- zsh/lib/correction.zsh | 5 - zsh/lib/diagnostics.zsh | 24 +- zsh/lib/directories.zsh | 2 + zsh/lib/functions.zsh | 33 +- zsh/lib/git.zsh | 288 +++-- zsh/lib/grep.zsh | 6 +- zsh/lib/history.zsh | 26 +- zsh/lib/key-bindings.zsh | 25 +- zsh/lib/misc.zsh | 17 +- zsh/lib/prompt_info_functions.zsh | 4 +- zsh/lib/spectrum.zsh | 1 + zsh/lib/termsupport.zsh | 80 +- zsh/lib/tests/cli.test.zsh | 169 +++ zsh/lib/theme-and-appearance.zsh | 120 +- zsh/lib/vcs_info.zsh | 2 +- zsh/oh-my-zsh.sh | 120 +- zsh/plugins/1password/1password.plugin.zsh | 12 +- zsh/plugins/1password/README.md | 16 +- zsh/plugins/1password/_opswd | 10 - zsh/plugins/1password/opswd | 61 +- zsh/plugins/adb/README.md | 8 - zsh/plugins/adb/_adb | 67 - zsh/plugins/ag/README.md | 13 - zsh/plugins/ag/_ag | 66 - zsh/plugins/alias-finder/.zunit.yml | 9 + zsh/plugins/alias-finder/README.md | 84 +- .../alias-finder/alias-finder.plugin.zsh | 87 +- .../alias-finder/tests/_output/.gitkeep | 0 .../alias-finder/tests/_support/.gitkeep | 0 .../alias-finder/tests/_support/bootstrap | 2 + zsh/plugins/alias-finder/tests/test_run.sh | 107 ++ zsh/plugins/aliases/README.md | 16 +- zsh/plugins/aliases/aliases.plugin.zsh | 2 +- zsh/plugins/aliases/cheatsheet.py | 5 +- zsh/plugins/ansible/README.md | 5 +- zsh/plugins/archlinux/README.md | 1 + zsh/plugins/archlinux/archlinux.plugin.zsh | 52 +- zsh/plugins/arduino-cli/README.md | 9 + .../arduino-cli/arduino-cli.plugin.zsh | 14 + zsh/plugins/argocd/README.md | 20 + zsh/plugins/argocd/argocd.plugin.zsh | 14 + zsh/plugins/asdf/README.md | 61 +- zsh/plugins/asdf/asdf.plugin.zsh | 38 +- zsh/plugins/autoenv/autoenv.plugin.zsh | 16 +- zsh/plugins/autojump/autojump.plugin.zsh | 29 +- zsh/plugins/aws/README.md | 42 +- zsh/plugins/aws/aws.plugin.zsh | 146 ++- zsh/plugins/azure/README.md | 49 + zsh/plugins/azure/azure.plugin.zsh | 60 + zsh/plugins/battery/README.md | 13 + zsh/plugins/battery/battery.plugin.zsh | 54 +- zsh/plugins/bazel/README.md | 19 +- zsh/plugins/bazel/_bazel | 2 +- zsh/plugins/bazel/bazel.plugin.zsh | 9 + zsh/plugins/bedtools/_bedtools | 2 +- zsh/plugins/bgnotify/README.md | 30 +- zsh/plugins/bgnotify/bgnotify.plugin.zsh | 209 ++-- zsh/plugins/branch/README.md | 2 +- zsh/plugins/branch/branch.plugin.zsh | 2 +- zsh/plugins/brew/README.md | 69 +- zsh/plugins/brew/brew.plugin.zsh | 49 +- zsh/plugins/bridgetown/README.md | 26 + zsh/plugins/bridgetown/bridgetown.plugin.zsh | 12 + zsh/plugins/buf/README.md | 9 + zsh/plugins/buf/buf.plugin.zsh | 14 + zsh/plugins/bun/README.md | 20 + zsh/plugins/bun/bun.plugin.zsh | 14 + zsh/plugins/bundler/README.md | 24 +- zsh/plugins/bundler/_bundler | 2 +- zsh/plugins/bundler/bundler.plugin.zsh | 34 +- zsh/plugins/cakephp3/cakephp3.plugin.zsh | 6 +- zsh/plugins/cargo/README.md | 3 - zsh/plugins/cargo/cargo.plugin.zsh | 7 - zsh/plugins/catimg/README.md | 5 +- zsh/plugins/catimg/catimg.plugin.zsh | 8 +- zsh/plugins/catimg/catimg.sh | 14 +- zsh/plugins/chezmoi/README.md | 11 + zsh/plugins/chezmoi/chezmoi.plugin.zsh | 14 + zsh/plugins/chruby/chruby.plugin.zsh | 38 +- zsh/plugins/chucknorris/README.md | 9 +- zsh/plugins/cloudfoundry/README.md | 2 +- zsh/plugins/coffee/README.md | 2 +- zsh/plugins/coffee/_coffee | 2 +- .../colored-man-pages.plugin.zsh | 3 +- zsh/plugins/colorize/colorize.plugin.zsh | 8 +- zsh/plugins/command-not-found/README.md | 8 +- .../command-not-found.plugin.zsh | 11 +- zsh/plugins/common-aliases/README.md | 14 +- zsh/plugins/compleat/compleat.plugin.zsh | 4 +- zsh/plugins/conda-env/README.md | 44 + zsh/plugins/conda-env/conda-env.plugin.zsh | 9 + zsh/plugins/conda/README.md | 37 + zsh/plugins/conda/conda.plugin.zsh | 23 + zsh/plugins/copybuffer/copybuffer.plugin.zsh | 4 +- zsh/plugins/copydir/README.md | 3 - zsh/plugins/copydir/copydir.plugin.zsh | 7 - zsh/plugins/copyfile/copyfile.plugin.zsh | 14 +- zsh/plugins/dash/README.md | 2 +- zsh/plugins/dash/dash.plugin.zsh | 2 +- zsh/plugins/dbt/README.md | 27 + zsh/plugins/dbt/dbt.plugin.zsh | 23 + zsh/plugins/debian/README.md | 7 +- zsh/plugins/debian/debian.plugin.zsh | 8 +- zsh/plugins/deno/README.md | 27 +- zsh/plugins/deno/deno.plugin.zsh | 1 + zsh/plugins/dircycle/README.md | 22 +- zsh/plugins/dircycle/dircycle.plugin.zsh | 45 +- zsh/plugins/direnv/direnv.plugin.zsh | 11 +- zsh/plugins/dirhistory/README.md | 43 + zsh/plugins/dirhistory/dirhistory.plugin.zsh | 25 +- zsh/plugins/dnf/README.md | 3 + zsh/plugins/dnf/_dnf5 | 570 +++++++++ zsh/plugins/dnf/dnf.plugin.zsh | 36 +- zsh/plugins/docker-compose/README.md | 42 +- zsh/plugins/docker-compose/_docker-compose | 2 +- .../docker-compose/docker-compose.plugin.zsh | 9 +- zsh/plugins/docker-machine/README.md | 19 - zsh/plugins/docker-machine/_docker-machine | 359 ------ .../docker-machine/docker-machine.plugin.zsh | 33 - zsh/plugins/docker/README.md | 108 +- zsh/plugins/docker/{ => completions}/_docker | 65 +- zsh/plugins/docker/docker.plugin.zsh | 70 +- zsh/plugins/doctl/doctl.plugin.zsh | 12 +- zsh/plugins/dotenv/README.md | 8 + zsh/plugins/dotenv/dotenv.plugin.zsh | 2 +- zsh/plugins/dotnet/README.md | 6 +- zsh/plugins/dotnet/dotnet.plugin.zsh | 28 +- zsh/plugins/emacs/README.md | 4 +- zsh/plugins/emacs/emacs.plugin.zsh | 6 +- zsh/plugins/emacs/emacsclient.sh | 4 +- zsh/plugins/ember-cli/README.md | 2 +- zsh/plugins/emoji/emoji.plugin.zsh | 18 +- zsh/plugins/emoji/update_emoji.py | 4 +- zsh/plugins/emotty/emotty.plugin.zsh | 2 +- zsh/plugins/encode64/README.md | 23 +- zsh/plugins/encode64/encode64.plugin.zsh | 10 + zsh/plugins/extract/README.md | 103 +- zsh/plugins/extract/_extract | 52 +- zsh/plugins/extract/extract.plugin.zsh | 124 +- zsh/plugins/eza/README.md | 144 +++ zsh/plugins/eza/eza.plugin.zsh | 76 ++ zsh/plugins/fancy-ctrl-z/README.md | 20 +- zsh/plugins/fasd/README.md | 2 +- zsh/plugins/fastfile/README.md | 4 +- zsh/plugins/fastfile/fastfile.plugin.zsh | 4 +- zsh/plugins/fd/README.md | 9 - zsh/plugins/fd/_fd | 273 ----- zsh/plugins/fig/README.md | 9 - zsh/plugins/fig/fig.plugin.zsh | 13 - zsh/plugins/firewalld/firewalld.plugin.zsh | 2 +- zsh/plugins/flutter/_flutter | 37 - zsh/plugins/flutter/flutter.plugin.zsh | 2 +- zsh/plugins/fluxcd/README.md | 9 + zsh/plugins/fluxcd/fluxcd.plugin.zsh | 14 + zsh/plugins/foot/README.md | 35 + zsh/plugins/foot/foot.plugin.zsh | 10 + zsh/plugins/forklift/forklift.plugin.zsh | 10 +- zsh/plugins/frontend-search/README.md | 12 +- zsh/plugins/frontend-search/_frontend | 2 +- .../frontend-search.plugin.zsh | 20 +- zsh/plugins/fzf/fzf.plugin.zsh | 54 +- zsh/plugins/gas/README.md | 2 +- zsh/plugins/gatsby/README.md | 2 +- zsh/plugins/gb/README.md | 21 - zsh/plugins/gb/_gb | 111 -- zsh/plugins/gcloud/gcloud.plugin.zsh | 13 +- zsh/plugins/gem/{ => completions}/_gem | 0 zsh/plugins/gem/gem.plugin.zsh | 27 +- zsh/plugins/git-auto-fetch/README.md | 2 +- .../git-auto-fetch/git-auto-fetch.plugin.zsh | 2 +- zsh/plugins/git-commit/README.md | 47 + zsh/plugins/git-commit/git-commit.plugin.zsh | 58 + zsh/plugins/git-extras/README.md | 2 +- zsh/plugins/git-extras/git-extras.plugin.zsh | 188 +-- zsh/plugins/git-prompt/README.md | 6 + zsh/plugins/git-prompt/git-prompt.plugin.zsh | 14 +- zsh/plugins/git-prompt/gitstatus.py | 15 +- zsh/plugins/git/README.md | 461 +++---- zsh/plugins/git/git.plugin.zsh | 697 ++++++----- zsh/plugins/gitfast/MANUAL.adoc | 40 + zsh/plugins/gitfast/README.md | 6 - zsh/plugins/gitfast/_git | 18 +- zsh/plugins/gitfast/git-completion.bash | 223 +--- zsh/plugins/gitfast/git-prompt.sh | 31 +- zsh/plugins/gitfast/gitfast.plugin.zsh | 2 +- zsh/plugins/gitfast/update | 8 - zsh/plugins/gitignore/README.md | 4 +- zsh/plugins/gitignore/gitignore.plugin.zsh | 17 +- zsh/plugins/gnu-utils/gnu-utils.plugin.zsh | 17 +- zsh/plugins/golang/README.md | 5 +- zsh/plugins/golang/golang.plugin.zsh | 3 + zsh/plugins/gpg-agent/README.md | 7 +- .../plugins/gradle}/LICENSE | 17 +- zsh/plugins/gradle/_gradle | 425 ++++--- zsh/plugins/gradle/gradle.plugin.zsh | 2 +- zsh/plugins/grails/grails.plugin.zsh | 14 +- zsh/plugins/grc/grc.plugin.zsh | 7 +- zsh/plugins/hasura/README.md | 9 + zsh/plugins/hasura/hasura.plugin.zsh | 13 + zsh/plugins/hcloud/README.md | 143 +++ zsh/plugins/hcloud/hcloud.plugin.zsh | 129 ++ zsh/plugins/helm/README.md | 12 +- zsh/plugins/helm/helm.plugin.zsh | 6 + zsh/plugins/heroku-alias/README.md | 140 +++ .../heroku-alias/heroku-alias.plugin.zsh | 92 ++ .../history-substring-search/README.md | 103 +- .../dependencies/OMZ-README.md | 15 + .../history-substring-search.plugin.zsh | 8 +- .../history-substring-search.zsh | 233 ++-- .../update-from-upstream.zsh | 129 -- zsh/plugins/history/README.md | 1 + zsh/plugins/history/history.plugin.zsh | 1 + zsh/plugins/hitchhiker/fortunes/hitchhiker | 36 +- zsh/plugins/httpie/_httpie | 4 +- zsh/plugins/ionic/ionic.plugin.zsh | 12 +- zsh/plugins/ipfs/_ipfs | 2 +- zsh/plugins/isodate/README.md | 4 +- zsh/plugins/iterm2/README.md | 12 + zsh/plugins/iterm2/iterm2.plugin.zsh | 11 + .../iterm2/iterm2_shell_integration.zsh | 178 +++ zsh/plugins/iterm2/update | 4 + zsh/plugins/jira/README.md | 81 +- zsh/plugins/jira/_jira | 3 + zsh/plugins/jira/jira.plugin.zsh | 80 +- zsh/plugins/jj/README.md | 127 ++ zsh/plugins/jj/jj.plugin.zsh | 71 ++ zsh/plugins/jsontools/README.md | 13 +- zsh/plugins/juju/README.md | 2 + zsh/plugins/juju/juju.plugin.zsh | 34 +- zsh/plugins/jump/jump.plugin.zsh | 11 +- zsh/plugins/k9s/README.md | 9 + zsh/plugins/k9s/k9s.plugin.zsh | 14 + zsh/plugins/kamal/README.md | 16 + zsh/plugins/kamal/_kamal | 691 +++++++++++ zsh/plugins/kamal/kamal.plugin.zsh | 25 + zsh/plugins/keychain/keychain.plugin.zsh | 12 +- zsh/plugins/kind/README.md | 22 + zsh/plugins/kind/kind.plugin.zsh | 23 + zsh/plugins/kitchen/_kitchen | 2 +- zsh/plugins/kitty/README.md | 23 + zsh/plugins/kitty/kitty.plugin.zsh | 16 + zsh/plugins/kn/kn.plugin.zsh | 2 +- zsh/plugins/kompose/README.md | 12 + zsh/plugins/kompose/kompose.plugin.zsh | 3 + zsh/plugins/kube-ps1/LICENSE | 201 +++ zsh/plugins/kube-ps1/README.md | 203 ++- zsh/plugins/kube-ps1/kube-ps1.plugin.zsh | 284 +++-- zsh/plugins/kubectl/README.md | 240 ++-- zsh/plugins/kubectl/kubectl.plugin.zsh | 69 +- zsh/plugins/kubectx/README.md | 44 +- zsh/plugins/kubectx/kubectx.plugin.zsh | 6 +- zsh/plugins/lando/README.md | 25 +- zsh/plugins/lando/lando.plugin.zsh | 35 +- zsh/plugins/laravel/README.md | 7 + zsh/plugins/laravel/laravel.plugin.zsh | 7 + .../last-working-dir.plugin.zsh | 17 +- zsh/plugins/localstack/README.md | 24 + zsh/plugins/localstack/localstack.plugin.zsh | 37 + zsh/plugins/localstack/sqs-send-result.png | Bin 0 -> 70661 bytes zsh/plugins/lol/README.md | 4 +- zsh/plugins/lol/lol.plugin.zsh | 2 +- zsh/plugins/lpass/_lpass | 2 +- zsh/plugins/macos/README.md | 15 +- zsh/plugins/macos/macos.plugin.zsh | 56 +- zsh/plugins/macos/spotify | 37 +- zsh/plugins/macports/README.md | 2 +- zsh/plugins/macports/_port | 8 +- .../magic-enter/magic-enter.plugin.zsh | 6 +- zsh/plugins/marked2/README.md | 2 +- zsh/plugins/marked2/marked2.plugin.zsh | 7 +- zsh/plugins/marktext/README.md | 17 + zsh/plugins/marktext/marktext.plugin.zsh | 7 + zsh/plugins/minikube/minikube.plugin.zsh | 24 +- zsh/plugins/mise/README.md | 32 + zsh/plugins/mise/mise.plugin.zsh | 17 + zsh/plugins/mix/README.md | 1 + zsh/plugins/mix/_mix | 16 +- zsh/plugins/molecule/README.md | 20 + zsh/plugins/molecule/molecule.plugin.zsh | 22 + zsh/plugins/mongo-atlas/README.md | 10 + .../mongo-atlas/mongo-atlas.plugin.zsh | 14 + zsh/plugins/mvn/README.md | 4 +- zsh/plugins/mvn/mvn.plugin.zsh | 18 +- .../n98-magerun/n98-magerun.plugin.zsh | 2 +- zsh/plugins/nats/README.md | 14 + zsh/plugins/nats/nats.plugin.zsh | 23 + zsh/plugins/nestjs/README.md | 52 + zsh/plugins/nestjs/nestjs.plugin.zsh | 41 + zsh/plugins/ngrok/README.md | 20 + zsh/plugins/ngrok/ngrok.plugin.zsh | 14 + zsh/plugins/nmap/nmap.plugin.zsh | 2 +- zsh/plugins/nodenv/README.md | 20 + zsh/plugins/nodenv/nodenv.plugin.zsh | 43 + zsh/plugins/nomad/_nomad | 4 +- zsh/plugins/npm/README.md | 2 + zsh/plugins/npm/npm.plugin.zsh | 10 +- zsh/plugins/npx/README.md | 16 - zsh/plugins/npx/npx.plugin.zsh | 12 - zsh/plugins/nvm/README.md | 48 +- zsh/plugins/nvm/_nvm | 34 - zsh/plugins/nvm/nvm.plugin.zsh | 108 +- zsh/plugins/opentofu/README.md | 61 + zsh/plugins/opentofu/opentofu.plugin.zsh | 46 + zsh/plugins/osx/README.md | 3 - zsh/plugins/osx/osx.plugin.zsh | 5 - zsh/plugins/otp/README.md | 2 +- zsh/plugins/pass/_pass | 7 +- zsh/plugins/per-directory-history/README.md | 6 +- .../per-directory-history.zsh | 14 +- zsh/plugins/perl/README.md | 40 +- zsh/plugins/perl/perl.plugin.zsh | 9 + zsh/plugins/perms/README.md | 16 +- zsh/plugins/perms/perms.plugin.zsh | 27 +- zsh/plugins/pip/README.md | 20 +- zsh/plugins/pip/pip.plugin.zsh | 30 +- zsh/plugins/pipenv/README.md | 16 +- zsh/plugins/pipenv/pipenv.plugin.zsh | 59 +- zsh/plugins/pm2/_pm2 | 398 ++++-- zsh/plugins/pod/_pod | 2 +- zsh/plugins/podman/README.md | 47 + zsh/plugins/podman/podman.plugin.zsh | 47 + zsh/plugins/poetry-env/README.md | 10 + zsh/plugins/poetry-env/poetry-env.plugin.zsh | 27 + zsh/plugins/poetry/README.md | 33 + zsh/plugins/poetry/poetry.plugin.zsh | 28 + zsh/plugins/postgres/README.md | 2 +- zsh/plugins/pre-commit/README.md | 22 + zsh/plugins/pre-commit/pre-commit.plugin.zsh | 17 + zsh/plugins/procs/README.md | 9 + zsh/plugins/procs/procs.plugin.zsh | 21 + zsh/plugins/pulumi/README.md | 41 + zsh/plugins/pulumi/pulumi.plugin.zsh | 28 + zsh/plugins/pyenv/README.md | 18 +- zsh/plugins/pyenv/pyenv.plugin.zsh | 16 +- zsh/plugins/python/README.md | 49 +- zsh/plugins/python/python.plugin.zsh | 59 +- zsh/plugins/qodana/README.md | 20 + zsh/plugins/qodana/qodana.plugin.zsh | 14 + zsh/plugins/qrcode/README.md | 8 + zsh/plugins/qrcode/qrcode.plugin.zsh | 17 + zsh/plugins/rails/README.md | 6 +- zsh/plugins/rails/_rails | 1004 +++++++-------- zsh/plugins/rails/rails.plugin.zsh | 6 +- zsh/plugins/rake-fast/rake-fast.plugin.zsh | 42 +- zsh/plugins/rand-quote/rand-quote.plugin.zsh | 2 +- zsh/plugins/rbfu/README.md | 18 - zsh/plugins/rbfu/rbfu.plugin.zsh | 49 - zsh/plugins/rbw/rbw.plugin.zsh | 17 +- zsh/plugins/rclone/README.md | 9 + zsh/plugins/rclone/rclone.plugin.zsh | 14 + zsh/plugins/react-native/README.md | 4 + .../react-native/react-native.plugin.zsh | 4 + zsh/plugins/repo/_repo | 2 + zsh/plugins/ripgrep/README.md | 9 - zsh/plugins/ripgrep/_ripgrep | 640 ---------- zsh/plugins/ros/_ros | 2 +- zsh/plugins/rsync/README.md | 26 +- zsh/plugins/ruby/ruby.plugin.zsh | 2 +- zsh/plugins/rust/rust.plugin.zsh | 2 +- zsh/plugins/rustup/README.md | 3 - zsh/plugins/rustup/rustup.plugin.zsh | 7 - zsh/plugins/rvm/README.md | 1 + zsh/plugins/rvm/rvm.plugin.zsh | 1 + zsh/plugins/safe-paste/safe-paste.plugin.zsh | 3 +- zsh/plugins/sbt/sbt.plugin.zsh | 2 +- zsh/plugins/scala/_scala | 2 +- zsh/plugins/scd/scd | 2 +- zsh/plugins/screen/screen.plugin.zsh | 6 +- zsh/plugins/scw/README.md | 10 +- zsh/plugins/scw/_scw | 333 ----- zsh/plugins/scw/scw.plugin.zsh | 14 + zsh/plugins/shell-proxy/README.md | 5 + zsh/plugins/shell-proxy/proxy.py | 23 +- .../shell-proxy/shell-proxy.plugin.zsh | 2 +- zsh/plugins/shell-proxy/ssh-proxy.py | 3 +- .../shrink-path/shrink-path.plugin.zsh | 25 +- zsh/plugins/sigstore/README.md | 13 + zsh/plugins/sigstore/sigstore.plugin.zsh | 22 + zsh/plugins/singlechar/singlechar.plugin.zsh | 2 +- zsh/plugins/skaffold/README.md | 9 + zsh/plugins/skaffold/skaffold.plugin.zsh | 14 + zsh/plugins/snap/README.md | 18 + zsh/plugins/snap/snap.plugin.zsh | 10 + zsh/plugins/spackenv/README.md | 17 + zsh/plugins/spackenv/spackenv.plugin.zsh | 5 + zsh/plugins/spring/README.md | 14 +- zsh/plugins/ssh-agent/README.md | 29 +- zsh/plugins/ssh-agent/ssh-agent.plugin.zsh | 19 +- zsh/plugins/ssh/README.md | 16 + zsh/plugins/ssh/ssh.plugin.zsh | 53 + zsh/plugins/starship/README.md | 21 + zsh/plugins/starship/starship.plugin.zsh | 8 + zsh/plugins/stripe/README.md | 9 + zsh/plugins/stripe/stripe.plugin.zsh | 13 + zsh/plugins/sublime/sublime.plugin.zsh | 4 +- zsh/plugins/sudo/sudo.plugin.zsh | 2 +- zsh/plugins/suse/README.md | 8 +- zsh/plugins/swiftpm/README.md | 4 +- zsh/plugins/swiftpm/_swift | 1086 +++++++++++------ zsh/plugins/symfony6/README.md | 9 + zsh/plugins/symfony6/symfony6.plugin.zsh | 82 ++ zsh/plugins/systemadmin/README.md | 5 +- .../systemadmin/systemadmin.plugin.zsh | 111 +- zsh/plugins/systemd/README.md | 1 + zsh/plugins/systemd/systemd.plugin.zsh | 5 + zsh/plugins/tailscale/README.md | 11 + zsh/plugins/tailscale/tailscale.plugin.zsh | 25 + zsh/plugins/task/README.md | 9 + zsh/plugins/task/task.plugin.zsh | 14 + zsh/plugins/term_tab/README | 16 - zsh/plugins/term_tab/README.md | 18 + zsh/plugins/term_tab/term_tab.plugin.zsh | 1 + zsh/plugins/terraform/README.md | 48 +- zsh/plugins/terraform/_terraform | 864 +++++++------ zsh/plugins/terraform/terraform.plugin.zsh | 26 +- zsh/plugins/thefuck/thefuck.plugin.zsh | 4 +- zsh/plugins/thor/README.md | 2 +- zsh/plugins/tig/tig.plugin.zsh | 2 + zsh/plugins/timer/timer.plugin.zsh | 5 +- zsh/plugins/timoni/README.md | 9 + zsh/plugins/timoni/timoni.plugin.zsh | 14 + zsh/plugins/tldr/README.md | 18 + zsh/plugins/tldr/tldr.plugin.zsh | 19 + zsh/plugins/tmux/README.md | 41 +- zsh/plugins/tmux/tmux.plugin.zsh | 125 +- zsh/plugins/toolbox/README.md | 12 +- zsh/plugins/toolbox/kubectx.plugin.zsh | 3 - zsh/plugins/toolbox/toolbox.plugin.zsh | 13 +- zsh/plugins/tt/README.MD | 26 + zsh/plugins/tt/tt.plugin.zsh | 21 + zsh/plugins/ubuntu/README.md | 17 +- zsh/plugins/ubuntu/ubuntu.plugin.zsh | 15 +- zsh/plugins/ufw/README.md | 2 +- zsh/plugins/universalarchive/README.md | 88 +- zsh/plugins/uv/README.md | 36 + zsh/plugins/uv/uv.plugin.zsh | 47 + zsh/plugins/vagrant-prompt/README.md | 50 +- .../vagrant-prompt/vagrant-prompt.plugin.zsh | 45 +- zsh/plugins/vault/README.md | 8 +- zsh/plugins/vault/_vault | 400 ------ zsh/plugins/vault/vault.plugin.zsh | 7 + zsh/plugins/vi-mode/README.md | 71 +- zsh/plugins/vi-mode/vi-mode.plugin.zsh | 79 +- zsh/plugins/vim-interaction/README.md | 22 +- .../vim-interaction.plugin.zsh | 2 +- zsh/plugins/virtualenv/virtualenv.plugin.zsh | 2 +- .../virtualenvwrapper.plugin.zsh | 4 +- zsh/plugins/volta/volta.plugin.zsh | 2 +- zsh/plugins/vscode/README.md | 82 +- zsh/plugins/vscode/vscode.plugin.zsh | 15 +- zsh/plugins/watson/README.md | 9 + zsh/plugins/watson/_watson | 34 + zsh/plugins/wd/README.md | 57 +- zsh/plugins/wd/_wd.sh | 10 +- zsh/plugins/wd/wd.plugin.zsh | 9 +- zsh/plugins/wd/wd.sh | 267 +++- zsh/plugins/web-search/README.md | 86 +- zsh/plugins/web-search/web-search.plugin.zsh | 39 +- zsh/plugins/xcode/README.md | 2 - zsh/plugins/xcode/xcode.plugin.zsh | 9 +- zsh/plugins/yarn/README.md | 96 +- zsh/plugins/yarn/_yarn | 14 +- zsh/plugins/yarn/yarn.plugin.zsh | 36 +- zsh/plugins/yii2/README.md | 4 +- zsh/plugins/yum/README.md | 2 +- zsh/plugins/z/LICENSE | 2 +- zsh/plugins/z/MANUAL.md | 82 +- zsh/plugins/z/Makefile | 4 - zsh/plugins/z/README | 148 --- zsh/plugins/z/_z | 2 +- zsh/plugins/z/img/demo.gif | Bin 0 -> 1271520 bytes zsh/plugins/z/img/mit_license.svg | 1 + zsh/plugins/z/img/zsh_4.3.11_plus.svg | 1 + zsh/plugins/z/z.1 | 173 --- zsh/plugins/z/z.plugin.zsh | 114 +- zsh/plugins/z/z.sh | 267 ---- zsh/plugins/zoxide/README.md | 3 + zsh/plugins/zoxide/zoxide.plugin.zsh | 2 +- zsh/plugins/zsh-interactive-cd/LICENSE | 375 ++++++ zsh/plugins/zsh-interactive-cd/README.md | 28 +- zsh/plugins/zsh-interactive-cd/demo.gif | Bin 0 -> 1497944 bytes .../zsh-interactive-cd.plugin.zsh | 54 +- zsh/plugins/zsh-navigation-tools/README.md | 2 +- .../zsh-navigation-tools/doc/n-preview | 2 +- zsh/plugins/zsh-navigation-tools/n-list | 8 +- zsh/templates/minimal.zshrc | 5 + zsh/templates/zshrc.zsh-template | 21 +- zsh/themes/Soliah.zsh-theme | 10 +- zsh/themes/adben.zsh-theme | 2 +- zsh/themes/af-magic.zsh-theme | 7 +- zsh/themes/agnoster.zsh-theme | 193 ++- zsh/themes/amuse.zsh-theme | 8 +- zsh/themes/aussiegeek.zsh-theme | 8 +- zsh/themes/avit.zsh-theme | 9 +- zsh/themes/bira.zsh-theme | 8 +- zsh/themes/blinks.zsh-theme | 4 +- zsh/themes/bureau.zsh-theme | 7 + zsh/themes/crunch.zsh-theme | 6 +- zsh/themes/dpoggi.zsh-theme | 5 +- zsh/themes/eastwood.zsh-theme | 2 +- zsh/themes/emotty.zsh-theme | 4 +- zsh/themes/essembeh.zsh-theme | 20 +- zsh/themes/fino-time.zsh-theme | 1 + zsh/themes/fishy.zsh-theme | 3 +- zsh/themes/gallois.zsh-theme | 136 ++- zsh/themes/gnzh.zsh-theme | 7 +- zsh/themes/half-life.zsh-theme | 6 +- zsh/themes/jonathan.zsh-theme | 10 +- zsh/themes/josh.zsh-theme | 8 +- zsh/themes/juanghurtado.zsh-theme | 5 +- zsh/themes/junkfood.zsh-theme | 4 +- zsh/themes/michelebologna.zsh-theme | 11 +- zsh/themes/mlh.zsh-theme | 12 +- zsh/themes/mortalscumbag.zsh-theme | 10 +- zsh/themes/nicoulaj.zsh-theme | 12 +- zsh/themes/oldgallois.zsh-theme | 24 + zsh/themes/pygmalion.zsh-theme | 36 +- zsh/themes/refined.zsh-theme | 4 +- zsh/themes/rkj-repos.zsh-theme | 2 +- zsh/themes/robbyrussell.zsh-theme | 6 +- zsh/themes/sonicradish.zsh-theme | 4 +- zsh/themes/wedisagree.zsh-theme | 14 +- zsh/tools/changelog.sh | 130 +- zsh/tools/check_for_upgrade.sh | 245 ++-- zsh/tools/install.sh | 110 +- zsh/tools/theme_chooser.sh | 2 +- zsh/tools/uninstall.sh | 23 +- zsh/tools/upgrade.sh | 100 +- zshrc | 45 +- 680 files changed, 16892 insertions(+), 16586 deletions(-) delete mode 100644 tmux/plugins/tmux-battery/LICENSE.md delete mode 100644 tmux/plugins/tmux-battery/README.md delete mode 100755 tmux/plugins/tmux-battery/battery.tmux delete mode 100755 tmux/plugins/tmux-battery/scripts/battery_color.sh delete mode 100755 tmux/plugins/tmux-battery/scripts/battery_color_charge.sh delete mode 100755 tmux/plugins/tmux-battery/scripts/battery_color_status.sh delete mode 100755 tmux/plugins/tmux-battery/scripts/battery_graph.sh delete mode 100755 tmux/plugins/tmux-battery/scripts/battery_icon.sh delete mode 100755 tmux/plugins/tmux-battery/scripts/battery_icon_charge.sh delete mode 100755 tmux/plugins/tmux-battery/scripts/battery_icon_status.sh delete mode 100755 tmux/plugins/tmux-battery/scripts/battery_percentage.sh delete mode 100755 tmux/plugins/tmux-battery/scripts/battery_remain.sh delete mode 100755 tmux/plugins/tmux-battery/scripts/battery_status_bg.sh delete mode 100755 tmux/plugins/tmux-battery/scripts/battery_status_fg.sh delete mode 100644 tmux/plugins/tmux-battery/scripts/helpers.sh delete mode 100644 tmux/plugins/tmux-continuum/LICENSE.md delete mode 100644 tmux/plugins/tmux-continuum/README.md delete mode 100755 tmux/plugins/tmux-continuum/continuum.tmux delete mode 100755 tmux/plugins/tmux-continuum/scripts/check_tmux_version.sh delete mode 100755 tmux/plugins/tmux-continuum/scripts/continuum_restore.sh delete mode 100755 tmux/plugins/tmux-continuum/scripts/continuum_save.sh delete mode 100755 tmux/plugins/tmux-continuum/scripts/continuum_status.sh delete mode 100755 tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start.sh delete mode 120000 tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/README.md delete mode 100755 tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_disable.sh delete mode 100755 tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_enable.sh delete mode 100755 tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_iterm_start_tmux.sh delete mode 100755 tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_terminal_start_tmux.sh delete mode 100755 tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/systemd_disable.sh delete mode 100755 tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/systemd_enable.sh delete mode 100644 tmux/plugins/tmux-continuum/scripts/helpers.sh delete mode 100644 tmux/plugins/tmux-continuum/scripts/shared.sh delete mode 100644 tmux/plugins/tmux-continuum/scripts/variables.sh delete mode 100644 tmux/plugins/tmux-copycat/LICENSE.md delete mode 100644 tmux/plugins/tmux-copycat/README.md delete mode 100755 tmux/plugins/tmux-copycat/copycat.tmux delete mode 100755 tmux/plugins/tmux-copycat/scripts/check_tmux_version.sh delete mode 100755 tmux/plugins/tmux-copycat/scripts/copycat_generate_results.sh delete mode 100755 tmux/plugins/tmux-copycat/scripts/copycat_git_special.sh delete mode 100755 tmux/plugins/tmux-copycat/scripts/copycat_jump.sh delete mode 100755 tmux/plugins/tmux-copycat/scripts/copycat_mode_bindings.sh delete mode 100755 tmux/plugins/tmux-copycat/scripts/copycat_mode_quit.sh delete mode 100755 tmux/plugins/tmux-copycat/scripts/copycat_mode_start.sh delete mode 100755 tmux/plugins/tmux-copycat/scripts/copycat_search.sh delete mode 100644 tmux/plugins/tmux-copycat/scripts/helpers.sh delete mode 100644 tmux/plugins/tmux-copycat/scripts/stored_search_helpers.sh delete mode 100644 tmux/plugins/tmux-copycat/scripts/variables.sh delete mode 100644 tmux/plugins/tmux-online-status/LICENSE.md delete mode 100644 tmux/plugins/tmux-online-status/README.md delete mode 100755 tmux/plugins/tmux-online-status/online_status.tmux delete mode 100755 tmux/plugins/tmux-online-status/scripts/online_status_icon.sh delete mode 100644 tmux/plugins/tmux-online-status/scripts/shared.sh delete mode 100644 tmux/plugins/tmux-open/LICENSE.md delete mode 100644 tmux/plugins/tmux-open/README.md delete mode 100755 tmux/plugins/tmux-open/open.tmux delete mode 100644 tmux/plugins/tmux-plugin-sysstat/LICENSE delete mode 100644 tmux/plugins/tmux-plugin-sysstat/readme.md delete mode 100755 tmux/plugins/tmux-plugin-sysstat/scripts/cpu.sh delete mode 100755 tmux/plugins/tmux-plugin-sysstat/scripts/cpu_collect.sh delete mode 100755 tmux/plugins/tmux-plugin-sysstat/scripts/helpers.sh delete mode 100755 tmux/plugins/tmux-plugin-sysstat/scripts/loadavg.sh delete mode 100755 tmux/plugins/tmux-plugin-sysstat/scripts/mem.sh delete mode 100755 tmux/plugins/tmux-plugin-sysstat/scripts/swap.sh delete mode 100755 tmux/plugins/tmux-plugin-sysstat/sysstat.tmux delete mode 100644 tmux/plugins/tmux-prefix-highlight/README.md delete mode 100755 tmux/plugins/tmux-prefix-highlight/prefix_highlight.tmux delete mode 100644 tmux/plugins/tmux-ressurect/LICENSE.md delete mode 100644 tmux/plugins/tmux-ressurect/README.md delete mode 100644 tmux/plugins/tmux-ressurect/docs/custom_key_bindings.md delete mode 100644 tmux/plugins/tmux-ressurect/docs/hooks.md delete mode 100644 tmux/plugins/tmux-ressurect/docs/migrating_from_tmuxinator.md delete mode 100644 tmux/plugins/tmux-ressurect/docs/restoring_pane_contents.md delete mode 100644 tmux/plugins/tmux-ressurect/docs/restoring_programs.md delete mode 100644 tmux/plugins/tmux-ressurect/docs/restoring_shell_history.md delete mode 100644 tmux/plugins/tmux-ressurect/docs/restoring_vim_and_neovim_sessions.md delete mode 100644 tmux/plugins/tmux-ressurect/docs/save_dir.md delete mode 100755 tmux/plugins/tmux-ressurect/resurrect.tmux delete mode 100755 tmux/plugins/tmux-ressurect/save_command_strategies/gdb.sh delete mode 100755 tmux/plugins/tmux-ressurect/save_command_strategies/pgrep.sh delete mode 100755 tmux/plugins/tmux-ressurect/save_command_strategies/ps.sh delete mode 100755 tmux/plugins/tmux-ressurect/scripts/check_tmux_version.sh delete mode 100644 tmux/plugins/tmux-ressurect/scripts/helpers.sh delete mode 100644 tmux/plugins/tmux-ressurect/scripts/process_restore_helpers.sh delete mode 100755 tmux/plugins/tmux-ressurect/scripts/restore.exp delete mode 100755 tmux/plugins/tmux-ressurect/scripts/restore.sh delete mode 100755 tmux/plugins/tmux-ressurect/scripts/save.sh delete mode 100644 tmux/plugins/tmux-ressurect/scripts/spinner_helpers.sh delete mode 100755 tmux/plugins/tmux-ressurect/scripts/tmux_spinner.sh delete mode 100644 tmux/plugins/tmux-ressurect/scripts/variables.sh delete mode 100755 tmux/plugins/tmux-ressurect/strategies/irb_default_strategy.sh delete mode 100755 tmux/plugins/tmux-ressurect/strategies/mosh-client_default_strategy.sh delete mode 100755 tmux/plugins/tmux-ressurect/strategies/nvim_session.sh delete mode 100755 tmux/plugins/tmux-ressurect/strategies/vim_session.sh delete mode 100644 tmux/plugins/tmux-sidebar/LICENSE.md delete mode 100644 tmux/plugins/tmux-sidebar/README.md delete mode 100644 tmux/plugins/tmux-sidebar/docs/options.md delete mode 100755 tmux/plugins/tmux-sidebar/scripts/check_tmux_version.sh delete mode 100755 tmux/plugins/tmux-sidebar/scripts/custom_tree.sh delete mode 100644 tmux/plugins/tmux-sidebar/scripts/helpers.sh delete mode 100755 tmux/plugins/tmux-sidebar/scripts/save_sidebar_width.sh delete mode 100755 tmux/plugins/tmux-sidebar/scripts/toggle.sh delete mode 100644 tmux/plugins/tmux-sidebar/scripts/tree_helpers.sh delete mode 100644 tmux/plugins/tmux-sidebar/scripts/variables.sh delete mode 100755 tmux/plugins/tmux-sidebar/sidebar.tmux delete mode 100644 tmux/plugins/tmux-yank/LICENSE.md delete mode 100644 tmux/plugins/tmux-yank/README.md delete mode 100755 tmux/plugins/tmux-yank/scripts/copy_line.sh delete mode 100755 tmux/plugins/tmux-yank/scripts/copy_pane_pwd.sh delete mode 100644 tmux/plugins/tmux-yank/scripts/helpers.sh delete mode 100755 tmux/plugins/tmux-yank/yank.tmux create mode 100644 zsh/.devcontainer/devcontainer.json create mode 100644 zsh/.github/INCIDENT_RESPONSE_PLAN.md create mode 100644 zsh/.github/dependabot.yml create mode 100644 zsh/.github/dependencies.yml create mode 100644 zsh/.github/workflows/dependencies.yml create mode 100644 zsh/.github/workflows/dependencies/.gitignore create mode 100644 zsh/.github/workflows/dependencies/requirements.txt create mode 100644 zsh/.github/workflows/dependencies/updater.py create mode 100644 zsh/.github/workflows/installer.yml create mode 100644 zsh/.github/workflows/installer/.gitignore create mode 100644 zsh/.github/workflows/installer/.vercelignore create mode 100644 zsh/.github/workflows/installer/vercel.json create mode 100644 zsh/.github/workflows/scorecard.yml delete mode 100644 zsh/.gitpod.Dockerfile delete mode 100644 zsh/.gitpod.yml create mode 100644 zsh/.prettierrc delete mode 100644 zsh/custom/plugins/yandex-cloud/yandex-cloud.plugin.zsh create mode 100644 zsh/lib/async_prompt.zsh create mode 100644 zsh/lib/tests/cli.test.zsh delete mode 100644 zsh/plugins/adb/README.md delete mode 100644 zsh/plugins/adb/_adb delete mode 100644 zsh/plugins/ag/README.md delete mode 100644 zsh/plugins/ag/_ag create mode 100644 zsh/plugins/alias-finder/.zunit.yml create mode 100644 zsh/plugins/alias-finder/tests/_output/.gitkeep create mode 100644 zsh/plugins/alias-finder/tests/_support/.gitkeep create mode 100644 zsh/plugins/alias-finder/tests/_support/bootstrap create mode 100644 zsh/plugins/alias-finder/tests/test_run.sh create mode 100644 zsh/plugins/arduino-cli/README.md create mode 100644 zsh/plugins/arduino-cli/arduino-cli.plugin.zsh create mode 100644 zsh/plugins/argocd/README.md create mode 100644 zsh/plugins/argocd/argocd.plugin.zsh create mode 100644 zsh/plugins/azure/README.md create mode 100644 zsh/plugins/azure/azure.plugin.zsh create mode 100644 zsh/plugins/bazel/bazel.plugin.zsh create mode 100644 zsh/plugins/bridgetown/README.md create mode 100644 zsh/plugins/bridgetown/bridgetown.plugin.zsh create mode 100644 zsh/plugins/buf/README.md create mode 100644 zsh/plugins/buf/buf.plugin.zsh create mode 100644 zsh/plugins/bun/README.md create mode 100644 zsh/plugins/bun/bun.plugin.zsh delete mode 100644 zsh/plugins/cargo/README.md delete mode 100644 zsh/plugins/cargo/cargo.plugin.zsh create mode 100644 zsh/plugins/chezmoi/README.md create mode 100644 zsh/plugins/chezmoi/chezmoi.plugin.zsh create mode 100644 zsh/plugins/conda-env/README.md create mode 100644 zsh/plugins/conda-env/conda-env.plugin.zsh create mode 100644 zsh/plugins/conda/README.md create mode 100644 zsh/plugins/conda/conda.plugin.zsh delete mode 100644 zsh/plugins/copydir/README.md delete mode 100644 zsh/plugins/copydir/copydir.plugin.zsh create mode 100644 zsh/plugins/dbt/README.md create mode 100644 zsh/plugins/dbt/dbt.plugin.zsh create mode 100644 zsh/plugins/dnf/_dnf5 delete mode 100644 zsh/plugins/docker-machine/README.md delete mode 100644 zsh/plugins/docker-machine/_docker-machine delete mode 100644 zsh/plugins/docker-machine/docker-machine.plugin.zsh rename zsh/plugins/docker/{ => completions}/_docker (97%) create mode 100644 zsh/plugins/eza/README.md create mode 100644 zsh/plugins/eza/eza.plugin.zsh delete mode 100644 zsh/plugins/fd/README.md delete mode 100644 zsh/plugins/fd/_fd delete mode 100644 zsh/plugins/fig/README.md delete mode 100644 zsh/plugins/fig/fig.plugin.zsh delete mode 100644 zsh/plugins/flutter/_flutter create mode 100644 zsh/plugins/fluxcd/README.md create mode 100644 zsh/plugins/fluxcd/fluxcd.plugin.zsh create mode 100644 zsh/plugins/foot/README.md create mode 100644 zsh/plugins/foot/foot.plugin.zsh delete mode 100644 zsh/plugins/gb/README.md delete mode 100644 zsh/plugins/gb/_gb rename zsh/plugins/gem/{ => completions}/_gem (100%) create mode 100644 zsh/plugins/git-commit/README.md create mode 100644 zsh/plugins/git-commit/git-commit.plugin.zsh create mode 100644 zsh/plugins/gitfast/MANUAL.adoc delete mode 100755 zsh/plugins/gitfast/update rename {tmux/plugins/tmux-prefix-highlight => zsh/plugins/gradle}/LICENSE (60%) create mode 100644 zsh/plugins/hasura/README.md create mode 100644 zsh/plugins/hasura/hasura.plugin.zsh create mode 100644 zsh/plugins/hcloud/README.md create mode 100644 zsh/plugins/hcloud/hcloud.plugin.zsh create mode 100644 zsh/plugins/heroku-alias/README.md create mode 100644 zsh/plugins/heroku-alias/heroku-alias.plugin.zsh create mode 100644 zsh/plugins/history-substring-search/dependencies/OMZ-README.md delete mode 100755 zsh/plugins/history-substring-search/update-from-upstream.zsh create mode 100644 zsh/plugins/iterm2/iterm2_shell_integration.zsh create mode 100755 zsh/plugins/iterm2/update create mode 100644 zsh/plugins/jj/README.md create mode 100644 zsh/plugins/jj/jj.plugin.zsh create mode 100644 zsh/plugins/k9s/README.md create mode 100644 zsh/plugins/k9s/k9s.plugin.zsh create mode 100644 zsh/plugins/kamal/README.md create mode 100644 zsh/plugins/kamal/_kamal create mode 100644 zsh/plugins/kamal/kamal.plugin.zsh create mode 100644 zsh/plugins/kind/README.md create mode 100644 zsh/plugins/kind/kind.plugin.zsh create mode 100644 zsh/plugins/kitty/README.md create mode 100644 zsh/plugins/kitty/kitty.plugin.zsh create mode 100644 zsh/plugins/kompose/README.md create mode 100644 zsh/plugins/kompose/kompose.plugin.zsh create mode 100644 zsh/plugins/kube-ps1/LICENSE create mode 100644 zsh/plugins/localstack/README.md create mode 100644 zsh/plugins/localstack/localstack.plugin.zsh create mode 100644 zsh/plugins/localstack/sqs-send-result.png create mode 100644 zsh/plugins/marktext/README.md create mode 100644 zsh/plugins/marktext/marktext.plugin.zsh create mode 100644 zsh/plugins/mise/README.md create mode 100644 zsh/plugins/mise/mise.plugin.zsh create mode 100644 zsh/plugins/molecule/README.md create mode 100644 zsh/plugins/molecule/molecule.plugin.zsh create mode 100644 zsh/plugins/mongo-atlas/README.md create mode 100644 zsh/plugins/mongo-atlas/mongo-atlas.plugin.zsh create mode 100644 zsh/plugins/nats/README.md create mode 100644 zsh/plugins/nats/nats.plugin.zsh create mode 100644 zsh/plugins/nestjs/README.md create mode 100644 zsh/plugins/nestjs/nestjs.plugin.zsh create mode 100644 zsh/plugins/ngrok/README.md create mode 100644 zsh/plugins/ngrok/ngrok.plugin.zsh create mode 100644 zsh/plugins/nodenv/README.md create mode 100644 zsh/plugins/nodenv/nodenv.plugin.zsh delete mode 100644 zsh/plugins/npx/README.md delete mode 100644 zsh/plugins/npx/npx.plugin.zsh delete mode 100644 zsh/plugins/nvm/_nvm create mode 100644 zsh/plugins/opentofu/README.md create mode 100644 zsh/plugins/opentofu/opentofu.plugin.zsh delete mode 100644 zsh/plugins/osx/README.md delete mode 100644 zsh/plugins/osx/osx.plugin.zsh create mode 100644 zsh/plugins/podman/README.md create mode 100644 zsh/plugins/podman/podman.plugin.zsh create mode 100644 zsh/plugins/poetry-env/README.md create mode 100644 zsh/plugins/poetry-env/poetry-env.plugin.zsh create mode 100644 zsh/plugins/pre-commit/README.md create mode 100644 zsh/plugins/pre-commit/pre-commit.plugin.zsh create mode 100644 zsh/plugins/procs/README.md create mode 100644 zsh/plugins/procs/procs.plugin.zsh create mode 100644 zsh/plugins/pulumi/README.md create mode 100644 zsh/plugins/pulumi/pulumi.plugin.zsh create mode 100644 zsh/plugins/qodana/README.md create mode 100644 zsh/plugins/qodana/qodana.plugin.zsh create mode 100644 zsh/plugins/qrcode/README.md create mode 100644 zsh/plugins/qrcode/qrcode.plugin.zsh delete mode 100644 zsh/plugins/rbfu/README.md delete mode 100644 zsh/plugins/rbfu/rbfu.plugin.zsh create mode 100644 zsh/plugins/rclone/README.md create mode 100644 zsh/plugins/rclone/rclone.plugin.zsh delete mode 100644 zsh/plugins/ripgrep/README.md delete mode 100644 zsh/plugins/ripgrep/_ripgrep delete mode 100644 zsh/plugins/rustup/README.md delete mode 100644 zsh/plugins/rustup/rustup.plugin.zsh delete mode 100644 zsh/plugins/scw/_scw create mode 100644 zsh/plugins/scw/scw.plugin.zsh create mode 100644 zsh/plugins/sigstore/README.md create mode 100644 zsh/plugins/sigstore/sigstore.plugin.zsh create mode 100644 zsh/plugins/skaffold/README.md create mode 100644 zsh/plugins/skaffold/skaffold.plugin.zsh create mode 100644 zsh/plugins/snap/README.md create mode 100644 zsh/plugins/snap/snap.plugin.zsh create mode 100644 zsh/plugins/spackenv/README.md create mode 100644 zsh/plugins/spackenv/spackenv.plugin.zsh create mode 100644 zsh/plugins/ssh/README.md create mode 100644 zsh/plugins/ssh/ssh.plugin.zsh create mode 100644 zsh/plugins/starship/README.md create mode 100644 zsh/plugins/starship/starship.plugin.zsh create mode 100644 zsh/plugins/stripe/README.md create mode 100644 zsh/plugins/stripe/stripe.plugin.zsh create mode 100644 zsh/plugins/symfony6/README.md create mode 100644 zsh/plugins/symfony6/symfony6.plugin.zsh create mode 100644 zsh/plugins/tailscale/README.md create mode 100644 zsh/plugins/tailscale/tailscale.plugin.zsh create mode 100644 zsh/plugins/task/README.md create mode 100644 zsh/plugins/task/task.plugin.zsh delete mode 100644 zsh/plugins/term_tab/README create mode 100644 zsh/plugins/term_tab/README.md create mode 100644 zsh/plugins/timoni/README.md create mode 100644 zsh/plugins/timoni/timoni.plugin.zsh create mode 100644 zsh/plugins/tldr/README.md create mode 100644 zsh/plugins/tldr/tldr.plugin.zsh delete mode 100644 zsh/plugins/toolbox/kubectx.plugin.zsh create mode 100644 zsh/plugins/tt/README.MD create mode 100644 zsh/plugins/tt/tt.plugin.zsh create mode 100644 zsh/plugins/uv/README.md create mode 100644 zsh/plugins/uv/uv.plugin.zsh delete mode 100644 zsh/plugins/vault/_vault create mode 100644 zsh/plugins/vault/vault.plugin.zsh create mode 100644 zsh/plugins/watson/README.md create mode 100644 zsh/plugins/watson/_watson mode change 100644 => 100755 zsh/plugins/wd/wd.sh delete mode 100644 zsh/plugins/z/Makefile delete mode 100644 zsh/plugins/z/README create mode 100644 zsh/plugins/z/img/demo.gif create mode 100644 zsh/plugins/z/img/mit_license.svg create mode 100644 zsh/plugins/z/img/zsh_4.3.11_plus.svg delete mode 100644 zsh/plugins/z/z.1 delete mode 100644 zsh/plugins/z/z.sh create mode 100644 zsh/plugins/zsh-interactive-cd/LICENSE create mode 100644 zsh/plugins/zsh-interactive-cd/demo.gif create mode 100644 zsh/templates/minimal.zshrc mode change 100644 => 100755 zsh/themes/nicoulaj.zsh-theme create mode 100644 zsh/themes/oldgallois.zsh-theme diff --git a/.gitignore b/.gitignore index e45103b..00e4653 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ +.kilo +tmp zsh/cache/* diff --git a/README.md b/README.md index d07da92..eba6ed1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,17 @@ +# Исходники + +## Oh My Zsh +https://github.com/ohmyzsh/ohmyzsh + +## Tmux +https://github.com/samoshkin/tmux-config +https://github.com/orgs/tmux-plugins/repositories?type=all + ### Зависимости + * tmux * zsh * vim * htop * xsel | xclip -* tree \ No newline at end of file +* tree diff --git a/install.sh b/install.sh index e082e0f..1036245 100755 --- a/install.sh +++ b/install.sh @@ -26,4 +26,7 @@ ln -sf .dots/tmux/tmux.conf "$HOME"/.tmux.conf ln -sf .dots/zshrc "$HOME"/.zshrc ln -sf .dots/vim/vimrc "$HOME"/.vimrc +# Initialise tmux plugin manager (https://github.com/tmux-plugins/tpm) +git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm + printf "OK: Completed\n" diff --git a/tmux/plugins/tmux-battery/LICENSE.md b/tmux/plugins/tmux-battery/LICENSE.md deleted file mode 100644 index 40f6ddd..0000000 --- a/tmux/plugins/tmux-battery/LICENSE.md +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (C) 2014 Bruno Sutic - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE -OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tmux/plugins/tmux-battery/README.md b/tmux/plugins/tmux-battery/README.md deleted file mode 100644 index 5bf4775..0000000 --- a/tmux/plugins/tmux-battery/README.md +++ /dev/null @@ -1,262 +0,0 @@ -# Tmux battery status - -Enables displaying battery percentage and status icon in tmux status-right. - -## Installation - -In order to read the battery status, this plugin depends on having one of the following applications installed: -- pmset (MacOS only) -- acpi -- upower -- termux-battery-status -- apm - -In a normal situation, one of the above should be installed on your system by default and thus it should not be necessary to specifically install one of them. That being said, the `acpi` utility is currently recommended for use over `upower` where possible due to ongoing CPU usage issues. - -### Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (recommended) - -Add plugin to the list of TPM plugins in `.tmux.conf`: - -```tmux -set -g @plugin 'tmux-plugins/tmux-battery' -``` - -Hit ` + I` to fetch the plugin and source it. - -If format strings are added to `status-right`, they should now be visible. - -### Manual Installation - -Clone the repo: - -```shell -git clone https://github.com/tmux-plugins/tmux-battery ~/clone/path -``` - -Add this line to the bottom of `.tmux.conf`: - -```tmux -run-shell ~/clone/path/battery.tmux -``` - -From the terminal, reload TMUX environment: - -```shell -tmux source-file ~/.tmux.conf -``` - -If format strings are added to `status-right`, they should now be visible. - -## Usage - -Add any of the supported format strings (see below) to the `status-right` tmux option in `.tmux.conf`. Example: - -```tmux -set -g status-right '#{battery_status_bg} Batt: #{battery_icon} #{battery_percentage} #{battery_remain} | %a %h-%d %H:%M ' -``` - -### Supported Format Strings - - - `#{battery_color_bg}` - will set the background color of the status bar based on the battery charge level if discharging and status otherwise - - `#{battery_color_fg}` - will set the foreground color of the status bar based on the battery charge level if discharging and status otherwise - - `#{battery_color_charge_bg}` - will set the background color of the status bar based solely on the battery charge level - - `#{battery_color_charge_fg}` - will set the foreground color of the status bar based solely on the battery charge level - - `#{battery_color_status_bg}` - will set the background color of the status bar based solely on the battery status - - `#{battery_color_status_fg}` - will set the foreground color of the status bar based solely on the battery status - - `#{battery_graph}` - will show battery percentage as a bar graph: ▁▂▄▆█ - - `#{battery_icon}` - will display a battery status/charge icon - - `#{battery_icon_charge}` - will display a battery charge icon - - `#{battery_icon_status}` - will display a battery status icon - - `#{battery_percentage}` - will show battery percentage - - `#{battery_remain}` - will show remaining time of battery charge\* - -\* These format strings can be further customized via options as described below. - -#### Options - -`#{battery_remain}` - - - `@batt_remain_short`: 'true' / 'false' - This will shorten the time remaining (when charging or discharging) to `~H:MM`. - -### Defaults - -#### Options - - - `@batt_remain_short`: 'false' - -#### Icons/Colors - -By default, the following colors and icons are used. (The exact colors displayed depends on your terminal / X11 config.) - -Please be aware that the 'level of charge' as noted below (e.g. `[80%-95%)`) uses interval notation. If you are unfamiliar with it, check it out here. - -Also, a note about the `@batt_color_...` options: `@batt_color_..._primary_...` options are what will be displayed in the main `bg` or `fg` format strings you choose - e.g. if you use `#{battery_color_bg}`, the `@batt_color_..._primary_...` colors you choose will be the background. Likewise, the corresponding `@batt_color_..._secondary_...` color will be the foreground. - -Level of Charge Colors: - - - primary tier 8 \[95%-100%] (`@batt_color_charge_primary_tier8`): '#00ff00' - - primary tier 7 \[80%-95%) (`@batt_color_charge_primary_tier7`): '#55ff00' - - primary tier 6 \[65%-80%) (`@batt_color_charge_primary_tier6`): '#aaff00' - - primary tier 5 \[50%-65%) (`@batt_color_charge_primary_tier5`): '#ffff00' - - primary tier 4 \[35%-50%) (`@batt_color_charge_primary_tier4`): '#ffc000' - - primary tier 3 \[20%-35%) (`@batt_color_charge_primary_tier3`): '#ff8000' - - primary tier 2 (5%-20%) (`@batt_color_charge_primary_tier2`): '#ff4000' - - primary tier 1 \[0%-5%] (`@batt_color_charge_primary_tier1`): '#ff0000' - - secondary tier 8 \[95%-100%] (`@batt_color_charge_secondary_tier8`): 'colour0' - - secondary tier 7 \[80%-95%) (`@batt_color_charge_secondary_tier7`): 'colour0' - - secondary tier 6 \[65%-80%) (`@batt_color_charge_secondary_tier6`): 'colour0' - - secondary tier 5 \[50%-65%) (`@batt_color_charge_secondary_tier5`): 'colour0' - - secondary tier 4 \[35%-50%) (`@batt_color_charge_secondary_tier4`): 'colour0' - - secondary tier 3 \[20%-35%) (`@batt_color_charge_secondary_tier3`): 'colour0' - - secondary tier 2 (5%-20%) (`@batt_color_charge_secondary_tier2`): 'colour0' - - secondary tier 1 \[0%-5%] (`@batt_color_charge_secondary_tier1`): 'colour0' - -Status Colors: - - - primary charged (`@batt_color_status_primary_charged`): 'colour33' - - primary charging (`@batt_color_status_primary_charging`): 'colour33' - - primary discharging (`@batt_color_status_primary_discharging`): 'colour14' - - primary attached (`@batt_color_status_primary_attached`): 'colour201' - - primary unknown (`@batt_color_status_primary_unknown`): 'colour7' - - secondary charged (`@batt_color_status_secondary_charged`): 'colour0' - - secondary charging (`@batt_color_status_secondary_charging`): 'colour0' - - secondary discharging (`@batt_color_status_secondary_discharging`): 'colour0' - - secondary attached (`@batt_color_status_secondary_attached`): 'colour0' - - secondary unknown (`@batt_color_status_secondary_unknown`): 'colour0' - -Level of Charge Icons: - - - tier 8 \[95%-100%] (`@batt_icon_charge_tier8`): '█' - - tier 7 \[80%-95%) (`@batt_icon_charge_tier7`): '▇' - - tier 6 \[65%-80%) (`@batt_icon_charge_tier6`): '▆' - - tier 5 \[50%-65%) (`@batt_icon_charge_tier5`): '▅' - - tier 4 \[35%-50%) (`@batt_icon_charge_tier4`): '▄' - - tier 3 \[20%-35%) (`@batt_icon_charge_tier3`): '▃' - - tier 2 (5%-20%) (`@batt_icon_charge_tier2`): '▂' - - tier 1 \[0%-5%] (`@batt_icon_charge_tier1`): '▁' - -Status Icons: - - - charged (`@batt_icon_status_charged`): '🔌' - - charged - OS X (`@batt_icon_status_charged`): '🔌' - - charging (`@batt_icon_status_charging`): '🔌' - - discharging (`@batt_icon_status_discharging`): '🔋' - - attached (`@batt_icon_status_attached`): '⚠️' - - unknown (`@batt_icon_status_unknown`): '?' - -#### Changing the Defaults - -All efforts have been made to make sane defaults, but if you wish to change any of them, add the option to `.tmux.conf`. For example: - -```tmux -set -g @batt_icon_charge_tier8 '🌕' -set -g @batt_icon_charge_tier7 '🌖' -set -g @batt_icon_charge_tier6 '🌖' -set -g @batt_icon_charge_tier5 '🌗' -set -g @batt_icon_charge_tier4 '🌗' -set -g @batt_icon_charge_tier3 '🌘' -set -g @batt_icon_charge_tier2 '🌘' -set -g @batt_icon_charge_tier1 '🌑' -set -g @batt_icon_status_charged '🔋' -set -g @batt_icon_status_charging '⚡' -set -g @batt_icon_status_discharging '👎' -set -g @batt_color_status_primary_charged '#3daee9' -set -g @batt_color_status_primary_charging '#3daee9' -``` - -Don't forget to reload the tmux environment after you do this by either hitting ` + I` if tmux battery is installed via the tmux plugin manager, or by typing `tmux source-file ~/.tmux.conf` in the terminal if tmux battery is manually installed. - -*Warning*: The battery icon change most likely will not be instant. When you un-plug the power cord, it will take some time (15 - 60 seconds) for the icon to change. This depends on the `status-interval` tmux option. Setting it to 15 seconds should be good enough. - -## Examples - -These are all examples of the default plugin color and icon schemes paired with the default tmux color scheme using the following `status-right` and `status-right-length` settings in `.tmux.conf` - -```tmux -set -g status-right 'Colors: #{battery_color_bg}bg#[default] #{battery_color_fg}fg#[default] #{battery_color_charge_bg}charge_bg#[default] #{battery_color_charge_fg}charge_fg#[default] #{battery_color_status_bg}status_bg#[default] #{battery_color_status_fg}status_fg#[default] | Graph: #{battery_graph} | Icon: #{battery_icon} | Charge Icon: #{battery_icon_charge} | Status Icon: #{battery_icon_status} | Percent: #{battery_percentage} | Remain: #{battery_remain}' -set -g status-right-length '150' -``` - -Battery charging at tier 8 \[95%-100%]:
-![battery-charging-tier8](./screenshots/battery_charging_tier8.png) - -Battery charging at tier 7 \[80%-95%):
-![battery-charging-tier7](./screenshots/battery_charging_tier7.png) - -Battery charging at tier 6 \[65%-80%):
-![battery-charging-tier6](./screenshots/battery_charging_tier6.png) - -Battery charging at tier 5 \[50%-65%):
-![battery-charging-tier5](./screenshots/battery_charging_tier5.png) - -Battery charging at tier 4 \[35%-50%):
-![battery-charging-tier4](./screenshots/battery_charging_tier4.png) - -Battery charging at tier 3 \[20%-35%):
-![battery-charging-tier3](./screenshots/battery_charging_tier3.png) - -Battery charging at tier 2 (5%-20%):
-![battery-charging-tier2](./screenshots/battery_charging_tier2.png) - -Battery charging at tier 1 \[0%-5%]:
-![battery-charging-tier1](./screenshots/battery_charging_tier1.png) - -Battery discharging at tier 8 \[95%-100%]:
-![battery-discharging-tier8](./screenshots/battery_discharging_tier8.png) - -Battery discharging at tier 7 \[80%-95%):
-![battery-discharging-tier7](./screenshots/battery_discharging_tier7.png) - -Battery discharging at tier 6 \[65%-80%):
-![battery-discharging-tier6](./screenshots/battery_discharging_tier6.png) - -Battery discharging at tier 5 \[50%-65%):
-![battery-discharging-tier5](./screenshots/battery_discharging_tier5.png) - -Battery discharging at tier 4 \[35%-50%):
-![battery-discharging-tier4](./screenshots/battery_discharging_tier4.png) - -Battery discharging at tier 3 \[20%-35%):
-![battery-discharging-tier3](./screenshots/battery_discharging_tier3.png) - -Battery discharging at tier 2 (5%-20%):
-![battery-discharging-tier2](./screenshots/battery_discharging_tier2.png) - -Battery discharging at tier 1 \[0%-5%]:
-![battery-discharging-tier1](./screenshots/battery_discharging_tier1.png) - -Battery in 'attached' status:
-![battery-status-attached](./screenshots/battery_status_attached.png) - -Battery in an unknown status:
-![battery-status-unknown](./screenshots/battery_status_unknown.png) - -### Tmux Plugins - -This plugin is part of the [tmux-plugins](https://github.com/tmux-plugins) organisation. Checkout plugins as [resurrect](https://github.com/tmux-plugins/tmux-resurrect), [logging](https://github.com/tmux-plugins/tmux-logging), [online status](https://github.com/tmux-plugins/tmux-online-status), and many more over at the [tmux-plugins](https://github.com/tmux-plugins) organisation page. - -### Maintainer - - - [Martin Beentjes](https://github.com/martinbeentjes) - -### Contributors - - - Adam Biggs - - Aleksandar Djurdjic - - Bruno Sutic - - Caleb - - Dan Cassidy - - Diego Ximenes - - Evan N-D - - Jan Ahrens - - Joey Geralnik - - HyunJong (Joseph) Lee - - Martin Beentjes - - Mike Foley - - Ryan Frantz - - Seth Wright - - Tom Levens - -### License - -[MIT](LICENSE.md) diff --git a/tmux/plugins/tmux-battery/battery.tmux b/tmux/plugins/tmux-battery/battery.tmux deleted file mode 100755 index 0c666b8..0000000 --- a/tmux/plugins/tmux-battery/battery.tmux +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/scripts/helpers.sh" - -battery_interpolation=( - "\#{battery_color_bg}" - "\#{battery_color_fg}" - "\#{battery_color_charge_bg}" - "\#{battery_color_charge_fg}" - "\#{battery_color_status_bg}" - "\#{battery_color_status_fg}" - "\#{battery_graph}" - "\#{battery_icon}" - "\#{battery_icon_charge}" - "\#{battery_icon_status}" - "\#{battery_percentage}" - "\#{battery_remain}" -) - -battery_commands=( - "#($CURRENT_DIR/scripts/battery_color.sh bg)" - "#($CURRENT_DIR/scripts/battery_color.sh fg)" - "#($CURRENT_DIR/scripts/battery_color_charge.sh bg)" - "#($CURRENT_DIR/scripts/battery_color_charge.sh fg)" - "#($CURRENT_DIR/scripts/battery_color_status.sh bg)" - "#($CURRENT_DIR/scripts/battery_color_status.sh fg)" - "#($CURRENT_DIR/scripts/battery_graph.sh)" - "#($CURRENT_DIR/scripts/battery_icon.sh)" - "#($CURRENT_DIR/scripts/battery_icon_charge.sh)" - "#($CURRENT_DIR/scripts/battery_icon_status.sh)" - "#($CURRENT_DIR/scripts/battery_percentage.sh)" - "#($CURRENT_DIR/scripts/battery_remain.sh)" -) - -set_tmux_option() { - local option="$1" - local value="$2" - tmux set-option -gq "$option" "$value" -} - -do_interpolation() { - local all_interpolated="$1" - for ((i=0; i<${#battery_commands[@]}; i++)); do - all_interpolated=${all_interpolated//${battery_interpolation[$i]}/${battery_commands[$i]}} - done - echo "$all_interpolated" -} - -update_tmux_option() { - local option="$1" - local option_value="$(get_tmux_option "$option")" - local new_option_value="$(do_interpolation "$option_value")" - set_tmux_option "$option" "$new_option_value" -} - -main() { - update_tmux_option "status-right" - update_tmux_option "status-left" -} -main diff --git a/tmux/plugins/tmux-battery/scripts/battery_color.sh b/tmux/plugins/tmux-battery/scripts/battery_color.sh deleted file mode 100755 index d8fefeb..0000000 --- a/tmux/plugins/tmux-battery/scripts/battery_color.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" - -print_color() { - local plane="$1" - local status="$2" - if [ "$status" == "discharging" ]; then - $CURRENT_DIR/battery_color_charge.sh "$plane" - else - $CURRENT_DIR/battery_color_status.sh "$plane" "$status" - fi -} - -main() { - local status="$(battery_status)" - local plane="$1" - print_color "$plane" "$status" -} - -main $@ diff --git a/tmux/plugins/tmux-battery/scripts/battery_color_charge.sh b/tmux/plugins/tmux-battery/scripts/battery_color_charge.sh deleted file mode 100755 index c09a8d4..0000000 --- a/tmux/plugins/tmux-battery/scripts/battery_color_charge.sh +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" - -# script global variables -color_charge_primary_tier8='' -color_charge_primary_tier7='' -color_charge_primary_tier6='' -color_charge_primary_tier5='' -color_charge_primary_tier4='' -color_charge_primary_tier3='' -color_charge_primary_tier2='' -color_charge_primary_tier1='' -color_charge_secondary_tier8='' -color_charge_secondary_tier7='' -color_charge_secondary_tier6='' -color_charge_secondary_tier5='' -color_charge_secondary_tier4='' -color_charge_secondary_tier3='' -color_charge_secondary_tier2='' -color_charge_secondary_tier1='' - -# script default variables -color_charge_primary_tier8_default='#00ff00' -color_charge_primary_tier7_default='#55ff00' -color_charge_primary_tier6_default='#aaff00' -color_charge_primary_tier5_default='#ffff00' -color_charge_primary_tier4_default='#ffc000' -color_charge_primary_tier3_default='#ff8000' -color_charge_primary_tier2_default='#ff4000' -color_charge_primary_tier1_default='#ff0000' -color_charge_secondary_tier8_default='colour0' -color_charge_secondary_tier7_default='colour0' -color_charge_secondary_tier6_default='colour0' -color_charge_secondary_tier5_default='colour0' -color_charge_secondary_tier4_default='colour0' -color_charge_secondary_tier3_default='colour0' -color_charge_secondary_tier2_default='colour0' -color_charge_secondary_tier1_default='colour0' - -# colors are set as script global variables -get_color_charge_settings() { - color_charge_primary_tier8=$(get_tmux_option "@batt_color_charge_primary_tier8" "$color_charge_primary_tier8_default") - color_charge_primary_tier7=$(get_tmux_option "@batt_color_charge_primary_tier7" "$color_charge_primary_tier7_default") - color_charge_primary_tier6=$(get_tmux_option "@batt_color_charge_primary_tier6" "$color_charge_primary_tier6_default") - color_charge_primary_tier5=$(get_tmux_option "@batt_color_charge_primary_tier5" "$color_charge_primary_tier5_default") - color_charge_primary_tier4=$(get_tmux_option "@batt_color_charge_primary_tier4" "$color_charge_primary_tier4_default") - color_charge_primary_tier3=$(get_tmux_option "@batt_color_charge_primary_tier3" "$color_charge_primary_tier3_default") - color_charge_primary_tier2=$(get_tmux_option "@batt_color_charge_primary_tier2" "$color_charge_primary_tier2_default") - color_charge_primary_tier1=$(get_tmux_option "@batt_color_charge_primary_tier1" "$color_charge_primary_tier1_default") - color_charge_secondary_tier8=$(get_tmux_option "@batt_color_charge_secondary_tier8" "$color_charge_secondary_tier8_default") - color_charge_secondary_tier7=$(get_tmux_option "@batt_color_charge_secondary_tier7" "$color_charge_secondary_tier7_default") - color_charge_secondary_tier6=$(get_tmux_option "@batt_color_charge_secondary_tier6" "$color_charge_secondary_tier6_default") - color_charge_secondary_tier5=$(get_tmux_option "@batt_color_charge_secondary_tier5" "$color_charge_secondary_tier5_default") - color_charge_secondary_tier4=$(get_tmux_option "@batt_color_charge_secondary_tier4" "$color_charge_secondary_tier4_default") - color_charge_secondary_tier3=$(get_tmux_option "@batt_color_charge_secondary_tier3" "$color_charge_secondary_tier3_default") - color_charge_secondary_tier2=$(get_tmux_option "@batt_color_charge_secondary_tier2" "$color_charge_secondary_tier2_default") - color_charge_secondary_tier1=$(get_tmux_option "@batt_color_charge_secondary_tier1" "$color_charge_secondary_tier1_default") -} - -print_color_charge() { - local primary_plane="$1" - local secondary_plane="" - if [ "$primary_plane" == "bg" ]; then - secondary_plane="fg" - else - secondary_plane="bg" - fi - percentage=$($CURRENT_DIR/battery_percentage.sh | sed -e 's/%//') - if [ $percentage -ge 95 -o "$percentage" == "" ]; then - # if percentage is empty, assume it's a desktop - printf "#[$primary_plane=$color_charge_primary_tier8${color_charge_secondary_tier8:+",$secondary_plane=$color_charge_secondary_tier8"}]" - elif [ $percentage -ge 80 ]; then - printf "#[$primary_plane=$color_charge_primary_tier7${color_charge_secondary_tier7:+",$secondary_plane=$color_charge_secondary_tier7"}]" - elif [ $percentage -ge 65 ]; then - printf "#[$primary_plane=$color_charge_primary_tier6${color_charge_secondary_tier6:+",$secondary_plane=$color_charge_secondary_tier6"}]" - elif [ $percentage -ge 50 ]; then - printf "#[$primary_plane=$color_charge_primary_tier5${color_charge_secondary_tier5:+",$secondary_plane=$color_charge_secondary_tier5"}]" - elif [ $percentage -ge 35 ]; then - printf "#[$primary_plane=$color_charge_primary_tier4${color_charge_secondary_tier4:+",$secondary_plane=$color_charge_secondary_tier4"}]" - elif [ $percentage -ge 20 ]; then - printf "#[$primary_plane=$color_charge_primary_tier3${color_charge_secondary_tier3:+",$secondary_plane=$color_charge_secondary_tier3"}]" - elif [ $percentage -gt 5 ]; then - printf "#[$primary_plane=$color_charge_primary_tier2${color_charge_secondary_tier2:+",$secondary_plane=$color_charge_secondary_tier2"}]" - else - printf "#[$primary_plane=$color_charge_primary_tier1${color_charge_secondary_tier1:+",$secondary_plane=$color_charge_secondary_tier1"}]" - fi -} - -main() { - local plane="$1" - get_color_charge_settings - print_color_charge "$plane" -} - -main $@ diff --git a/tmux/plugins/tmux-battery/scripts/battery_color_status.sh b/tmux/plugins/tmux-battery/scripts/battery_color_status.sh deleted file mode 100755 index 429f847..0000000 --- a/tmux/plugins/tmux-battery/scripts/battery_color_status.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" - -# script global variables -color_status_primary_charged='' -color_status_primary_charging='' -color_status_primary_discharging='' -color_status_primary_attached='' -color_status_primary_unknown='' -color_status_secondary_charged='' -color_status_secondary_charging='' -color_status_secondary_discharging='' -color_status_secondary_attached='' -color_status_secondary_unknown='' - -# script default variables -color_status_primary_charged_default='colour33' -color_status_primary_charging_default='colour33' -color_status_primary_discharging_default='colour14' -color_status_primary_attached_default='colour201' -color_status_primary_unknown_default='colour7' -color_status_secondary_charged_default='colour0' -color_status_secondary_charging_default='colour0' -color_status_secondary_discharging_default='colour0' -color_status_secondary_attached_default='colour0' -color_status_secondary_unknown_default='colour0' - -# colors are set as script global variables -get_color_status_settings() { - color_status_primary_charged=$(get_tmux_option "@batt_color_status_primary_charged" "$color_status_primary_charged_default") - color_status_primary_charging=$(get_tmux_option "@batt_color_status_primary_charging" "$color_status_primary_charging_default") - color_status_primary_discharging=$(get_tmux_option "@batt_color_status_primary_discharging" "$color_status_primary_discharging_default") - color_status_primary_attached=$(get_tmux_option "@batt_color_status_primary_attached" "$color_status_primary_attached_default") - color_status_primary_unknown=$(get_tmux_option "@batt_color_status_primary_unknown" "$color_status_primary_unknown_default") - color_status_secondary_charged=$(get_tmux_option "@batt_color_status_secondary_charged" "$color_status_secondary_charged_default") - color_status_secondary_charging=$(get_tmux_option "@batt_color_status_secondary_charging" "$color_status_secondary_charging_default") - color_status_secondary_discharging=$(get_tmux_option "@batt_color_status_secondary_discharging" "$color_status_secondary_discharging_default") - color_status_secondary_attached=$(get_tmux_option "@batt_color_status_secondary_attached" "$color_status_secondary_attached_default") - color_status_secondary_unknown=$(get_tmux_option "@batt_color_status_secondary_unknown" "$color_status_secondary_unknown_default") -} - -print_color_status() { - local plane_primary="$1" - local plane_secondary="" - if [ "$plane_primary" == "bg" ]; then - plane_secondary="fg" - else - plane_secondary="bg" - fi - local status="$2" - if [[ $status =~ (charged) || $status =~ (full) ]]; then - printf "#[$plane_primary=$color_status_primary_charged${color_status_secondary_charged:+",$plane_secondary=$color_status_secondary_charged"}]" - elif [[ $status =~ (^charging) ]]; then - printf "#[$plane_primary=$color_status_primary_charging${color_status_secondary_charging:+",$plane_secondary=$color_status_secondary_charging"}]" - elif [[ $status =~ (^discharging) ]]; then - printf "#[$plane_primary=$color_status_primary_discharging${color_status_secondary_discharging:+",$plane_secondary=$color_status_secondary_discharging"}]" - elif [[ $status =~ (attached) ]]; then - printf "#[$plane_primary=$color_status_primary_attached${color_status_secondary_attached:+",$plane_secondary=$color_status_secondary_attached"}]" - else - printf "#[$plane_primary=$color_status_primary_unknown${color_status_secondary_unknown:+",$plane_secondary=$color_status_secondary_unknown"}]" - fi -} - -main() { - local plane="$1" - local status=${2:-$(battery_status)} - get_color_status_settings - print_color_status "$plane" "$status" -} - -main $@ diff --git a/tmux/plugins/tmux-battery/scripts/battery_graph.sh b/tmux/plugins/tmux-battery/scripts/battery_graph.sh deleted file mode 100755 index 42f23c4..0000000 --- a/tmux/plugins/tmux-battery/scripts/battery_graph.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" - -print_graph() { - local percentage=$1 - if [ $percentage -gt 5 ]; then - printf "▁" - else - printf " " - fi - if [ $percentage -ge 25 ]; then - printf "▂" - else - printf " " - fi - if [ $percentage -ge 50 ]; then - printf "▄" - else - printf " " - fi - if [ $percentage -ge 75 ]; then - printf "▆" - else - printf " " - fi - if [ $percentage -ge 95 ]; then - printf "█" - else - printf " " - echo "▇" - fi -} - -main() { - local percentage=$($CURRENT_DIR/battery_percentage.sh) - if [ "$(uname)" == "OpenBSD" ]; then - print_graph ${percentage} - else - print_graph ${percentage%?} - fi -} -main diff --git a/tmux/plugins/tmux-battery/scripts/battery_icon.sh b/tmux/plugins/tmux-battery/scripts/battery_icon.sh deleted file mode 100755 index b40c42e..0000000 --- a/tmux/plugins/tmux-battery/scripts/battery_icon.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" - -print_icon() { - local status=$1 - if [ "$status" == "discharging" ]; then - $CURRENT_DIR/battery_icon_charge.sh - else - $CURRENT_DIR/battery_icon_status.sh "$status" - fi -} - -main() { - local status=$(battery_status) - print_icon "$status" -} - -main diff --git a/tmux/plugins/tmux-battery/scripts/battery_icon_charge.sh b/tmux/plugins/tmux-battery/scripts/battery_icon_charge.sh deleted file mode 100755 index 8bdd568..0000000 --- a/tmux/plugins/tmux-battery/scripts/battery_icon_charge.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" - -# script global variables -icon_charge_tier8='' -icon_charge_tier7='' -icon_charge_tier6='' -icon_charge_tier5='' -icon_charge_tier4='' -icon_charge_tier3='' -icon_charge_tier2='' -icon_charge_tier1='' - -# script default variables -icon_charge_tier8_default='█' -icon_charge_tier7_default='▇' -icon_charge_tier6_default='▆' -icon_charge_tier5_default='▅' -icon_charge_tier4_default='▄' -icon_charge_tier3_default='▃' -icon_charge_tier2_default='▂' -icon_charge_tier1_default='▁' - -# icons are set as script global variables -get_icon_charge_settings() { - icon_charge_tier8=$(get_tmux_option "@batt_icon_charge_tier8" "$icon_charge_tier8_default") - icon_charge_tier7=$(get_tmux_option "@batt_icon_charge_tier7" "$icon_charge_tier7_default") - icon_charge_tier6=$(get_tmux_option "@batt_icon_charge_tier6" "$icon_charge_tier6_default") - icon_charge_tier5=$(get_tmux_option "@batt_icon_charge_tier5" "$icon_charge_tier5_default") - icon_charge_tier4=$(get_tmux_option "@batt_icon_charge_tier4" "$icon_charge_tier4_default") - icon_charge_tier3=$(get_tmux_option "@batt_icon_charge_tier3" "$icon_charge_tier3_default") - icon_charge_tier2=$(get_tmux_option "@batt_icon_charge_tier2" "$icon_charge_tier2_default") - icon_charge_tier1=$(get_tmux_option "@batt_icon_charge_tier1" "$icon_charge_tier1_default") -} - -print_icon_charge() { - percentage=$($CURRENT_DIR/battery_percentage.sh | sed -e 's/%//') - if [ $percentage -ge 95 -o "$percentage" == "" ]; then - # if percentage is empty, assume it's a desktop - printf "$icon_charge_tier8" - elif [ $percentage -ge 80 ]; then - printf "$icon_charge_tier7" - elif [ $percentage -ge 65 ]; then - printf "$icon_charge_tier6" - elif [ $percentage -ge 50 ]; then - printf "$icon_charge_tier5" - elif [ $percentage -ge 35 ]; then - printf "$icon_charge_tier4" - elif [ $percentage -ge 20 ]; then - printf "$icon_charge_tier3" - elif [ $percentage -gt 5 ]; then - printf "$icon_charge_tier2" - else - printf "$icon_charge_tier1" - fi -} - -main() { - get_icon_charge_settings - print_icon_charge -} - -main diff --git a/tmux/plugins/tmux-battery/scripts/battery_icon_status.sh b/tmux/plugins/tmux-battery/scripts/battery_icon_status.sh deleted file mode 100755 index e1873fb..0000000 --- a/tmux/plugins/tmux-battery/scripts/battery_icon_status.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" - -# script global variables -icon_status_charged='' -icon_status_charging='' -icon_status_discharging='' -icon_status_attached='' -icon_status_unknown='' - -# script default variables -icon_status_charged_default='🔌' -icon_status_charged_default_osx='🔌' -icon_status_charging_default='🔌' -icon_status_discharging_default='🔋' -icon_status_attached_default='⚠️' -icon_status_unknown_default='?' - -# determine which charged_default variable to use -get_icon_status_charged_default() { - if is_osx; then - printf "$icon_status_charged_default_osx" - else - printf "$icon_status_charged_default" - fi -} - -# icons are set as script global variables -get_icon_status_settings() { - icon_status_charged=$(get_tmux_option "@batt_icon_status_charged" "$(get_icon_status_charged_default)") - icon_status_charging=$(get_tmux_option "@batt_icon_status_charging" "$icon_status_charging_default") - icon_status_discharging=$(get_tmux_option "@batt_icon_status_discharging" "$icon_status_discharging_default") - icon_status_attached=$(get_tmux_option "@batt_icon_status_attached" "$icon_status_attached_default") - icon_status_unknown=$(get_tmux_option "@batt_icon_status_unknown" "$icon_status_unknown_default") -} - -print_icon_status() { - local status=$1 - if [[ $status =~ (charged) || $status =~ (full) ]]; then - printf "$icon_status_charged" - elif [[ $status =~ (^charging) ]]; then - printf "$icon_status_charging" - elif [[ $status =~ (^discharging) ]]; then - printf "$icon_status_discharging" - elif [[ $status =~ (attached) ]]; then - printf "$icon_status_attached" - else - printf "$icon_status_unknown" - fi -} - -main() { - get_icon_status_settings - local status=${1:-$(battery_status)} - print_icon_status "$status" -} - -main diff --git a/tmux/plugins/tmux-battery/scripts/battery_percentage.sh b/tmux/plugins/tmux-battery/scripts/battery_percentage.sh deleted file mode 100755 index eb56e0e..0000000 --- a/tmux/plugins/tmux-battery/scripts/battery_percentage.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" - -print_battery_percentage() { - # percentage displayed in the 2nd field of the 2nd row - if command_exists "pmset"; then - pmset -g batt | grep -o "[0-9]\{1,3\}%" - elif command_exists "acpi"; then - acpi -b | grep -m 1 -Eo "[0-9]+%" - elif command_exists "upower"; then - # use DisplayDevice if available otherwise battery - local battery=$(upower -e | grep -E 'battery|DisplayDevice'| tail -n1) - if [ -z "$battery" ]; then - return - fi - local percentage=$(upower -i $battery | awk '/percentage:/ {print $2}') - if [ "$percentage" ]; then - echo ${percentage%.*%} - return - fi - local energy - local energy_full - energy=$(upower -i $battery | awk -v nrg="$energy" '/energy:/ {print nrg+$2}') - energy_full=$(upower -i $battery | awk -v nrgfull="$energy_full" '/energy-full:/ {print nrgfull+$2}') - if [ -n "$energy" ] && [ -n "$energy_full" ]; then - echo $energy $energy_full | awk '{printf("%d%%", ($1/$2)*100)}' - fi - elif command_exists "termux-battery-status"; then - termux-battery-status | jq -r '.percentage' | awk '{printf("%d%%", $1)}' - elif command_exists "apm"; then - apm -l - fi -} - -main() { - print_battery_percentage -} -main diff --git a/tmux/plugins/tmux-battery/scripts/battery_remain.sh b/tmux/plugins/tmux-battery/scripts/battery_remain.sh deleted file mode 100755 index c11158f..0000000 --- a/tmux/plugins/tmux-battery/scripts/battery_remain.sh +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" - -short=false - -get_remain_settings() { - short=$(get_tmux_option "@batt_remain_short" false) -} - -battery_discharging() { - local status="$(battery_status)" - [[ $status =~ (discharging) ]] -} - -battery_charged() { - local status="$(battery_status)" - [[ $status =~ (charged) ]] -} - - -convertmins() { - ((h=${1}/60)) - ((m=${1}%60)) - printf "%02d:%02d\n" $h $m $s -} - -apm_battery_remaining_time() { - local remaining_time="$(convertmins $(apm -m))" - if battery_discharging; then - if $short; then - echo $remaining_time | awk '{printf "~%s", $1}' - else - echo $remaining_time | awk '{printf "- %s left", $1}' - fi - elif battery_charged; then - if $short; then - echo $remaining_time | awk '{printf "charged", $1}' - else - echo $remaining_time | awk '{printf "fully charged", $1}' - fi - else - echo "charging" - fi -} - -pmset_battery_remaining_time() { - local status="$(pmset -g batt)" - if echo $status | grep 'no estimate' >/dev/null 2>&1; then - if $short; then - echo '~?:??' - else - echo '- Calculating estimate...' - fi - else - local remaining_time="$(echo $status | grep -o '[0-9]\{1,2\}:[0-9]\{1,2\}')" - if battery_discharging; then - if $short; then - echo $remaining_time | awk '{printf "~%s", $1}' - else - echo $remaining_time | awk '{printf "- %s left", $1}' - fi - elif battery_charged; then - if $short; then - echo $remaining_time | awk '{printf "charged", $1}' - else - echo $remaining_time | awk '{printf "fully charged", $1}' - fi - else - if $short; then - echo $remaining_time | awk '{printf "~%s", $1}' - else - echo $remaining_time | awk '{printf "- %s till full", $1}' - fi - fi - fi -} - -upower_battery_remaining_time() { - battery=$(upower -e | grep -E 'battery|DisplayDevice'| tail -n1) - if battery_discharging; then - local remaining_time - remaining_time=$(upower -i "$battery" | grep -E '(remain|time to empty)') - if $short; then - echo "$remaining_time" | awk '{printf "%s %s", $(NF-1), $(NF)}' - else - echo "$remaining_time" | awk '{printf "%s %s left", $(NF-1), $(NF)}' - fi - elif battery_charged; then - if $short; then - echo "" - else - echo "charged" - fi - else - local remaining_time - remaining_time=$(upower -i "$battery" | grep -E 'time to full') - if $short; then - echo "$remaining_time" | awk '{printf "%s %s", $(NF-1), $(NF)}' - else - echo "$remaining_time" | awk '{printf "%s %s to full", $(NF-1), $(NF)}' - fi - fi -} - -acpi_battery_remaining_time() { - acpi -b | grep -m 1 -Eo "[0-9]+:[0-9]+:[0-9]+" -} - -print_battery_remain() { - if command_exists "pmset"; then - pmset_battery_remaining_time - elif command_exists "acpi"; then - acpi_battery_remaining_time - elif command_exists "upower"; then - upower_battery_remaining_time - elif command_exists "apm"; then - apm_battery_remaining_time - fi -} - -main() { - get_remain_settings - print_battery_remain -} -main diff --git a/tmux/plugins/tmux-battery/scripts/battery_status_bg.sh b/tmux/plugins/tmux-battery/scripts/battery_status_bg.sh deleted file mode 100755 index 42d1626..0000000 --- a/tmux/plugins/tmux-battery/scripts/battery_status_bg.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" - -color_full_charge_default="#[bg=green]" -color_high_charge_default="#[bg=yellow]" -color_medium_charge_default="#[bg=colour208]" # orange -color_low_charge_default="#[bg=red]" -color_charging_default="#[bg=green]" - -color_full_charge="" -color_high_charge="" -color_medium_charge="" -color_low_charge="" -color_charging="" - -get_charge_color_settings() { - color_full_charge=$(get_tmux_option "@batt_color_full_charge" "$color_full_charge_default") - color_high_charge=$(get_tmux_option "@batt_color_high_charge" "$color_high_charge_default") - color_medium_charge=$(get_tmux_option "@batt_color_medium_charge" "$color_medium_charge_default") - color_low_charge=$(get_tmux_option "@batt_color_low_charge" "$color_low_charge_default") - color_charging=$(get_tmux_option "@batt_color_charging" "$color_charging_default") -} - -print_battery_status_bg() { - # Call `battery_percentage.sh`. - percentage=$($CURRENT_DIR/battery_percentage.sh | sed -e 's/%//') - status=$(battery_status | awk '{print $1;}') - if [ $status == 'charging' ]; then - printf $color_charging - elif [ $percentage -eq 100 ]; then - printf $color_full_charge - elif [ $percentage -le 99 -a $percentage -ge 51 ];then - printf $color_high_charge - elif [ $percentage -le 50 -a $percentage -ge 16 ];then - printf $color_medium_charge - elif [ "$percentage" == "" ];then - printf $color_full_charge_default # assume it's a desktop - else - printf $color_low_charge - fi -} - -main() { - get_charge_color_settings - print_battery_status_bg -} -main diff --git a/tmux/plugins/tmux-battery/scripts/battery_status_fg.sh b/tmux/plugins/tmux-battery/scripts/battery_status_fg.sh deleted file mode 100755 index 2418b8c..0000000 --- a/tmux/plugins/tmux-battery/scripts/battery_status_fg.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" - -color_full_charge_default="#[fg=green]" -color_high_charge_default="#[fg=yellow]" -color_medium_charge_default="#[fg=colour208]" # orange -color_low_charge_default="#[fg=red]" -color_charging_default="#[fg=green]" - -color_full_charge="" -color_high_charge="" -color_medium_charge="" -color_low_charge="" -color_charging="" - -get_charge_color_settings() { - color_full_charge=$(get_tmux_option "@batt_color_full_charge" "$color_full_charge_default") - color_high_charge=$(get_tmux_option "@batt_color_high_charge" "$color_high_charge_default") - color_medium_charge=$(get_tmux_option "@batt_color_medium_charge" "$color_medium_charge_default") - color_low_charge=$(get_tmux_option "@batt_color_low_charge" "$color_low_charge_default") - color_charging=$(get_tmux_option "@batt_color_charging" "$color_charging_default") -} - -print_battery_status_fg() { - # Call `battery_percentage.sh`. - percentage=$($CURRENT_DIR/battery_percentage.sh | sed -e 's/%//') - status=$(battery_status | awk '{print $1;}') - if [ $status == 'charging' ]; then - printf $color_charging - elif [ $percentage -eq 100 ]; then - printf $color_full_charge - elif [ $percentage -le 99 -a $percentage -ge 51 ];then - printf $color_high_charge - elif [ $percentage -le 50 -a $percentage -ge 16 ];then - printf $color_medium_charge - elif [ "$percentage" == "" ];then - printf $color_full_charge_default # assume it's a desktop - else - printf $color_low_charge - fi -} - -main() { - get_charge_color_settings - print_battery_status_fg -} -main diff --git a/tmux/plugins/tmux-battery/scripts/helpers.sh b/tmux/plugins/tmux-battery/scripts/helpers.sh deleted file mode 100644 index 067c120..0000000 --- a/tmux/plugins/tmux-battery/scripts/helpers.sh +++ /dev/null @@ -1,50 +0,0 @@ -get_tmux_option() { - local option="$1" - local default_value="$2" - local option_value="$(tmux show-option -gqv "$option")" - if [ -z "$option_value" ]; then - echo "$default_value" - else - echo "$option_value" - fi -} - -is_osx() { - [ $(uname) == "Darwin" ] -} - -is_chrome() { - chrome="/sys/class/chromeos/cros_ec" - if [ -d "$chrome" ]; then - return 0 - else - return 1 - fi -} - -command_exists() { - local command="$1" - type "$command" >/dev/null 2>&1 -} - -battery_status() { - if command_exists "pmset"; then - pmset -g batt | awk -F '; *' 'NR==2 { print $2 }' - elif command_exists "acpi"; then - acpi -b | awk '{gsub(/,/, ""); print tolower($3); exit}' - elif command_exists "upower"; then - local battery - battery=$(upower -e | grep -E 'battery|DisplayDevice'| tail -n1) - upower -i $battery | awk '/state/ {print $2}' - elif command_exists "termux-battery-status"; then - termux-battery-status | jq -r '.status' | awk '{printf("%s%", tolower($1))}' - elif command_exists "apm"; then - local battery - battery=$(apm -a) - if [ $battery -eq 0 ]; then - echo "discharging" - elif [ $battery -eq 1 ]; then - echo "charging" - fi - fi -} diff --git a/tmux/plugins/tmux-continuum/LICENSE.md b/tmux/plugins/tmux-continuum/LICENSE.md deleted file mode 100644 index e6e7350..0000000 --- a/tmux/plugins/tmux-continuum/LICENSE.md +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (C) Bruno Sutic - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE -OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tmux/plugins/tmux-continuum/README.md b/tmux/plugins/tmux-continuum/README.md deleted file mode 100644 index bafc6aa..0000000 --- a/tmux/plugins/tmux-continuum/README.md +++ /dev/null @@ -1,98 +0,0 @@ -# tmux-continuum - -Features: - -- continuous saving of tmux environment -- automatic tmux start when computer/server is turned on -- automatic restore when tmux is started - -Together these features enable uninterrupted tmux usage. No matter the computer -or server restarts, if the machine is on, tmux will be there how you left it off -the last time it was used. - -Tested and working on Linux, OSX and Cygwin. - -#### Continuous saving - -Tmux environment will be saved at the interval of 15 minutes. All the saving -happens in the background without the impact to your workflow. - -This action starts automatically when the plugin is installed. - -#### Automatic tmux start - -Tmux is automatically started after the computer/server is turned on. - -See the [instructions](docs/automatic_start.md) how to enable this for your -system. - -#### Automatic restore - -Last saved environment is automatically restored when tmux is started. - -Put `set -g @continuum-restore 'on'` in `.tmux.conf` to enable this. - -Note: automatic restore happens **exclusively** on tmux server start. No other -action (e.g. sourcing `.tmux.conf`) triggers this. - -#### Dependencies - -`tmux 1.9` or higher, `bash`, -[tmux-resurrect](https://github.com/tmux-plugins/tmux-resurrect) plugin. - -### Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (recommended) - -Please make sure you have -[tmux-resurrect](https://github.com/tmux-plugins/tmux-resurrect) installed. - -Add plugin to the list of TPM plugins in `.tmux.conf`: - - set -g @plugin 'tmux-plugins/tmux-resurrect' - set -g @plugin 'tmux-plugins/tmux-continuum' - -Hit `prefix + I` to fetch the plugin and source it. The plugin will -automatically start "working" in the background, no action required. - -### Manual Installation - -Please make sure you have -[tmux-resurrect](https://github.com/tmux-plugins/tmux-resurrect) installed. - -Clone the repo: - - $ git clone https://github.com/tmux-plugins/tmux-continuum ~/clone/path - -Add this line to the bottom of `.tmux.conf`: - - run-shell ~/clone/path/continuum.tmux - -Reload TMUX environment with: `$ tmux source-file ~/.tmux.conf` - -The plugin will automatically start "working" in the background, no action -required. - -### Docs - -- [frequently asked questions](docs/faq.md) -- [behavior when running multiple tmux servers](docs/multiple_tmux_servers.md) - - this doc is safe to skip, but you might want to read it if you're using tmux - with `-L` or `-S` flags -- [automatically start tmux after the computer is turned on](docs/automatic_start.md) -- [continuum status in tmux status line](docs/continuum_status.md) - -### Other goodies - -- [tmux-copycat](https://github.com/tmux-plugins/tmux-copycat) - a plugin for - regex searches in tmux and fast match selection -- [tmux-yank](https://github.com/tmux-plugins/tmux-yank) - enables copying - highlighted text to system clipboard -- [tmux-open](https://github.com/tmux-plugins/tmux-open) - a plugin for quickly - opening highlighted file or a url - -### Reporting bugs and contributing - -Both contributing and bug reports are welcome. Please check out -[contributing guidelines](CONTRIBUTING.md). - -### License -[MIT](LICENSE.md) diff --git a/tmux/plugins/tmux-continuum/continuum.tmux b/tmux/plugins/tmux-continuum/continuum.tmux deleted file mode 100755 index 00ad3e9..0000000 --- a/tmux/plugins/tmux-continuum/continuum.tmux +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env bash - -set -x - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/scripts/helpers.sh" -source "$CURRENT_DIR/scripts/variables.sh" -source "$CURRENT_DIR/scripts/shared.sh" - -save_command_interpolation="#($CURRENT_DIR/scripts/continuum_save.sh)" - -supported_tmux_version_ok() { - "$CURRENT_DIR/scripts/check_tmux_version.sh" "$SUPPORTED_VERSION" -} - -handle_tmux_automatic_start() { - "$CURRENT_DIR/scripts/handle_tmux_automatic_start.sh" -} - -another_tmux_server_running() { - if just_started_tmux_server; then - another_tmux_server_running_on_startup - else - # script loaded after tmux server start can have multiple clients attached - [ "$(number_tmux_processes_except_current_server)" -gt "$(number_current_server_client_processes)" ] - fi -} - -delay_saving_environment_on_first_plugin_load() { - if [ -z "$(get_tmux_option "$last_auto_save_option" "")" ]; then - # last save option not set, this is first time plugin load - set_last_save_timestamp - fi -} - -add_resurrect_save_interpolation() { - local status_right_value="$(get_tmux_option "status-right" "")" - # check interpolation not already added - if ! [[ "$status_right_value" == *"$save_command_interpolation"* ]]; then - local new_value="${save_command_interpolation}${status_right_value}" - set_tmux_option "status-right" "$new_value" - fi -} - -just_started_tmux_server() { - local tmux_start_time - tmux_start_time="$(tmux display-message -p -F '#{start_time}')" - [ "$tmux_start_time" == "" ] || [ "$tmux_start_time" -gt "$(($(date +%s)-10))" ] -} - -start_auto_restore_in_background() { - "$CURRENT_DIR/scripts/continuum_restore.sh" & -} - -update_tmux_option() { - local option="$1" - local option_value="$(get_tmux_option "$option")" - # replace interpolation string with a script to execute - local new_option_value="${option_value/$status_interpolation_string/$status_script}" - set_tmux_option "$option" "$new_option_value" -} - -main() { - if supported_tmux_version_ok; then - handle_tmux_automatic_start - - # Advanced edge case handling: start auto-saving only if this is the - # only tmux server. We don't want saved files from more environments to - # overwrite each other. - if ! another_tmux_server_running; then - # give user a chance to restore previously saved session - delay_saving_environment_on_first_plugin_load - add_resurrect_save_interpolation - fi - - if just_started_tmux_server; then - start_auto_restore_in_background - fi - - # Put "#{continuum_status}" interpolation in status-right or - # status-left tmux option to get current tmux continuum status. - update_tmux_option "status-right" - update_tmux_option "status-left" - fi -} -main diff --git a/tmux/plugins/tmux-continuum/scripts/check_tmux_version.sh b/tmux/plugins/tmux-continuum/scripts/check_tmux_version.sh deleted file mode 100755 index f4a887a..0000000 --- a/tmux/plugins/tmux-continuum/scripts/check_tmux_version.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash - -VERSION="$1" -UNSUPPORTED_MSG="$2" - -# this is used to get "clean" integer version number. Examples: -# `tmux 1.9` => `19` -# `1.9a` => `19` -get_digits_from_string() { - local string="$1" - local only_digits="$(echo "$string" | tr -dC '[:digit:]')" - echo "$only_digits" -} - -tmux_version_int() { - local tmux_version_string=$(tmux -V) - echo "$(get_digits_from_string "$tmux_version_string")" -} - -exit_if_unsupported_version() { - local current_version="$1" - local supported_version="$2" - if [ "$current_version" -lt "$supported_version" ]; then - exit 1 - fi -} - -main() { - local supported_version_int="$(get_digits_from_string "$VERSION")" - local current_version_int="$(tmux_version_int)" - exit_if_unsupported_version "$current_version_int" "$supported_version_int" -} -main diff --git a/tmux/plugins/tmux-continuum/scripts/continuum_restore.sh b/tmux/plugins/tmux-continuum/scripts/continuum_restore.sh deleted file mode 100755 index 27afbc4..0000000 --- a/tmux/plugins/tmux-continuum/scripts/continuum_restore.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" -source "$CURRENT_DIR/variables.sh" - -auto_restore_enabled() { - local auto_restore_value="$(get_tmux_option "$auto_restore_option" "$auto_restore_default")" - [ "$auto_restore_value" == "on" ] && [ ! -f "$auto_restore_halt_file" ] -} - -fetch_and_run_tmux_resurrect_restore_script() { - # give tmux some time to start and source all the plugins - sleep 1 - local resurrect_restore_script_path="$(get_tmux_option "$resurrect_restore_path_option" "")" - if [ -n "$resurrect_restore_script_path" ]; then - "$resurrect_restore_script_path" - fi -} - -main() { - # Advanced edge case handling: auto restore only if this is the only tmux - # server. If another tmux server exists, it is assumed auto-restore is not wanted. - if auto_restore_enabled && ! another_tmux_server_running_on_startup; then - fetch_and_run_tmux_resurrect_restore_script - fi -} -main diff --git a/tmux/plugins/tmux-continuum/scripts/continuum_save.sh b/tmux/plugins/tmux-continuum/scripts/continuum_save.sh deleted file mode 100755 index c0e0e7e..0000000 --- a/tmux/plugins/tmux-continuum/scripts/continuum_save.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" -source "$CURRENT_DIR/variables.sh" -source "$CURRENT_DIR/shared.sh" - -supported_tmux_version_ok() { - "$CURRENT_DIR/check_tmux_version.sh" "$SUPPORTED_VERSION" -} - -get_interval() { - get_tmux_option "$auto_save_interval_option" "$auto_save_interval_default" -} - -auto_save_not_disabled() { - [ "$(get_interval)" -gt 0 ] -} - -enough_time_since_last_run_passed() { - local last_saved_timestamp="$(get_tmux_option "$last_auto_save_option" "0")" - local interval_minutes="$(get_interval)" - local interval_seconds="$((interval_minutes * 60))" - local next_run="$((last_saved_timestamp + $interval_seconds))" - [ "$(current_timestamp)" -ge "$next_run" ] -} - -fetch_and_run_tmux_resurrect_save_script() { - local resurrect_save_script_path="$(get_tmux_option "$resurrect_save_path_option" "")" - if [ -n "$resurrect_save_script_path" ]; then - "$resurrect_save_script_path" "quiet" >/dev/null 2>&1 & - set_last_save_timestamp - fi -} - -acquire_lock() { - # Sometimes tmux starts multiple saves in parallel. We want only one - # save to be running, otherwise we can get corrupted saved state. - local lockdir_prefix="/tmp/tmux-continuum-$(current_tmux_server_pid)-lock-" - # The following implements a lock that auto-expires after 100...200s. - local lock_generation=$((`date +%s` / 100)) - local lockdir1="${lockdir_prefix}${lock_generation}" - local lockdir2="${lockdir_prefix}$(($lock_generation + 1))" - if mkdir "$lockdir1"; then - trap "rmdir "$lockdir1"" EXIT - if mkdir "$lockdir2"; then - trap "rmdir "$lockdir1" "$lockdir2"" EXIT - return 0 - fi - fi - return 1 # Someone else has the lock. -} - -main() { - if supported_tmux_version_ok && auto_save_not_disabled && enough_time_since_last_run_passed && acquire_lock; then - fetch_and_run_tmux_resurrect_save_script - fi -} -main diff --git a/tmux/plugins/tmux-continuum/scripts/continuum_status.sh b/tmux/plugins/tmux-continuum/scripts/continuum_status.sh deleted file mode 100755 index 280cf00..0000000 --- a/tmux/plugins/tmux-continuum/scripts/continuum_status.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" -source "$CURRENT_DIR/variables.sh" - -print_status() { - local save_int="$(get_tmux_option "$auto_save_interval_option")" - local status="" - local style_wrap - if [ $save_int -gt 0 ]; then - style_wrap="$(get_tmux_option "$status_on_style_wrap_option" "")" - status="$save_int" - else - style_wrap="$(get_tmux_option "$status_off_style_wrap_option" "")" - status="off" - fi - - if [ -n "$style_wrap" ]; then - status="${style_wrap/$status_wrap_string/$status}" - fi - echo "$status" -} -print_status diff --git a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start.sh b/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start.sh deleted file mode 100755 index 433798b..0000000 --- a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" -source "$CURRENT_DIR/variables.sh" - -is_tmux_automatic_start_enabled() { - local auto_start_value="$(get_tmux_option "$auto_start_option" "$auto_start_default")" - [ "$auto_start_value" == "on" ] -} - -is_osx() { - [ $(uname) == "Darwin" ] -} - -is_systemd() { - [ $(ps -o comm= -p1) == 'systemd' ] -} - -main() { - if is_tmux_automatic_start_enabled; then - if is_osx; then - "$CURRENT_DIR/handle_tmux_automatic_start/osx_enable.sh" - elif is_systemd; then - "$CURRENT_DIR/handle_tmux_automatic_start/systemd_enable.sh" - fi - else - if is_osx; then - "$CURRENT_DIR/handle_tmux_automatic_start/osx_disable.sh" - elif is_systemd; then - "$CURRENT_DIR/handle_tmux_automatic_start/systemd_disable.sh" - fi - fi -} -main diff --git a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/README.md b/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/README.md deleted file mode 120000 index c0cc077..0000000 --- a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/README.md +++ /dev/null @@ -1 +0,0 @@ -docs/automatic_start.md \ No newline at end of file diff --git a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_disable.sh b/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_disable.sh deleted file mode 100755 index 19f9af1..0000000 --- a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_disable.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/../variables.sh" - -main() { - rm "$osx_auto_start_file_path" > /dev/null 2>&1 -} -main diff --git a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_enable.sh b/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_enable.sh deleted file mode 100755 index 7e3e274..0000000 --- a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_enable.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/../helpers.sh" -source "$CURRENT_DIR/../variables.sh" - -template() { - local tmux_start_script="$1" - local is_fullscreen="$2" - - local fullscreen_tag="" - if [ "$is_fullscreen" == "true" ]; then - # newline and spacing so tag is aligned with other tags in template - fullscreen_tag=$'\n fullscreen' - fi - - local content - read -r -d '' content <<-EOF - - - - - Label - ${osx_auto_start_file_name} - ProgramArguments - - ${tmux_start_script}$fullscreen_tag - - RunAtLoad - - - - EOF - echo "$content" -} - -get_iterm_or_teminal_option_value() { - local options="$1" - if [[ "$options" =~ "iterm" ]]; then - echo "iterm" - else - # Terminal.app is the default console app - echo "terminal" - fi -} - -get_fullscreen_option_value() { - local options="$1" - if [[ "$options" =~ "fullscreen" ]]; then - echo "true" - else - echo "false" - fi -} - -main() { - local options="$(get_tmux_option "$auto_start_config_option" "$auto_start_config_default")" - local iterm_or_terminal_value="$(get_iterm_or_teminal_option_value "$options")" - local fullscreen_option_value="$(get_fullscreen_option_value "$options")" - local tmux_start_script_path="${CURRENT_DIR}/osx_${iterm_or_terminal_value}_start_tmux.sh" - - local launchd_plist_file_content="$(template "$tmux_start_script_path" "$fullscreen_option_value")" - echo "$launchd_plist_file_content" > "$osx_auto_start_file_path" -} -main diff --git a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_iterm_start_tmux.sh b/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_iterm_start_tmux.sh deleted file mode 100755 index b79e4d7..0000000 --- a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_iterm_start_tmux.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env bash - -# for "true full screen" call the script with "fullscreen" as the first argument -TRUE_FULL_SCREEN="$1" - -start_iterm_and_run_tmux() { - osascript <<-EOF - tell application "iTerm" - activate - - # open iterm window - try - set _session to current session of current terminal - on error - set _term to (make new terminal) - tell _term - launch session "Tmux" - set _session to current session - end tell - end try - - # start tmux - tell _session - write text "tmux" - end tell - end tell - EOF -} - -resize_window_to_full_screen() { - osascript <<-EOF - tell application "iTerm" - set winID to id of window 1 - tell i term application "Finder" - set desktopSize to bounds of window of desktop - end tell - set bounds of window id winID to desktopSize - end tell - EOF -} - -resize_to_true_full_screen() { - osascript <<-EOF - tell application "iTerm" - # wait for iTerm to start - delay 1 - activate - # short wait for iTerm to gain focus - delay 0.1 - # Command + Enter for fullscreen - tell i term application "System Events" - key code 36 using {command down} - end tell - end tell - EOF -} - -main() { - start_iterm_and_run_tmux - if [ "$TRUE_FULL_SCREEN" == "fullscreen" ]; then - resize_to_true_full_screen - else - resize_window_to_full_screen - fi -} -main diff --git a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_terminal_start_tmux.sh b/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_terminal_start_tmux.sh deleted file mode 100755 index 5a49391..0000000 --- a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/osx_terminal_start_tmux.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env bash - -# for "true full screen" call the script with "fullscreen" as the first argument -TRUE_FULL_SCREEN="$1" - -start_terminal_and_run_tmux() { - osascript <<-EOF - tell application "Terminal" - if not (exists window 1) then reopen - activate - set winID to id of window 1 - do script "tmux" in window id winID - end tell - EOF -} - -resize_window_to_full_screen() { - osascript <<-EOF - tell application "Terminal" - set winID to id of window 1 - tell application "Finder" - set desktopSize to bounds of window of desktop - end tell - set bounds of window id winID to desktopSize - end tell - EOF -} - -resize_to_true_full_screen() { - osascript <<-EOF - tell application "Terminal" - # waiting for Terminal.app to start - delay 1 - activate - # short wait for Terminal to gain focus - delay 0.1 - tell application "System Events" - keystroke "f" using {control down, command down} - end tell - end tell - EOF -} - -main() { - start_terminal_and_run_tmux - if [ "$TRUE_FULL_SCREEN" == "fullscreen" ]; then - resize_to_true_full_screen - else - resize_window_to_full_screen - fi -} -main diff --git a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/systemd_disable.sh b/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/systemd_disable.sh deleted file mode 100755 index 115e1c9..0000000 --- a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/systemd_disable.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/../variables.sh" - -main() { - systemctl --user disable ${systemd_service_name} -} -main diff --git a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/systemd_enable.sh b/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/systemd_enable.sh deleted file mode 100755 index d37c889..0000000 --- a/tmux/plugins/tmux-continuum/scripts/handle_tmux_automatic_start/systemd_enable.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( dirname ${BASH_SOURCE[0]} )" - -source "$CURRENT_DIR/../helpers.sh" -source "$CURRENT_DIR/../variables.sh" - -template() { - local tmux_start_script="$1" - shift - local options="$@" - local content="" - - read -r -d '' content <<-EOF - [Unit] - Description=tmux default session (detached) - Documentation=man:tmux(1) - - [Service] - Type=forking - Environment=DISPLAY=:0 - ExecStart=/usr/bin/tmux ${systemd_tmux_server_start_cmd} - - ExecStop=${HOME}/.tmux/plugins/tmux-resurrect/scripts/save.sh - ExecStop=/usr/bin/tmux kill-server - KillMode=none - - RestartSec=2 - - [Install] - WantedBy=default.target - EOF - - echo "$content" -} - -systemd_tmux_is_enabled() { - systemctl --user is_enabled $(basename "${systemd_unit_file_path}") >/dev/null 2>&1 -} - -enable_tmux_unit_on_boot() { - if ! systemd_tmux_is_enabled; then - systemctl --user enable ${systemd_service_name} - fi -} - -main() { - local options="$(get_tmux_option "$auto_start_config_option" "${auto_start_config_default}")" - local systemd_tmux_server_start_cmd="$(get_tmux_option "${systemd_tmux_server_start_cmd_option}" "${systemd_tmux_server_start_cmd_default}" )" - local tmux_start_script_path="${CURRENT_DIR}/linux_start_tmux.sh" - local systemd_unit_file=$(template "${tmux_start_script_path}" "${options}") - mkdir -p "$(dirname ${systemd_unit_file_path})" - echo "$systemd_unit_file" > "${systemd_unit_file_path}" - enable_tmux_unit_on_boot -} -main diff --git a/tmux/plugins/tmux-continuum/scripts/helpers.sh b/tmux/plugins/tmux-continuum/scripts/helpers.sh deleted file mode 100644 index b64fb36..0000000 --- a/tmux/plugins/tmux-continuum/scripts/helpers.sh +++ /dev/null @@ -1,48 +0,0 @@ -get_tmux_option() { - local option="$1" - local default_value="$2" - local option_value=$(tmux show-option -gqv "$option") - if [ -z "$option_value" ]; then - echo "$default_value" - else - echo "$option_value" - fi -} - -set_tmux_option() { - local option="$1" - local value="$2" - tmux set-option -gq "$option" "$value" -} - -# multiple tmux server detection helpers - -current_tmux_server_pid() { - echo "$TMUX" | - cut -f2 -d"," -} - -all_tmux_processes() { - # ignores `tmux source-file .tmux.conf` command used to reload tmux.conf - ps -Ao "command pid" | - \grep "^tmux" | - \grep -v "^tmux source" -} - -number_tmux_processes_except_current_server() { - all_tmux_processes | - \grep -v " $(current_tmux_server_pid)$" | - wc -l | - sed "s/ //g" -} - -number_current_server_client_processes() { - tmux list-clients | - wc -l | - sed "s/ //g" -} - -another_tmux_server_running_on_startup() { - # there are 2 tmux processes (current tmux server + 1) on tmux startup - [ "$(number_tmux_processes_except_current_server)" -gt 1 ] -} diff --git a/tmux/plugins/tmux-continuum/scripts/shared.sh b/tmux/plugins/tmux-continuum/scripts/shared.sh deleted file mode 100644 index 5ac8885..0000000 --- a/tmux/plugins/tmux-continuum/scripts/shared.sh +++ /dev/null @@ -1,7 +0,0 @@ -current_timestamp() { - echo "$(date +%s)" -} - -set_last_save_timestamp() { - set_tmux_option "$last_auto_save_option" "$(current_timestamp)" -} diff --git a/tmux/plugins/tmux-continuum/scripts/variables.sh b/tmux/plugins/tmux-continuum/scripts/variables.sh deleted file mode 100644 index 8d0a057..0000000 --- a/tmux/plugins/tmux-continuum/scripts/variables.sh +++ /dev/null @@ -1,40 +0,0 @@ -SUPPORTED_VERSION="1.9" - -# these tmux options contain paths to tmux resurrect save and restore scripts -resurrect_save_path_option="@resurrect-save-script-path" -resurrect_restore_path_option="@resurrect-restore-script-path" - -auto_save_interval_option="@continuum-save-interval" -auto_save_interval_default="15" - -# time when the tmux environment was last saved (unix timestamp) -last_auto_save_option="@continuum-save-last-timestamp" - -auto_restore_option="@continuum-restore" -auto_restore_default="off" - -auto_restore_halt_file="${HOME}/tmux_no_auto_restore" - -# tmux auto start options -auto_start_option="@continuum-boot" -auto_start_default="off" - -# comma separated list of additional options for tmux auto start -auto_start_config_option="@continuum-boot-options" -auto_start_config_default="" - -osx_auto_start_file_name="Tmux.Start.plist" -osx_auto_start_file_path="${HOME}/Library/LaunchAgents/${osx_auto_start_file_name}" - -status_interpolation_string="\#{continuum_status}" -status_script="#($CURRENT_DIR/scripts/continuum_status.sh)" -# below options set style/color for #{continuum_status} interpolation -status_on_style_wrap_option="@continuum-status-on-wrap-style" # example value: "#[fg=green]#{value}#[fg=white]" -status_off_style_wrap_option="@continuum-status-off-wrap-style" # example value: "#[fg=yellow,bold]#{value}#[fg=white,nobold]" -status_wrap_string="\#{value}" - -systemd_service_name="tmux.service" -systemd_unit_file_path="$HOME/.config/systemd/user/${systemd_service_name}" - -systemd_tmux_server_start_cmd_option="@continuum-systemd-start-cmd" -systemd_tmux_server_start_cmd_default="new-session -d" diff --git a/tmux/plugins/tmux-copycat/LICENSE.md b/tmux/plugins/tmux-copycat/LICENSE.md deleted file mode 100644 index 40f6ddd..0000000 --- a/tmux/plugins/tmux-copycat/LICENSE.md +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (C) 2014 Bruno Sutic - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE -OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tmux/plugins/tmux-copycat/README.md b/tmux/plugins/tmux-copycat/README.md deleted file mode 100644 index 83a35fe..0000000 --- a/tmux/plugins/tmux-copycat/README.md +++ /dev/null @@ -1,142 +0,0 @@ -# Tmux copycat - -[![Build Status](https://travis-ci.org/tmux-plugins/tmux-copycat.svg?branch=master)](https://travis-ci.org/tmux-plugins/tmux-copycat) - -This plugin enables: - -- regex searches -- search result highlighting -- predefined searches - -Predefined searches are plugin killer feature. It speeds the workflow and -reduces mouse usage with Tmux. - -It works even better when paired with -[tmux yank](https://github.com/tmux-plugins/tmux-yank). Tested and working on -Linux, OSX and Cygwin. - -### Screencast - -[![screencast screenshot](/video/screencast_img.png)](https://vimeo.com/101867689) - -#### Search - -- `prefix + /` - regex search (strings work too) - -Example search entries: - -- `foo` - searches for string `foo` -- `[0-9]+` - regex search for numbers - -Grep is used for searching.
-Searches are case insensitive.
- -#### Predefined searches - -- `prefix + ctrl-f` - simple *f*ile search -- `prefix + ctrl-g` - jumping over *g*it status files (best used after `git status` command) -- `prefix + alt-h` - jumping over SHA-1/SHA-256 hashes (best used after `git log` command) -- `prefix + ctrl-u` - *u*rl search (http, ftp and git urls) -- `prefix + ctrl-d` - number search (mnemonic d, as digit) -- `prefix + alt-i` - *i*p address search - -These start "copycat mode" and jump to first match. - -#### "Copycat mode" bindings - -These are enabled when you search with copycat: - -- `n` - jumps to the next match -- `N` - jumps to the previous match - -To copy a highlighted match: - -- `Enter` - if you're using Tmux `vi` mode -- `ctrl-w` or `alt-w` - if you're using Tmux `emacs` mode - -Copying a highlighted match will take you "out" of copycat mode. Paste with -`prefix + ]` (this is Tmux default paste). - -Copying highlighted matches can be enhanced with -[tmux yank](https://github.com/tmux-plugins/tmux-yank). - -### Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (recommended) - -Add plugin to the list of TPM plugins in `.tmux.conf`: - - set -g @plugin 'tmux-plugins/tmux-copycat' - -Hit `prefix + I` to fetch the plugin and source it. You should now be able to -use the plugin. - -Optional (but recommended) install `gawk` via your package manager of choice -for better UTF-8 character support. - -### Manual Installation - -Clone the repo: - - $ git clone https://github.com/tmux-plugins/tmux-copycat ~/clone/path - -Add this line to the bottom of `.tmux.conf`: - - run-shell ~/clone/path/copycat.tmux - -Reload TMUX environment with: `$ tmux source-file ~/.tmux.conf`. You should now -be able to use the plugin. - -Optional (but recommended) install `gawk` via your package manager of choice -for better UTF-8 character support. - -### Installation for Tmux 2.3 and earlier - -Due to the changes in tmux, the latest version of this plugin doesn't support -tmux 2.3 and earlier. It is recommended you upgrade to tmux version 2.4 or -later. If you must continue using older version, please follow -[these steps for installation](docs/installation_for_tmux_2.3.md). - -### Limitations - -This plugin has some known limitations. Please read about it -[here](docs/limitations.md). - -### Docs - -- Most of the behavior of tmux-copycat can be customized via tmux options. - [Check out the full options list](docs/customizations.md). -- To speed up the workflow you can define new bindings in `.tmux.conf` for - searches you use often, more info [here](docs/defining_new_stored_searches.md) - -### Other goodies - -`tmux-copycat` works great with: - -- [tmux-yank](https://github.com/tmux-plugins/tmux-yank) - enables copying - highlighted text to system clipboard -- [tmux-open](https://github.com/tmux-plugins/tmux-open) - a plugin for quickly - opening a highlighted file or a url -- [tmux-continuum](https://github.com/tmux-plugins/tmux-continuum) - automatic - restoring and continuous saving of tmux env - -### Test suite - -This plugin has a pretty extensive integration test suite that runs on -[travis](https://travis-ci.org/tmux-plugins/tmux-copycat). - -When run locally, it depends on `vagrant`. Run it with: - - # within project top directory - $ ./run-tests - -### Contributions and new features - -Bug fixes and contributions are welcome. - -Feel free to suggest new features, via github issues. - -If you have a bigger idea you'd like to work on, please get in touch, also via -github issues. - -### License - -[MIT](LICENSE.md) diff --git a/tmux/plugins/tmux-copycat/copycat.tmux b/tmux/plugins/tmux-copycat/copycat.tmux deleted file mode 100755 index 7b9f8fb..0000000 --- a/tmux/plugins/tmux-copycat/copycat.tmux +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/scripts/variables.sh" -source "$CURRENT_DIR/scripts/helpers.sh" -source "$CURRENT_DIR/scripts/stored_search_helpers.sh" - -# this function defines default stored searches -set_default_stored_searches() { - local file_search="$(get_tmux_option "$copycat_file_search_option" "$default_file_search_key")" - local url_search="$(get_tmux_option "$copycat_url_search_option" "$default_url_search_key")" - local digit_search="$(get_tmux_option "$copycat_digit_search_option" "$default_digit_search_key")" - local hash_search="$(get_tmux_option "$copycat_hash_search_option" "$default_hash_search_key")" - local ip_search="$(get_tmux_option "$copycat_ip_search_option" "$default_ip_search_key")" - - if stored_search_not_defined "$url_search"; then - tmux set-option -g "${COPYCAT_VAR_PREFIX}_${url_search}" "(https?://|git@|git://|ssh://|ftp://|file:///)[[:alnum:]?=%/_.:,;~@!#$&()*+-]*" - fi - if stored_search_not_defined "$file_search"; then - tmux set-option -g "${COPYCAT_VAR_PREFIX}_${file_search}" "(^|^\.|[[:space:]]|[[:space:]]\.|[[:space:]]\.\.|^\.\.)[[:alnum:]~_-]*/[][[:alnum:]_.#$%&+=/@-]*" - fi - if stored_search_not_defined "$digit_search"; then - tmux set-option -g "${COPYCAT_VAR_PREFIX}_${digit_search}" "[[:digit:]]+" - fi - if stored_search_not_defined "$hash_search"; then - tmux set-option -g "${COPYCAT_VAR_PREFIX}_${hash_search}" "\b([0-9a-f]{7,40}|[[:alnum:]]{52}|[0-9a-f]{62})\b" - fi - if stored_search_not_defined "$ip_search"; then - tmux set-option -g "${COPYCAT_VAR_PREFIX}_${ip_search}" "[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}" - fi -} - -set_start_bindings() { - set_default_stored_searches - local stored_search_vars="$(stored_search_vars)" - local search_var - local key - local pattern - for search_var in $stored_search_vars; do - key="$(get_stored_search_key "$search_var")" - pattern="$(get_stored_search_pattern "$search_var")" - tmux bind-key "$key" run-shell "$CURRENT_DIR/scripts/copycat_mode_start.sh '$pattern'" - done -} - -set_copycat_search_binding() { - local key_bindings - read -r -d '' -a key_bindings <<<"$(get_tmux_option "$copycat_search_option" "$default_copycat_search_key")" - local key - for key in "${key_bindings[@]}"; do - tmux bind-key "$key" run-shell "$CURRENT_DIR/scripts/copycat_search.sh" - done -} - -set_copycat_git_special_binding() { - local key_bindings - read -r -d '' -a key_bindings <<<"$(get_tmux_option "$copycat_git_search_option" "$default_git_search_key")" - local key - for key in "${key_bindings[@]}"; do - tmux bind-key "$key" run-shell "$CURRENT_DIR/scripts/copycat_git_special.sh #{pane_current_path}" - done -} - -main() { - set_start_bindings - set_copycat_search_binding - set_copycat_git_special_binding -} -main diff --git a/tmux/plugins/tmux-copycat/scripts/check_tmux_version.sh b/tmux/plugins/tmux-copycat/scripts/check_tmux_version.sh deleted file mode 100755 index b0aedec..0000000 --- a/tmux/plugins/tmux-copycat/scripts/check_tmux_version.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env bash - -VERSION="$1" -UNSUPPORTED_MSG="$2" - -get_tmux_option() { - local option=$1 - local default_value=$2 - local option_value=$(tmux show-option -gqv "$option") - if [ -z "$option_value" ]; then - echo "$default_value" - else - echo "$option_value" - fi -} - -# Ensures a message is displayed for 5 seconds in tmux prompt. -# Does not override the 'display-time' tmux option. -display_message() { - local message="$1" - - # display_duration defaults to 5 seconds, if not passed as an argument - if [ "$#" -eq 2 ]; then - local display_duration="$2" - else - local display_duration="5000" - fi - - # saves user-set 'display-time' option - local saved_display_time=$(get_tmux_option "display-time" "750") - - # sets message display time to 5 seconds - tmux set-option -gq display-time "$display_duration" - - # displays message - tmux display-message "$message" - - # restores original 'display-time' value - tmux set-option -gq display-time "$saved_display_time" -} - -# this is used to get "clean" integer version number. Examples: -# `tmux 1.9` => `19` -# `1.9a` => `19` -get_digits_from_string() { - local string="$1" - local only_digits="$(echo "$string" | tr -dC '[:digit:]')" - echo "$only_digits" -} - -tmux_version_int() { - local tmux_version_string=$(tmux -V) - echo "$(get_digits_from_string "$tmux_version_string")" -} - -unsupported_version_message() { - if [ -n "$UNSUPPORTED_MSG" ]; then - echo "$UNSUPPORTED_MSG" - else - echo "Error, Tmux version unsupported! Please install Tmux version $VERSION or greater!" - fi -} - -exit_if_unsupported_version() { - local current_version="$1" - local supported_version="$2" - if [ "$current_version" -lt "$supported_version" ]; then - display_message "$(unsupported_version_message)" - exit 1 - fi -} - -main() { - local supported_version_int="$(get_digits_from_string "$VERSION")" - local current_version_int="$(tmux_version_int)" - exit_if_unsupported_version "$current_version_int" "$supported_version_int" -} -main diff --git a/tmux/plugins/tmux-copycat/scripts/copycat_generate_results.sh b/tmux/plugins/tmux-copycat/scripts/copycat_generate_results.sh deleted file mode 100755 index c5f94dc..0000000 --- a/tmux/plugins/tmux-copycat/scripts/copycat_generate_results.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" - -search_pattern="$1" - -capture_pane() { - local file=$1 - # copying 9M lines back will hopefully fetch the whole scrollback - tmux capture-pane -S -9000000 -p > "$file" -} - -# doing 2 things in 1 step so that we don't write to disk too much -reverse_and_create_copycat_file() { - local file=$1 - local copycat_file=$2 - local grep_pattern=$3 - (tac 2>/dev/null || tail -r) < "$file" | grep -oniE "$grep_pattern" > "$copycat_file" -} - -delete_old_files() { - local scrollback_filename="$(get_scrollback_filename)" - local copycat_filename="$(get_copycat_filename)" - rm -f "$scrollback_filename" "$copycat_filename" -} - -generate_copycat_file() { - local grep_pattern="$1" - local scrollback_filename="$(get_scrollback_filename)" - local copycat_filename="$(get_copycat_filename)" - mkdir -p "$(_get_tmp_dir)" - chmod 0700 "$(_get_tmp_dir)" - capture_pane "$scrollback_filename" - reverse_and_create_copycat_file "$scrollback_filename" "$copycat_filename" "$grep_pattern" -} - -if_no_results_exit_with_message() { - local copycat_filename="$(get_copycat_filename)" - # check for empty filename - if ! [ -s "$copycat_filename" ]; then - display_message "No results!" - exit 0 - fi -} - -main() { - local grep_pattern="$1" - if not_in_copycat_mode; then - delete_old_files - generate_copycat_file "$grep_pattern" - if_no_results_exit_with_message - set_copycat_mode - copycat_increase_counter - fi -} -main "$search_pattern" diff --git a/tmux/plugins/tmux-copycat/scripts/copycat_git_special.sh b/tmux/plugins/tmux-copycat/scripts/copycat_git_special.sh deleted file mode 100755 index 6e30bf6..0000000 --- a/tmux/plugins/tmux-copycat/scripts/copycat_git_special.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -PANE_CURRENT_PATH="$1" - -source "$CURRENT_DIR/helpers.sh" - -git_status_files() { - local git_working_dir="$PANE_CURRENT_PATH" - local git_dir="$PANE_CURRENT_PATH/.git" - echo "$(git --git-dir="$git_dir" --work-tree="$git_working_dir" status --porcelain)" -} - -formatted_git_status() { - local raw_gist_status="$(git_status_files)" - echo "$(echo "$raw_gist_status" | cut -c 4-)" -} - -exit_if_no_results() { - local results="$1" - if [ -z "$results" ]; then - display_message "No results!" - exit 0 - fi -} - -concatenate_files() { - local git_status_files="$(formatted_git_status)" - exit_if_no_results "$git_status_files" - - local result="" - # Undefined until later within a while loop. - local file_separator - while read -r line; do - result="${result}${file_separator}${line}" - file_separator="|" - done <<< "$git_status_files" - echo "$result" -} - -# Creates one, big regex out of git status files. -# Example: -# `git status` shows files `foo.txt` and `bar.txt` -# output regex will be: -# `(foo.txt|bar.txt) -git_status_files_regex() { - local concatenated_files="$(concatenate_files)" - local regex_result="(${concatenated_files})" - echo "$regex_result" -} - -main() { - local search_regex="$(git_status_files_regex)" - # starts copycat mode - $CURRENT_DIR/copycat_mode_start.sh "$search_regex" -} -main diff --git a/tmux/plugins/tmux-copycat/scripts/copycat_jump.sh b/tmux/plugins/tmux-copycat/scripts/copycat_jump.sh deleted file mode 100755 index fd2362c..0000000 --- a/tmux/plugins/tmux-copycat/scripts/copycat_jump.sh +++ /dev/null @@ -1,289 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" - -MAXIMUM_PADDING="25" # maximum padding below the result when it can't be centered - -# jump to 'next' or 'prev' match -# global var for this file -NEXT_PREV="$1" - -# 'vi' or 'emacs', this variable used as a global file constant -TMUX_COPY_MODE="$(tmux_copy_mode)" - -_file_number_of_lines() { - local file="$1" - echo "$(wc -l $file | $AWK_CMD '{print $1}')" -} - -_get_result_line() { - local file="$1" - local number="$2" - echo "$(head -"$number" "$file" | tail -1)" -} - -_string_starts_with_digit() { - local string="$1" - echo "$string" | - \grep -q '^[[:digit:]]\+:' -} - -_get_line_number() { - local string="$1" - local copycat_file="$2" # args 2 & 3 used to handle bug in OSX grep - local position_number="$3" - if _string_starts_with_digit "$string"; then - # we have a number! - local grep_line_number="$(echo "$string" | cut -f1 -d:)" - # grep line number index starts from 1, tmux line number index starts from 0 - local tmux_line_number="$((grep_line_number - 1))" - else - # no number in the results line This is a bug in OSX grep. - # Fetching a number from a previous line. - local previous_line_num="$((position_number - 1))" - local result_line="$(_get_result_line "$copycat_file" "$previous_line_num")" - # recursively invoke this same function - tmux_line_number="$(_get_line_number "$result_line" "$copycat_file" "$previous_line_num")" - fi - echo "$tmux_line_number" -} - -_get_match() { - local string="$1" - local full_match - if _string_starts_with_digit "$string"; then - full_match="$(echo "$string" | cut -f2- -d:)" - else - # This scenario handles OS X grep bug "no number in the results line". - # When there's no number at the beginning of the line, we're taking the - # whole line as a match. This handles the result line like this: - # `http://www.example.com` (the `http` would otherwise get cut off) - full_match="$string" - fi - echo -n "$full_match" -} - -_escape_backslash() { - local string="$1" - echo "$(echo "$string" | sed 's/\\/\\\\/g')" -} - -_get_match_line_position() { - local file="$1" - local line_number="$2" - local match="$3" - local adjusted_line_num=$((line_number + 1)) - local result_line=$(tail -"$adjusted_line_num" "$file" | head -1) - - # OS X awk cannot have `=` as the first char in the variable (bug in awk). - # If exists, changing the `=` character with `.` to avoid error. - local platform="$(uname)" - if [ "$platform" == "Darwin" ]; then - result_line="$(echo "$result_line" | sed 's/^=/./')" - match="$(echo "$match" | sed 's/^=/./')" - fi - - # awk treats \r, \n, \t etc as single characters and that messes up match - # highlighting. For that reason, we're escaping backslashes so above chars - # are treated literally. - result_line="$(_escape_backslash "$result_line")" - match="$(_escape_backslash "$match")" - - local index=$($AWK_CMD -v a="$result_line" -v b="$match" 'BEGIN{print index(a,b)}') - local zero_index=$((index - 1)) - echo "$zero_index" -} - -_copycat_jump() { - local line_number="$1" - local match_line_position="$2" - local match="$3" - local scrollback_line_number="$4" - _copycat_enter_mode - _copycat_exit_select_mode - _copycat_jump_to_line "$line_number" "$scrollback_line_number" - _copycat_position_to_match_start "$match_line_position" - _copycat_select "$match" -} - -_copycat_enter_mode() { - tmux copy-mode -} - -# clears selection from a previous match -_copycat_exit_select_mode() { - tmux send-keys -X clear-selection -} - -# "manually" go up in the scrollback for a number of lines -_copycat_manually_go_up() { - local line_number="$1" - tmux send-keys -X -N "$line_number" cursor-up - tmux send-keys -X start-of-line -} - -_copycat_create_padding_below_result() { - local number_of_lines="$1" - local maximum_padding="$2" - local padding - - # Padding should not be greater than half pane height - # (it wouldn't be centered then). - if [ "$number_of_lines" -gt "$maximum_padding" ]; then - padding="$maximum_padding" - else - padding="$number_of_lines" - fi - - # cannot create padding, exit function - if [ "$padding" -eq "0" ]; then - return - fi - - tmux send-keys -X -N "$padding" cursor-down - tmux send-keys -X -N "$padding" cursor-up -} - -# performs a jump to go to line -_copycat_go_to_line_with_jump() { - local line_number="$1" - # first jumps to the "bottom" in copy mode so that jumps are consistent - tmux send-keys -X history-bottom - tmux send-keys -X start-of-line - tmux send-keys -X goto-line $line_number -} - -# maximum line number that can be reached via tmux 'jump' -_get_max_jump() { - local scrollback_line_number="$1" - local window_height="$2" - local max_jump=$((scrollback_line_number - $window_height)) - # max jump can't be lower than zero - if [ "$max_jump" -lt "0" ]; then - max_jump="0" - fi - echo "$max_jump" -} - -_copycat_jump_to_line() { - local line_number="$1" - local scrollback_line_number="$2" - local window_height="$(tmux display-message -p '#{pane_height}')" - local correct_line_number - - local max_jump=$(_get_max_jump "$scrollback_line_number" "$window_height") - local correction="0" - - if [ "$line_number" -gt "$max_jump" ]; then - # We need to 'reach' a line number that is not accessible via 'jump'. - # Introducing 'correction' - correct_line_number="$max_jump" - correction=$((line_number - $correct_line_number)) - else - # we can reach the desired line number via 'jump'. Correction not needed. - correct_line_number="$line_number" - fi - - _copycat_go_to_line_with_jump "$correct_line_number" - - if [ "$correction" -gt "0" ]; then - _copycat_manually_go_up "$correction" - fi - - # If no corrections (meaning result is not at the top of scrollback) - # we can then 'center' the result within a pane. - if [ "$correction" -eq "0" ]; then - local half_window_height="$((window_height / 2))" - # creating as much padding as possible, up to half pane height - _copycat_create_padding_below_result "$line_number" "$half_window_height" - fi -} - -_copycat_position_to_match_start() { - local match_line_position="$1" - [ "$match_line_position" -eq "0" ] && return 0 - - tmux send-keys -X -N "$match_line_position" cursor-right -} - -_copycat_select() { - local match="$1" - local length="${#match}" - tmux send-keys -X begin-selection - tmux send-keys -X -N "$length" cursor-right - if [ "$TMUX_COPY_MODE" == "vi" ]; then - tmux send-keys -X cursor-left # selection correction for 1 char - fi -} - -# all functions above are "private", called from `do_next_jump` function - -get_new_position_number() { - local copycat_file="$1" - local current_position="$2" - local new_position - - # doing a forward/up jump - if [ "$NEXT_PREV" == "next" ]; then - local number_of_results=$(wc -l "$copycat_file" | $AWK_CMD '{ print $1 }') - if [ "$current_position" -eq "$number_of_results" ]; then - # position can't go beyond the last result - new_position="$current_position" - else - new_position="$((current_position + 1))" - fi - - # doing a backward/down jump - elif [ "$NEXT_PREV" == "prev" ]; then - if [ "$current_position" -eq "1" ]; then - # position can't go below 1 - new_position="1" - else - new_position="$((current_position - 1))" - fi - fi - echo "$new_position" -} - -do_next_jump() { - local position_number="$1" - local copycat_file="$2" - local scrollback_file="$3" - - local scrollback_line_number=$(_file_number_of_lines "$scrollback_file") - local result_line="$(_get_result_line "$copycat_file" "$position_number")" - local line_number=$(_get_line_number "$result_line" "$copycat_file" "$position_number") - local match=$(_get_match "$result_line") - local match_line_position=$(_get_match_line_position "$scrollback_file" "$line_number" "$match") - _copycat_jump "$line_number" "$match_line_position" "$match" "$scrollback_line_number" -} - -notify_about_first_last_match() { - local current_position="$1" - local next_position="$2" - local message_duration="1500" - - # if position didn't change, we are either on a 'first' or 'last' match - if [ "$current_position" -eq "$next_position" ]; then - if [ "$NEXT_PREV" == "next" ]; then - display_message "Last match!" "$message_duration" - elif [ "$NEXT_PREV" == "prev" ]; then - display_message "First match!" "$message_duration" - fi - fi -} - -main() { - if in_copycat_mode; then - local copycat_file="$(get_copycat_filename)" - local scrollback_file="$(get_scrollback_filename)" - local current_position="$(get_copycat_position)" - local next_position="$(get_new_position_number "$copycat_file" "$current_position")" - do_next_jump "$next_position" "$copycat_file" "$scrollback_file" - notify_about_first_last_match "$current_position" "$next_position" - set_copycat_position "$next_position" - fi -} -main diff --git a/tmux/plugins/tmux-copycat/scripts/copycat_mode_bindings.sh b/tmux/plugins/tmux-copycat/scripts/copycat_mode_bindings.sh deleted file mode 100755 index 7c63487..0000000 --- a/tmux/plugins/tmux-copycat/scripts/copycat_mode_bindings.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" -AWK_CMD='awk' -if command_exists gawk; then - AWK_CMD='gawk' -fi - -# Extends a keyboard key. -# Benefits: tmux won't report errors and everything will work fine even if the -# script is deleted. -extend_key() { - local key="$1" - local script="$2" - local cmd - - # 1. 'cmd' or 'key' is sent to tmux. This ensures the default key action is done. - # 2. Script is executed. - # 3. `true` command ensures an exit status 0 is returned. This ensures a - # user never gets an error msg - even if the script file from step 2 is - # deleted. - # We fetch the current behavior of the 'key' mapping in - # variable 'cmd' - cmd=$(tmux list-keys -T $(tmux_copy_mode_string) | $AWK_CMD '$4 == "'$key'"' | $AWK_CMD '{ $1=""; $2=""; $3=""; $4=""; sub(" ", " "); print }') - # If 'cmd' is already a copycat command, we do nothing - if echo "$cmd" | grep -q copycat; then - return - fi - # We save the previous mapping to a file in order to be able to recover - # the previous mapping when we unbind - tmux list-keys -T $(tmux_copy_mode_string) | $AWK_CMD '$4 == "'$key'"' >> "${TMPDIR:-/tmp}/copycat_$(whoami)_recover_keys" - tmux bind-key -T $(tmux_copy_mode_string) "$key" run-shell "tmux $cmd; $script; true" -} - -copycat_cancel_bindings() { - # keys that quit copy mode are enhanced to quit copycat mode as well. - local cancel_mode_bindings=$(copycat_quit_copy_mode_keys) - local key - for key in $cancel_mode_bindings; do - extend_key "$key" "$CURRENT_DIR/copycat_mode_quit.sh" - done -} - -copycat_mode_bindings() { - extend_key "$(copycat_next_key)" "$CURRENT_DIR/copycat_jump.sh 'next'" - extend_key "$(copycat_prev_key)" "$CURRENT_DIR/copycat_jump.sh 'prev'" -} - -main() { - copycat_mode_bindings - copycat_cancel_bindings -} -main diff --git a/tmux/plugins/tmux-copycat/scripts/copycat_mode_quit.sh b/tmux/plugins/tmux-copycat/scripts/copycat_mode_quit.sh deleted file mode 100755 index 8b291e1..0000000 --- a/tmux/plugins/tmux-copycat/scripts/copycat_mode_quit.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" - -unbind_cancel_bindings() { - local cancel_mode_bindings=$(copycat_quit_copy_mode_keys) - local key - for key in $cancel_mode_bindings; do - tmux unbind-key -n "$key" - done -} - -unbind_prev_next_bindings() { - tmux unbind-key -n "$(copycat_next_key)" - tmux unbind-key -n "$(copycat_prev_key)" -} - -unbind_all_bindings() { - grep -v copycat <"${TMPDIR:-/tmp}/copycat_$(whoami)_recover_keys" | while read -r key_cmd; do - sh -c "tmux $key_cmd" - done < /dev/stdin - rm "${TMPDIR:-/tmp}/copycat_$(whoami)_recover_keys" -} - -main() { - if in_copycat_mode; then - reset_copycat_position - unset_copycat_mode - copycat_decrease_counter - # removing all bindings only if no panes are in copycat mode - if copycat_counter_zero; then - unbind_all_bindings - fi - fi -} -main diff --git a/tmux/plugins/tmux-copycat/scripts/copycat_mode_start.sh b/tmux/plugins/tmux-copycat/scripts/copycat_mode_start.sh deleted file mode 100755 index 7c0c209..0000000 --- a/tmux/plugins/tmux-copycat/scripts/copycat_mode_start.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -SUPPORTED_VERSION="1.9" - -PATTERN="$1" - -supported_tmux_version_ok() { - $CURRENT_DIR/check_tmux_version.sh "$SUPPORTED_VERSION" -} - -main() { - local pattern="$1" - if supported_tmux_version_ok; then - $CURRENT_DIR/copycat_generate_results.sh "$pattern" # will `exit 0` if no results - $CURRENT_DIR/copycat_mode_bindings.sh - $CURRENT_DIR/copycat_jump.sh 'next' - fi -} -main "$PATTERN" diff --git a/tmux/plugins/tmux-copycat/scripts/copycat_search.sh b/tmux/plugins/tmux-copycat/scripts/copycat_search.sh deleted file mode 100755 index b77f1f2..0000000 --- a/tmux/plugins/tmux-copycat/scripts/copycat_search.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -main() { - tmux command-prompt -p "copycat search:" "run-shell \"$CURRENT_DIR/copycat_mode_start.sh '%1'\"" -} -main diff --git a/tmux/plugins/tmux-copycat/scripts/helpers.sh b/tmux/plugins/tmux-copycat/scripts/helpers.sh deleted file mode 100644 index edc8abb..0000000 --- a/tmux/plugins/tmux-copycat/scripts/helpers.sh +++ /dev/null @@ -1,192 +0,0 @@ -# config options - -default_next_key="n" -tmux_option_next="@copycat_next" - -default_prev_key="N" -tmux_option_prev="@copycat_prev" - -# keeps track of number of panes in copycat mode -tmux_option_counter="@copycat_counter" - -# === awk vs gawk === -command_exists() { - command -v "$@" > /dev/null 2>&1 -} -AWK_CMD='awk' -if command_exists gawk; then - AWK_CMD='gawk' -fi - -# === general helpers === - -get_tmux_option() { - local option=$1 - local default_value=$2 - local option_value=$(tmux show-option -gqv "$option") - if [ -z "$option_value" ]; then - echo "$default_value" - else - echo "$option_value" - fi -} - -set_tmux_option() { - local option=$1 - local value=$2 - tmux set-option -gq "$option" "$value" -} - -tmux_copy_mode() { - tmux show-option -gwv mode-keys -} - -tmux_copy_mode_string() { - if [ $(tmux_copy_mode) == 'vi' ]; then - echo copy-mode-vi - else - echo copy-mode - fi -} - -# === copycat mode specific helpers === - -set_copycat_mode() { - set_tmux_option "$(_copycat_mode_var)" "true" -} - -unset_copycat_mode() { - set_tmux_option "$(_copycat_mode_var)" "false" -} - -in_copycat_mode() { - local copycat_mode=$(get_tmux_option "$(_copycat_mode_var)" "false") - [ "$copycat_mode" == "true" ] -} - -not_in_copycat_mode() { - if in_copycat_mode; then - return 1 - else - return 0 - fi -} - -# === copycat mode position === - -get_copycat_position() { - local copycat_position_variable=$(_copycat_position_var) - echo $(get_tmux_option "$copycat_position_variable" "0") -} - -set_copycat_position() { - local position="$1" - local copycat_position_variable=$(_copycat_position_var) - set_tmux_option "$copycat_position_variable" "$position" -} - -reset_copycat_position() { - set_copycat_position "0" -} - -# === scrollback and results position === - -get_scrollback_filename() { - echo "$(_get_tmp_dir)/scrollback-$(_pane_unique_id)" -} - -get_copycat_filename() { - echo "$(_get_tmp_dir)/results-$(_pane_unique_id)" -} - -# Ensures a message is displayed for 5 seconds in tmux prompt. -# Does not override the 'display-time' tmux option. -display_message() { - local message="$1" - - # display_duration defaults to 5 seconds, if not passed as an argument - if [ "$#" -eq 2 ]; then - local display_duration="$2" - else - local display_duration="5000" - fi - - # saves user-set 'display-time' option - local saved_display_time=$(get_tmux_option "display-time" "750") - - # sets message display time to 5 seconds - tmux set-option -gq display-time "$display_duration" - - # displays message - tmux display-message "$message" - - # restores original 'display-time' value - tmux set-option -gq display-time "$saved_display_time" -} - -# === counter functions === - -copycat_increase_counter() { - local count=$(get_tmux_option "$tmux_option_counter" "0") - local new_count="$((count + 1))" - set_tmux_option "$tmux_option_counter" "$new_count" -} - -copycat_decrease_counter() { - local count="$(get_tmux_option "$tmux_option_counter" "0")" - if [ "$count" -gt "0" ]; then - # decreasing the counter only if it won't go below 0 - local new_count="$((count - 1))" - set_tmux_option "$tmux_option_counter" "$new_count" - fi -} - -copycat_counter_zero() { - local count="$(get_tmux_option "$tmux_option_counter" "0")" - [ "$count" -eq "0" ] -} - -# === key binding functions === - -copycat_next_key() { - echo "$(get_tmux_option "$tmux_option_next" "$default_next_key")" -} - -copycat_prev_key() { - echo "$(get_tmux_option "$tmux_option_prev" "$default_prev_key")" -} - -# function expected output: 'C-c Enter q' -copycat_quit_copy_mode_keys() { - local commands_that_quit_copy_mode="cancel" - local copy_mode="$(tmux_copy_mode_string)" - tmux list-keys -T "$copy_mode" | - \grep "$commands_that_quit_copy_mode" | - $AWK_CMD '{ print $4 }' | - sort -u | - sed 's/C-j//g' | - xargs echo -} - -# === 'private' functions === - -_copycat_mode_var() { - local pane_id="$(_pane_unique_id)" - echo "@copycat_mode_$pane_id" -} - -_copycat_position_var() { - local pane_id="$(_pane_unique_id)" - echo "@copycat_position_$pane_id" -} - -_get_tmp_dir() { - echo "${TMPDIR:-/tmp}/tmux-$EUID-copycat" -} - -# returns a string unique to current pane -# sed removes `$` sign because `session_id` contains is -_pane_unique_id() { - tmux display-message -p "#{session_id}-#{window_index}-#{pane_index}" | - sed 's/\$//' -} diff --git a/tmux/plugins/tmux-copycat/scripts/stored_search_helpers.sh b/tmux/plugins/tmux-copycat/scripts/stored_search_helpers.sh deleted file mode 100644 index 6d192fe..0000000 --- a/tmux/plugins/tmux-copycat/scripts/stored_search_helpers.sh +++ /dev/null @@ -1,23 +0,0 @@ -stored_search_not_defined() { - local key="$1" - local search_value="$(tmux show-option -gqv "${COPYCAT_VAR_PREFIX}_${key}")" - [ -z $search_value ] -} - -stored_search_vars() { - tmux show-options -g | - \grep -i "^${COPYCAT_VAR_PREFIX}_" | - cut -d ' ' -f1 | # cut just variable names - xargs # splat var names in one line -} - -# get the search key from the variable name -get_stored_search_key() { - local search_var="$1" - echo "$(echo "$search_var" | sed "s/^${COPYCAT_VAR_PREFIX}_//")" -} - -get_stored_search_pattern() { - local search_var="$1" - echo "$(get_tmux_option "$search_var" "")" -} diff --git a/tmux/plugins/tmux-copycat/scripts/variables.sh b/tmux/plugins/tmux-copycat/scripts/variables.sh deleted file mode 100644 index 82f8f7a..0000000 --- a/tmux/plugins/tmux-copycat/scripts/variables.sh +++ /dev/null @@ -1,26 +0,0 @@ -# stored search variable prefix -COPYCAT_VAR_PREFIX="@copycat_search" - -# basic search -default_copycat_search_key="/" -copycat_search_option="@copycat_search" - -# git special search -default_git_search_key="C-g" -copycat_git_search_option="@copycat_git_special" - -# regular searches -default_file_search_key="C-f" -copycat_file_search_option="@copycat_file_search" - -default_url_search_key="C-u" -copycat_url_search_option="@copycat_url_search" - -default_digit_search_key="C-d" -copycat_digit_search_option="@copycat_digit_search" - -default_hash_search_key="M-h" -copycat_hash_search_option="@copycat_hash_search" - -default_ip_search_key="M-i" -copycat_ip_search_option="@copycat_ip_search" diff --git a/tmux/plugins/tmux-online-status/LICENSE.md b/tmux/plugins/tmux-online-status/LICENSE.md deleted file mode 100644 index 40f6ddd..0000000 --- a/tmux/plugins/tmux-online-status/LICENSE.md +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (C) 2014 Bruno Sutic - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE -OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tmux/plugins/tmux-online-status/README.md b/tmux/plugins/tmux-online-status/README.md deleted file mode 100644 index 475257e..0000000 --- a/tmux/plugins/tmux-online-status/README.md +++ /dev/null @@ -1,92 +0,0 @@ -# Tmux online status - -Tmux plugin that enables displaying online status for your workstation. - -Introduces a new `#{online_status}` format. - -This plugin is useful if: -- you spend most of your time in Tmux and don't want to "switch" away from - the terminal to check whether you're connected. -- you have a flaky internet connection and you don't want to be surprised - when a simple `curl` or `wget` fails because the connection just broke. - -Tested and working on Linux, OSX, FreeBSD, and Cygwin. - -### Usage - -Add `#{online_status}` format string to your existing `status-right` tmux -option. - -Here's the example in `.tmux.conf`: - - set -g status-right "Online: #{online_status} | %a %h-%d %H:%M " - -**OS X**
-On OS X the above will look like this when online
-![online indicator](/screenshots/online_indicator.png)
-or this when offline
-![offline indicator](/screenshots/offline_indicator.png)
- -**Linux**
-Online status on Linux
-![online indicator](/screenshots/online_indicator_linux.png)
-offline status
-![offline indicator](/screenshots/offline_indicator_linux.png)
- -#### Configure icons -If the icons don't display well on your machine you can change them in -`.tmux.conf`: - - set -g @online_icon "ok" - set -g @offline_icon "offline!" - -### Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (recommended) - -Add plugin to the list of TPM plugins in `.tmux.conf`: - - set -g @plugin 'tmux-plugins/tmux-online-status' - -Hit `prefix + I` to fetch the plugin and source it. - -`#{online_status}` interpolation should now work. - -### Manual Installation - -Clone the repo: - - $ git clone https://github.com/tmux-plugins/tmux-online-status ~/clone/path - -Add this line to the bottom of `.tmux.conf`: - - run-shell ~/clone/path/online_status.tmux - -Reload TMUX environment: - - # type this in terminal - $ tmux source-file ~/.tmux.conf - -`#{online_status}` interpolation should now work. - -### Limitations - -Online status icon most likely won't be instant. The duration depends on the -`status-interval` Tmux option. So, it might take anywhere between 5 and 60 -seconds for online status icon to change. - -Set `status-interval` to a low number to make this faster, example: - - # in .tmux.conf - set -g status-interval 5 - -### Other plugins - -You might also find these useful: - -- [battery](https://github.com/tmux-plugins/tmux-battery) - battery status in - Tmux `status-right` -- [logging](https://github.com/tmux-plugins/tmux-logging) - easy logging and - screen capturing - -### License - -[MIT](LICENSE.md) diff --git a/tmux/plugins/tmux-online-status/online_status.tmux b/tmux/plugins/tmux-online-status/online_status.tmux deleted file mode 100755 index 6856a06..0000000 --- a/tmux/plugins/tmux-online-status/online_status.tmux +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -online_status_icon="#($CURRENT_DIR/scripts/online_status_icon.sh)" -online_status_interpolation_string="\#{online_status}" - -source $CURRENT_DIR/scripts/shared.sh - -do_interpolation() { - local string="$1" - local interpolated="${string/$online_status_interpolation_string/$online_status_icon}" - echo "$interpolated" -} - -update_tmux_option() { - local option="$1" - local option_value="$(get_tmux_option "$option")" - local new_option_value="$(do_interpolation "$option_value")" - set_tmux_option "$option" "$new_option_value" -} - -main() { - update_tmux_option "status-right" - update_tmux_option "status-left" -} -main diff --git a/tmux/plugins/tmux-online-status/scripts/online_status_icon.sh b/tmux/plugins/tmux-online-status/scripts/online_status_icon.sh deleted file mode 100755 index 2114b9d..0000000 --- a/tmux/plugins/tmux-online-status/scripts/online_status_icon.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -online_option_string="@online_icon" -offline_option_string="@offline_icon" -ping_timeout_string="@ping_timeout" -route_to_ping_string="@route_to_ping" - -online_icon_osx="✅ " -online_icon="✔" -offline_icon_osx="⛔️ " -offline_icon_cygwin="X" -offline_icon="❌ " -ping_timeout_default="3" -route_to_ping_default="www.google.com" - -source $CURRENT_DIR/shared.sh - -is_osx() { - [ $(uname) == "Darwin" ] -} - -is_cygwin() { - [[ $(uname) =~ CYGWIN ]] -} - -is_freebsd() { - [ $(uname) == FreeBSD ] -} - -online_icon_default() { - if is_osx; then - echo "$online_icon_osx" - else - echo "$online_icon" - fi -} - -offline_icon_default() { - if is_osx; then - echo "$offline_icon_osx" - elif is_cygwin; then - echo "$offline_icon_cygwin" - else - echo "$offline_icon" - fi -} - -online_status() { - if is_osx || is_freebsd; then - local timeout_flag="-t" - else - local timeout_flag="-w" - fi - if is_cygwin; then - local number_pings_flag="-n" - else - local number_pings_flag="-c" - fi - local ping_timeout="$(get_tmux_option "$ping_timeout_string" "$ping_timeout_default")" - local ping_route="$(get_tmux_option "$route_to_ping_string" "$route_to_ping_default")" - ping "$number_pings_flag" 1 "$timeout_flag" "$ping_timeout" "$ping_route" >/dev/null 2>&1 -} - -print_icon() { - if $(online_status); then - printf "$(get_tmux_option "$online_option_string" "$(online_icon_default)")" - else - printf "$(get_tmux_option "$offline_option_string" "$(offline_icon_default)")" - fi -} - -main() { - print_icon -} -main diff --git a/tmux/plugins/tmux-online-status/scripts/shared.sh b/tmux/plugins/tmux-online-status/scripts/shared.sh deleted file mode 100644 index eba621f..0000000 --- a/tmux/plugins/tmux-online-status/scripts/shared.sh +++ /dev/null @@ -1,16 +0,0 @@ -get_tmux_option() { - local option=$1 - local default_value=$2 - local option_value=$(tmux show-option -gqv "$option") - if [ -z "$option_value" ]; then - echo "$default_value" - else - echo "$option_value" - fi -} - -set_tmux_option() { - local option="$1" - local value="$2" - tmux set-option -gq "$option" "$value" -} diff --git a/tmux/plugins/tmux-open/LICENSE.md b/tmux/plugins/tmux-open/LICENSE.md deleted file mode 100644 index 40f6ddd..0000000 --- a/tmux/plugins/tmux-open/LICENSE.md +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (C) 2014 Bruno Sutic - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE -OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tmux/plugins/tmux-open/README.md b/tmux/plugins/tmux-open/README.md deleted file mode 100644 index d2d17bc..0000000 --- a/tmux/plugins/tmux-open/README.md +++ /dev/null @@ -1,95 +0,0 @@ -# Tmux open - -Plugin for opening highlighted selection directly from Tmux copy mode. - -Tested and working on Linux, OSX and Cygwin. - -### Key bindings - -In tmux copy mode: - -- `o` - "open" a highlighted selection with the system default program. `open` - for OS X or `xdg-open` for Linux. -- `Ctrl-o` - open a highlighted selection with the `$EDITOR` -- `Shift-s` - search the highlighted selection directly inside a search engine (defaults to google). - -### Examples - -In copy mode: - -- highlight `file.pdf` and press `o` - file will open in the default PDF viewer. -- highlight `file.doc` and press `o` - file will open in system default `.doc` - file viewer. -- highlight `http://example.com` and press `o` - link will be opened in the - default browser. -- highlight `file.txt` and press `Ctrl-o` - file will open in `$EDITOR`. -- highlight `TypeError: 'undefined' is not a function` and press `Shift-s` - the text snipped will be searched directly inside google by default - -### Screencast - -[![screencast screenshot](/video/screencast_img.png)](http://vimeo.com/102455265) - -### Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (recommended) - -Add plugin to the list of TPM plugins in `.tmux.conf`: - - set -g @plugin 'tmux-plugins/tmux-open' - -Hit `prefix + I` to fetch the plugin and source it. You should now be able to -use the plugin. - -### Manual Installation - -Clone the repo: - - $ git clone https://github.com/tmux-plugins/tmux-open ~/clone/path - -Add this line to the bottom of `.tmux.conf`: - - run-shell ~/clone/path/open.tmux - -Reload TMUX environment: - - # type this in terminal - $ tmux source-file ~/.tmux.conf - -You should now be able to use the plugin. - -### Configuration - -> How can I change the default "o" key binding to something else? For example, -> key "x"? - -Put `set -g @open 'x'` in `tmux.conf`. - -> How can I change the default "Ctrl-o" key binding to "Ctrl-x"? - -Put `set -g @open-editor 'C-x'` in `tmux.conf`. - -> How can I change the default search engine to "duckduckgo" or any other one? - -Put `set -g @open-S 'https://www.duckduckgo.com/'` in `tmux.conf` - -> How can I use multiple search engines? - -Put: - -``` -set -g @open-B 'https://www.bing.com/search?q=' -set -g @open-S 'https://www.google.com/search?q=' -``` - -in `tmux.conf` - -### Other goodies - -`tmux-open` works great with: - -- [tmux-copycat](https://github.com/tmux-plugins/tmux-copycat) - a plugin for - regex searches in tmux and fast match selection -- [tmux-yank](https://github.com/tmux-plugins/tmux-yank) - enables copying - highlighted text to system clipboard - -### License - -[MIT](LICENSE.md) diff --git a/tmux/plugins/tmux-open/open.tmux b/tmux/plugins/tmux-open/open.tmux deleted file mode 100755 index 824ea24..0000000 --- a/tmux/plugins/tmux-open/open.tmux +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/scripts/helpers.sh" - -default_open_key="o" -open_option="@open" - -default_open_editor_key="C-o" -open_editor_option="@open-editor" -open_editor_override="@open-editor-command" - -command_exists() { - local command="$1" - type "$command" >/dev/null 2>&1 -} - -is_osx() { - local platform=$(uname) - [ "$platform" == "Darwin" ] -} - -is_cygwin() { - [[ "$(uname)" =~ CYGWIN ]] -} - -get_editor_from_the_env_var() { - if [ -z $EDITOR ]; then - # $EDITOR not set, fallback - echo "vi" - else - echo "$EDITOR" - fi -} - -command_generator() { - local command_string="$1" - echo "xargs -I {} tmux run-shell -b 'cd #{pane_current_path}; $command_string \"{}\" > /dev/null'" -} - -search_command_generator() { - local command_string="$1" - local engine="$2" - - echo "xargs -I {} tmux run-shell -b 'cd #{pane_current_path}; $command_string $engine\"{}\" > /dev/null'" -} - -generate_open_command() { - if is_osx; then - echo "$(command_generator "open")" - elif is_cygwin; then - echo "$(command_generator "cygstart")" - elif command_exists "xdg-open"; then - echo "$(command_generator "xdg-open")" - else - # error command for Linux machines when 'xdg-open' not installed - "$CURRENT_DIR/scripts/tmux_open_error_message.sh" "xdg-open" - fi -} - -generate_open_search_command() { - local engine="$1" - if is_osx; then - echo "$(search_command_generator "open" "$engine")" - elif is_cygwin; then - echo "$(command_generator "cygstart")" - elif command_exists "xdg-open"; then - echo "$(search_command_generator "xdg-open" "$engine")" - else - # error command for Linux machines when 'xdg-open' not installed - "$CURRENT_DIR/scripts/tmux_open_error_message.sh" "xdg-open" - fi -} - -# 1. write a command to the terminal, example: 'vim -- some_file.txt' -# 2. invoke the command by pressing enter/C-m -generate_editor_command() { - local environment_editor=$(get_editor_from_the_env_var) - local editor=$(get_tmux_option "$open_editor_override" "$environment_editor") - # vim freezes terminal unless there's the '--' argument. Other editors seem - # to be fine with it (textmate [mate], light table [table]). - echo "xargs -I {} tmux send-keys '$editor -- \"{}\"'; tmux send-keys 'C-m'" -} - -set_copy_mode_open_bindings() { - local open_command="$(generate_open_command)" - local key_bindings=$(get_tmux_option "$open_option" "$default_open_key") - local key - for key in $key_bindings; do - if tmux-is-at-least 2.4; then - tmux bind-key -T copy-mode-vi "$key" send-keys -X copy-pipe-and-cancel "$open_command" - tmux bind-key -T copy-mode "$key" send-keys -X copy-pipe-and-cancel "$open_command" - else - tmux bind-key -t vi-copy "$key" copy-pipe "$open_command" - tmux bind-key -t emacs-copy "$key" copy-pipe "$open_command" - fi - done -} - -set_copy_mode_open_editor_bindings() { - local editor_command="$(generate_editor_command)" - local key_bindings=$(get_tmux_option "$open_editor_option" "$default_open_editor_key") - local key - for key in $key_bindings; do - if tmux-is-at-least 2.4; then - tmux bind-key -T copy-mode-vi "$key" send-keys -X copy-pipe-and-cancel "$editor_command" - tmux bind-key -T copy-mode "$key" send-keys -X copy-pipe-and-cancel "$editor_command" - else - tmux bind-key -t vi-copy "$key" copy-pipe "$editor_command" - tmux bind-key -t emacs-copy "$key" copy-pipe "$editor_command" - fi - done -} - -set_copy_mode_open_search_bindings() { - local stored_engine_vars="$(stored_engine_vars)" - local engine_var - local engine - local key - - for engine_var in $stored_engine_vars; do - engine="$(get_engine "$engine_var")" - - if tmux-is-at-least 2.4; then - tmux bind-key -T copy-mode-vi "$engine_var" send-keys -X copy-pipe-and-cancel "$(generate_open_search_command "$engine")" - tmux bind-key -T copy-mode "$engine_var" send-keys -X copy-pipe-and-cancel "$(generate_open_search_command "$engine")" - else - tmux bind-key -t vi-copy "$engine_var" copy-pipe "$(generate_open_search_command "$engine")" - tmux bind-key -t emacs-copy "$engine_var" copy-pipe "$(generate_open_search_command "$engine")" - fi - - done -} - -main() { - set_copy_mode_open_bindings - set_copy_mode_open_editor_bindings - set_copy_mode_open_search_bindings -} - -main diff --git a/tmux/plugins/tmux-plugin-sysstat/LICENSE b/tmux/plugins/tmux-plugin-sysstat/LICENSE deleted file mode 100644 index 1aa9736..0000000 --- a/tmux/plugins/tmux-plugin-sysstat/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License - -Copyright (c) 2017 Alexey Samoshkin - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/tmux/plugins/tmux-plugin-sysstat/readme.md b/tmux/plugins/tmux-plugin-sysstat/readme.md deleted file mode 100644 index 2bd0295..0000000 --- a/tmux/plugins/tmux-plugin-sysstat/readme.md +++ /dev/null @@ -1,372 +0,0 @@ - -Tmux sysstat plugin -=================== -Allow to print CPU usage, memory & swap, load average, net I/O metrics in Tmux status bar - -![intro](/screenshots/intro.png) - -You might checkout [tmux-config](https://github.com/samoshkin/tmux-config) repo to see this plugin in action. - -Features --------- -- CPU usage -- Memory available/free, used, total (KiB,MiB,GiB), free/used % -- Swap used, free, total, free/used % -- load average for last 1,5,15 minutes -- configurable thresholds (low, medium, stress) with custom colors -- tweak each metric output using templates (e.g, 'used 10% out of 16G') -- configurable size scale (K,M,G) -- OSX, Linux support -- [ ] **TODO:** network I/O metric support - -Tested on: OS X El Capitan 10.11.5, Ubuntu 14 LTS, CentOS 7, FreeBSD 11.1. - - -Installation ------------- -Best installed through [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (TMP). Add following line to your `.tmux.conf` file: - -``` -set -g @plugin 'samoshkin/tmux-plugin-sysstat' -``` - -Use `prefix + I` from inside tmux to install all plugins and source them. If you prefer, same effect can be achieved from [command line](https://github.com/tmux-plugins/tpm/blob/master/docs/managing_plugins_via_cmd_line.md): - -``` -$ ~.tmux/plugins/tpm/bin/install_plugins -``` - -Basic usage ------------ - -Once plugged in, tmux `status-left` or `status-right` options can be configured with following placeholders. Each placeholder will be expanded to metric's default output. - -- `#{sysstat_cpu}`, CPU usage - `CPU:40.2%` -- `#{sysstat_mem}`, memory usage - `MEM:73%` -- `#{sysstat_swap}`, swap usage - `SW:66%` -- `#{sysstat_loadavg}`, system load average - `0.25 0.04 0.34` - -For example: -``` -set -g status-right "#{sysstat_cpu} | #{sysstat_mem} | #{sysstat_swap} | #{sysstat_loadavg} | #[fg=cyan]#(echo $USER)#[default]@#H" -``` - -Changing default output ------------------------- - -You can change default output for CPU and memory metrics, if you need more fields to show, or you want to provide custom template. In your `.tmux.conf`: - -For example, to get `Used 4.5G out of 16G` output for memory metric: - -``` -set -g @sysstat_mem_view_tmpl '#Used [fg=#{mem.color}]#{mem.used}#[default] out of #{mem.total}' -``` - -If you don't want `CPU:` prefix and don't like colored output for CPU metric: - -``` -set -g @sysstat_cpu_view_tmpl '#{cpu.pused}' -``` - -### Supported fields - -As you can see, each metric can be configured with template, containing fixed text (`CPU:`), color placeholder (`#[fg=#{mem.color}]`) and field placeholder (`#{mem.used}`). This approach gives you the ultimate control over the output for each metric. Following field placeholders are supported: - - - - - - - - - - - -
CPU
#{cpu.color}main metric color
#{cpu.pused}CPU usage percentage
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Memory
#{mem.color}main metric color
#{mem.free}free/available memory
#{mem.pfree}free memory percentage against total
#{mem.used}used memory
#{mem.pused}used memory percentage against total
#{mem.total}total installed memory
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Swap
#{swap.color}main swap metric color
#{swap.free}free swap memory
#{swap.pfree}free swap memory percentage against total swap space
#{swap.used}used swap memory
#{swap.pused}used swap memory percentage against total swap space
#{swap.total}total swap space
- -### Change size scale - -free/used/total memory can be shown both in absolute and relative units. When it comes to absolute units, you can choose *size scale factor* to choose between GiB, MiB, KiB. Default is GiB. If you have less than 3-4G memory installed, it makes sense to use MiB. KiB option is less practical, because it yields pretty lengthy output, which does not fit status bar limited estate. - -``` -set -g @sysstat_mem_size_unit "G" -``` - -If you choose `G` for size scale, output will have `%.1f` (1 digit after floating point), otherwise size is integer (4.5G, 1024M, 1232345K). - -Thresholds and colored output ---------------- -Each metric output is colored by default. Colors vary depending on metric value. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ThresholdCPUMemorySwapDefault color
lowx < 30%x < 75%x < 25%green
medium30% < x < 80%75% < x < 90%25% < x < 75%yellow
highx > 80%x > 90%x > 75%red
- -You can change thresholds in your `.tmux.conf`: - -``` -set -g @sysstat_cpu_medium_threshold "75" -set -g @sysstat_cpu_stress_threshold "95" - -set -g @sysstat_mem_medium_threshold "85" -set -g @sysstat_mem_stress_threshold "95" - -set -g @sysstat_swap_medium_threshold "80" -set -g @sysstat_swap_stress_threshold "90" -``` - -You can change colors for each threshold individually. You can use ANSI basic colors (red, cyan, green) or if your terminal supports 256 colors (and most do nowadays), use `colourXXX` format. - -``` -set -g @sysstat_cpu_color_low "colour076" -set -g @sysstat_cpu_color_medium "colour220" -set -g @sysstat_cpu_color_stress "colour160" -set -g @sysstat_mem_color_low "green" -set -g @sysstat_mem_color_medium "blue" -set -g @sysstat_mem_color_stress "cyan" -``` - -`#{(mem|cpu|swap).color}` placeholder in your `@sysstat_(mem|cpu|swap)_view_tmpl` would be replaced by corresponding color, depending on whether metric value falls in particular threshold. - -### 256 color palette support - -For 256 color palette support, make sure that `tmux` and parent terminal are configured with correct terminal type. See [here](https://unix.stackexchange.com/questions/1045/getting-256-colors-to-work-in-tmux) and [there](https://github.com/tmux/tmux/wiki/FAQ) - -``` -# ~/.tmux.conf -set -g default-terminal "screen-256color" -``` - -``` -# parent terminal -$ echo $TERM -xterm-256color - -# jump into a tmux session -$ tmux new -$ echo $TERM -screen-256color -``` - - - -### Multiple colors for each threshold - -You can have up to *3* colors configured for each threshold. To understand why you might need this, let tackle this task. Note, this is rather advanced use case. - -> I want `CPU: #{cpu.pused}` metric output, have green and yellow text colors at "low" and "medium" threshold, and finally, for "high" threshold, I want to use red color, but reverse foreground and background, that is use red for background, and white for text. More over I want "CPU:" text colored apart in red - -Like this: - -![cpu threshold with custom colors](/screenshots/cpu_thresholds.png) - -You can achieve the result using following configuration: - -``` -set -g @sysstat_cpu_view_tmpl '#[fg=#{cpu.color3}]CPU:#[default] #[fg=#{cpu.color},bg=#{cpu.color2}]#{cpu.pused}#[default]' - -set -g @sysstat_cpu_color_low "$color_level_ok default default" -set -g @sysstat_cpu_color_medium "$color_level_warn default default" -set -g @sysstat_cpu_color_stress "white,bold $color_level_stress $color_level_stress" -``` - -Tmux status-interval setting ------------------------------ -You can configure status refresh interval, increasing or reducing frequency of `tmux-plugin-sysstat` command invocations. - -``` -set -g status-interval 5 -``` - -It's adviced to set `status-interval` to some reasonable value, like 5-10 seconds. More frequent updates (1 second) are useless, because they distract, and results in extra resource stress spent on metrics calculation itself. - - - -Internals: CPU calculation --------------------------------------------------- -**NOTE:** Stop here if you want to just use this plugin without making your feet wet. If you're hardcore tmux user and are curious about internals, keep reading - -Internally, we use `iostat` and `top` on OSX, and `vmstat` and `top` on Linux to collect metric value. Neither requires you to install extra packages. These commands are run in sampling mode to report stats every N seconds M times. First sample include average values since the system start. Second one is the average CPU per second for last N seconds (exactly what we need) - -For example: - -``` -$ iostat -c 2 -w 5 - disk0 cpu load average - KB/t tps MB/s us sy id 1m 5m 15m - 44.22 6 0.26 3 2 95 1.74 1.90 2.15 - 5.47 8 0.04 4 5 91 1.84 1.92 2.16 << use this row, 2nd sample -``` - -We align CPU calculation intervals (`-w`) with tmux status bar refresh interval (`status-interval` setting). - -Internals: memory calculation ----------------------------- -You might ask what we treat as `free` memory and how it's calculated. - -### OSX -Let's start with OSX. We use `vm_stat` command (not same as `vmstat` on Linux), which reports following data (number of memory pages, not KB): - -``` -$ vm_stat -Pages free: 37279 -Pages active: 1514200 -Pages inactive: 1152997 -Pages speculative: 6214 -Pages throttled: 0 -Pages wired down: 1174408 -Pages purgeable: 15405 -Pages stored in compressor: 1615663 -Pages occupied by compressor: 306717 -``` - -Total installed memory formula is: -``` -Total = free + active + inactive + speculative + occupied by compressor + wired -``` - -where -- `free`, completely unused memory by the system -- `wired`, critical information stored in RAM by system, kernel and key applications. Never swapped to the hard drive, never replaced with user-level data. -- `active`, information currently in use or very recently used by applications. When this kind of memory is not used for long (or application is closed), it's move to inactive memory. -- `inactive`, like buffers/cached memory in Linux. Memory for applications, which recently exited, retained for faster start-up of same application in future. - -So the question what constitutes `free` and `used` memory. It turns out, that various monitoring and system statistics tools on OSX each calculate it differently. - -- htop: `used = active + wired`, `free` = `total - used` -- top. Used = `used = active + inactive + occupied by compressor + wired`; Free = `free + speculative` Resident set size (RSS) = `active` -- OSX activity Monitor. Used = `app memory + wired + compressor`. Note, it's not clear what is app memory. - -In general, they either treat currently used memory, which can be reclaimed in case of need (cached, inactive, occupied by compressor), as `used` or `free`. - -It makes sense to talk about `available` memory rather than `free` one. Available memory is unused memory + any used memory which can be reclaimed for application needs. - -So, `tmux-plugin-sysstat`, uses following formula: - -``` -used = active + wired -available/free = free/unused + inactive + speculative + occupied by compressor -``` - -### Linux - -Same thinking can be applied to Linux systems. - -Usually commands like `free` report free/unused, used, buffers, cache memory kinds. - -``` -$ free - total used free shared buffers cached -Mem: 1016464 900236 116228 21048 93448 241544 --/+ buffers/cache: 565244 451220 -Swap: 1046524 141712 904812 -``` - -Second line indicates available memory (free + buffers + cache), with an assumption that buffers and cache can be 100% reclaimed in case of need. - -However, we're not using free, because its output varies per system. For example on RHEL7, there is no `-/+ buffers/cache`, and `available` memory is reported in different way. We read directly from `/proc/meminfo` - -``` -$ cat /proc/meminfo - -MemTotal: 1016232 kB -MemFree: 152672 kB -MemAvailable: 637832 kB -Buffers: 0 kB -Cached: 529040 kB -``` - -`tmux-plugin-sysstat` uses following formula: - -``` -free/available = MemAvailable; // if MemAvailable present -free/available = MemFree + Buffers + Cached; -used = MemTotal - free/avaialble -``` - -Using `MemAvailable` is more accurate way of getting available memory, rather than manual calculation `free + buffers + cache`, because the assumption that `buffers + cache` can be 100% reclaimed for new application needs might be wrong. When using `MemAvailable`, OS calculates available memory for you, which is apparently better and accurate approach. - -See [this topic](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773) on more reasoning about `MemAvailable` field. diff --git a/tmux/plugins/tmux-plugin-sysstat/scripts/cpu.sh b/tmux/plugins/tmux-plugin-sysstat/scripts/cpu.sh deleted file mode 100755 index adc2223..0000000 --- a/tmux/plugins/tmux-plugin-sysstat/scripts/cpu.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env bash - -set -u -set -e - -LC_NUMERIC=C - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -source "$CURRENT_DIR/helpers.sh" - -cpu_tmp_dir=$(tmux show-option -gqv "@sysstat_cpu_tmp_dir") - -cpu_view_tmpl=$(get_tmux_option "@sysstat_cpu_view_tmpl" 'CPU:#[fg=#{cpu.color}]#{cpu.pused}#[default]') - -cpu_medium_threshold=$(get_tmux_option "@sysstat_cpu_medium_threshold" "30") -cpu_stress_threshold=$(get_tmux_option "@sysstat_cpu_stress_threshold" "80") - -cpu_color_low=$(get_tmux_option "@sysstat_cpu_color_low" "green") -cpu_color_medium=$(get_tmux_option "@sysstat_cpu_color_medium" "yellow") -cpu_color_stress=$(get_tmux_option "@sysstat_cpu_color_stress" "red") - -get_cpu_color(){ - local cpu_used=$1 - - if fcomp "$cpu_stress_threshold" "$cpu_used"; then - echo "$cpu_color_stress"; - elif fcomp "$cpu_medium_threshold" "$cpu_used"; then - echo "$cpu_color_medium"; - else - echo "$cpu_color_low"; - fi -} - -print_cpu_usage() { - local cpu_pused=$(get_cpu_usage_or_collect) - local cpu_color=$(get_cpu_color "$cpu_pused") - - local cpu_view="$cpu_view_tmpl" - cpu_view="${cpu_view//'#{cpu.pused}'/$(printf "%.1f%%" "$cpu_pused")}" - cpu_view="${cpu_view//'#{cpu.color}'/$(echo "$cpu_color" | awk '{ print $1 }')}" - cpu_view="${cpu_view//'#{cpu.color2}'/$(echo "$cpu_color" | awk '{ print $2 }')}" - cpu_view="${cpu_view//'#{cpu.color3}'/$(echo "$cpu_color" | awk '{ print $3 }')}" - - echo "$cpu_view" -} - -get_cpu_usage_or_collect() { - local collect_cpu_metric="$cpu_tmp_dir/cpu_collect.metric" - - # read cpu metric from file, otherwise 0 as a temporary null value, until first cpu metric is collected - [ -f "$collect_cpu_metric" ] && cat "$collect_cpu_metric" || echo "0.0" - - start_cpu_collect_if_required >/dev/null 2>&1 -} - -start_cpu_collect_if_required() { - local collect_cpu_pidfile="$cpu_tmp_dir/cpu_collect.pid" - - # check if cpu collect process is running, otherwise start it in background - if [ -f "$collect_cpu_pidfile" ] && ps -p "$(cat "$collect_cpu_pidfile")" > /dev/null 2>&1; then - return; - fi - - jobs >/dev/null 2>&1 - "$CURRENT_DIR/cpu_collect.sh" &>/dev/null & - if [ -n "$(jobs -n)" ]; then - echo "$!" > "${collect_cpu_pidfile}" - else - echo "Failed to start CPU collect job" >&2 - exit 1 - fi -} - -main(){ - print_cpu_usage -} - -main diff --git a/tmux/plugins/tmux-plugin-sysstat/scripts/cpu_collect.sh b/tmux/plugins/tmux-plugin-sysstat/scripts/cpu_collect.sh deleted file mode 100755 index 768caba..0000000 --- a/tmux/plugins/tmux-plugin-sysstat/scripts/cpu_collect.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash - -LC_NUMERIC=C - -set -u -set -e - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -source "$CURRENT_DIR/helpers.sh" - -refresh_interval=$(get_tmux_option "status-interval" "5") -samples_count="60" -cpu_metric_file="$(get_tmux_option "@sysstat_cpu_tmp_dir" "/dev/null")/cpu_collect.metric" - -get_cpu_usage() { - if is_osx; then - if command_exists "iostat"; then - iostat -w "$refresh_interval" -c "$samples_count" \ - | stdbuf -o0 awk 'NR > 2 { print 100-$(NF-3); }' - else - top -l "$samples_count" -s "$refresh_interval" -n 0 \ - | sed -u -nr '/CPU usage/s/.*,[[:space:]]*([0-9]+[.,][0-9]*)%[[:space:]]*idle.*/\1/p' \ - | stdbuf -o0 awk '{ print 100-$0 }' - fi - elif ! command_exists "vmstat"; then - if is_freebsd; then - vmstat -n "$refresh_interval" -c "$samples_count" \ - | stdbuf -o0 awk 'NR>2 {print 100-$(NF-0)}' - else - vmstat -n "$refresh_interval" "$samples_count" \ - | stdbuf -o0 awk 'NR>2 {print 100-$(NF-2)}' - fi - else - if is_freebsd; then - top -d"$samples_count" \ - | sed -u -nr '/CPU:/s/.*,[[:space:]]*([0-9]+[.,][0-9]*)%[[:space:]]*id.*/\1/p' \ - | stdbuf -o0 awk '{ print 100-$0 }' - else - top -b -n "$samples_count" -d "$refresh_interval" \ - | sed -u -nr '/%Cpu/s/.*,[[:space:]]*([0-9]+[.,][0-9]*)[[:space:]]*id.*/\1/p' \ - | stdbuf -o0 awk '{ print 100-$0 }' - fi - fi -} - -main() { - get_cpu_usage | while read -r value; do - echo "$value" | tee "$cpu_metric_file" - done -} - -main - diff --git a/tmux/plugins/tmux-plugin-sysstat/scripts/helpers.sh b/tmux/plugins/tmux-plugin-sysstat/scripts/helpers.sh deleted file mode 100755 index 92793b3..0000000 --- a/tmux/plugins/tmux-plugin-sysstat/scripts/helpers.sh +++ /dev/null @@ -1,76 +0,0 @@ - -get_tmux_option() { - local option="$1" - local default_value="$2" - local option_value="$(tmux show-option -gqv "$option")" - if [ -z "$option_value" ]; then - echo "$default_value" - else - echo "$option_value" - fi -} - -set_tmux_option() { - local option="$1" - local value="$2" - tmux set-option -gq "$option" "$value" -} - -is_osx() { - [ $(uname) == "Darwin" ] -} - -is_linux(){ - [ $(uname -s) == "Linux" ] -} - -is_freebsd() { - [ $(uname) == FreeBSD ] -} - -command_exists() { - local command="$1" - type "$command" >/dev/null 2>&1 -} - -# because bash does not support floating-point math -# but awk does -calc() { - local stdin; - read -d '' -u 0 stdin; - awk "BEGIN { print $stdin }"; -} - -# "<" math operator which works with floats, once again based on awk -fcomp() { - awk -v n1="$1" -v n2="$2" 'BEGIN {if (n1`) - -```tmux.conf -set -g @prefix_highlight_output_prefix '< ' -set -g @prefix_highlight_output_suffix ' >' -``` - -The empty (shown when prefix is off) prompt and attribute can be configured, -It is useful for aligning segments. - -```tmux.conf -set -g @prefix_highlight_empty_prompt ' ' # default is '' (empty char) -set -g @prefix_highlight_empty_attr 'fg=default,bg=green' # default is 'fg=default,bg=default' -``` - -Defaultly, empty prompt can't be attached optional affixes. -If you want attach affixes on empty prompt, config `@prefix_highlight_empty_has_affixes` to `on`. - -```tmux.conf -set -g @prefix_highlight_empty_has_affixes 'on' # default is 'off' -set -g @prefix_highlight_empty_prompt 'Tmux' -set -g @prefix_highlight_output_prefix '< ' -set -g @prefix_highlight_output_suffix ' >' -``` - -### License - -[MIT](LICENSE) diff --git a/tmux/plugins/tmux-prefix-highlight/prefix_highlight.tmux b/tmux/plugins/tmux-prefix-highlight/prefix_highlight.tmux deleted file mode 100755 index 7fa21be..0000000 --- a/tmux/plugins/tmux-prefix-highlight/prefix_highlight.tmux +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env bash - -set -e - -# Place holder for status left/right -place_holder="\#{prefix_highlight}" - -# Possible configurations -fg_color_config='@prefix_highlight_fg' -bg_color_config='@prefix_highlight_bg' -output_prefix='@prefix_highlight_output_prefix' -output_suffix='@prefix_highlight_output_suffix' -show_copy_config='@prefix_highlight_show_copy_mode' -copy_attr_config='@prefix_highlight_copy_mode_attr' -prefix_prompt='@prefix_highlight_prefix_prompt' -copy_prompt='@prefix_highlight_copy_prompt' -empty_prompt='@prefix_highlight_empty_prompt' -empty_attr_config='@prefix_highlight_empty_attr' -empty_has_affixes='@prefix_highlight_empty_has_affixes' - -tmux_option() { - local -r value=$(tmux show-option -gqv "$1") - local -r default="$2" - - if [ ! -z "$value" ]; then - echo "$value" - else - echo "$default" - fi -} - -# Defaults -default_fg='colour231' -default_bg='colour04' -default_copy_attr='fg=default,bg=yellow' -default_empty_attr='fg=default,bg=default' -default_prefix_prompt=$(tmux_option prefix | tr "[:lower:]" "[:upper:]" | sed 's/C-/\^/') -default_copy_prompt='Copy' -default_empty_prompt='' - -highlight() { - local -r \ - status="$1" \ - prefix="$2" \ - prefix_highlight="$3" \ - show_copy_mode="$4" \ - copy_highlight="$5" \ - output_prefix="$6" \ - output_suffix="$7" \ - copy="$8" \ - empty="$9" - - local -r status_value="$(tmux_option "$status")" - local -r prefix_with_optional_affixes="$output_prefix$prefix$output_suffix" - local -r copy_with_optional_affixes="$output_prefix$copy$output_suffix" - - if [[ "on" = "$empty_has_affixes" ]]; then - local -r empty_with_optional_affixes="$output_prefix$empty$output_suffix" - else - local -r empty_with_optional_affixes="$empty" - fi - - if [[ "on" = "$show_copy_mode" ]]; then - local -r fallback="${copy_highlight}#{?pane_in_mode,$copy_with_optional_affixes,${empty_highlight}$empty_with_optional_affixes}" - else - local -r fallback="${empty_highlight}$empty_with_optional_affixes" - fi - - local -r highlight_on_prefix="${prefix_highlight}#{?client_prefix,$prefix_with_optional_affixes,$fallback}#[default]" - tmux set-option -gq "$status" "${status_value/$place_holder/$highlight_on_prefix}" -} - -main() { - local -r \ - fg_color=$(tmux_option "$fg_color_config" "$default_fg") \ - bg_color=$(tmux_option "$bg_color_config" "$default_bg") \ - show_copy_mode=$(tmux_option "$show_copy_config" "off") \ - output_prefix=$(tmux_option "$output_prefix" " ") \ - output_suffix=$(tmux_option "$output_suffix" " ") \ - copy_attr=$(tmux_option "$copy_attr_config" "$default_copy_attr") \ - prefix_prompt=$(tmux_option "$prefix_prompt" "$default_prefix_prompt") \ - copy_prompt=$(tmux_option "$copy_prompt" "$default_copy_prompt") \ - empty_prompt=$(tmux_option "$empty_prompt" "$default_empty_prompt") \ - empty_attr=$(tmux_option "$empty_attr_config" "$default_empty_attr") \ - empty_has_affixes=$(tmux_option "$empty_has_affixes" "off") - - local -r \ - prefix_highlight="#[fg=$fg_color,bg=$bg_color]" \ - copy_highlight="${copy_attr:+#[default,$copy_attr]}" \ - empty_highlight="${empty_attr:+#[default,$empty_attr]}" - - highlight "status-right" \ - "$prefix_prompt" \ - "$prefix_highlight" \ - "$show_copy_mode" \ - "$copy_highlight" \ - "$output_prefix" \ - "$output_suffix" \ - "$copy_prompt" \ - "$empty_prompt" \ - "$empty_highlight" \ - "$empty_has_affixes" - - highlight "status-left" \ - "$prefix_prompt" \ - "$prefix_highlight" \ - "$show_copy_mode" \ - "$copy_highlight" \ - "$output_prefix" \ - "$output_suffix" \ - "$copy_prompt" \ - "$empty_prompt" \ - "$empty_highlight" \ - "$empty_has_affixes" -} - -main diff --git a/tmux/plugins/tmux-ressurect/LICENSE.md b/tmux/plugins/tmux-ressurect/LICENSE.md deleted file mode 100644 index 40f6ddd..0000000 --- a/tmux/plugins/tmux-ressurect/LICENSE.md +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (C) 2014 Bruno Sutic - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE -OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tmux/plugins/tmux-ressurect/README.md b/tmux/plugins/tmux-ressurect/README.md deleted file mode 100644 index 94f68f1..0000000 --- a/tmux/plugins/tmux-ressurect/README.md +++ /dev/null @@ -1,133 +0,0 @@ -# Tmux Resurrect - -[![Build Status](https://travis-ci.org/tmux-plugins/tmux-resurrect.svg?branch=master)](https://travis-ci.org/tmux-plugins/tmux-resurrect) - -Restore `tmux` environment after system restart. - -Tmux is great, except when you have to restart the computer. You lose all the -running programs, working directories, pane layouts etc. -There are helpful management tools out there, but they require initial -configuration and continuous updates as your workflow evolves or you start new -projects. - -`tmux-resurrect` saves all the little details from your tmux environment so it -can be completely restored after a system restart (or when you feel like it). -No configuration is required. You should feel like you never quit tmux. - -It even (optionally) -[restores vim and neovim sessions](docs/restoring_vim_and_neovim_sessions.md)! - -Automatic restoring and continuous saving of tmux env is also possible with -[tmux-continuum](https://github.com/tmux-plugins/tmux-continuum) plugin. - -### Screencast - -[![screencast screenshot](/video/screencast_img.png)](https://vimeo.com/104763018) - -### Key bindings - -- `prefix + Ctrl-s` - save -- `prefix + Ctrl-r` - restore - -### About - -This plugin goes to great lengths to save and restore all the details from your -`tmux` environment. Here's what's been taken care of: - -- all sessions, windows, panes and their order -- current working directory for each pane -- **exact pane layouts** within windows (even when zoomed) -- active and alternative session -- active and alternative window for each session -- windows with focus -- active pane for each window -- "grouped sessions" (useful feature when using tmux with multiple monitors) -- programs running within a pane! More details in the - [restoring programs doc](docs/restoring_programs.md). - -Optional: - -- [restoring vim and neovim sessions](docs/restoring_vim_and_neovim_sessions.md) -- [restoring pane contents](docs/restoring_pane_contents.md) -- [restoring shell history](docs/restoring_shell_history.md) (experimental) - -Requirements / dependencies: `tmux 1.9` or higher, `bash`. - -Tested and working on Linux, OSX and Cygwin. - -`tmux-resurrect` is idempotent! It will not try to restore panes or windows that -already exist.
-The single exception to this is when tmux is started with only 1 pane in order -to restore previous tmux env. Only in this case will this single pane be -overwritten. - -### Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (recommended) - -Add plugin to the list of TPM plugins in `.tmux.conf`: - - set -g @plugin 'tmux-plugins/tmux-resurrect' - -Hit `prefix + I` to fetch the plugin and source it. You should now be able to -use the plugin. - -### Manual Installation - -Clone the repo: - - $ git clone https://github.com/tmux-plugins/tmux-resurrect ~/clone/path - -Add this line to the bottom of `.tmux.conf`: - - run-shell ~/clone/path/resurrect.tmux - -Reload TMUX environment with: `$ tmux source-file ~/.tmux.conf`. -You should now be able to use the plugin. - -### Docs - -- [Guide for migrating from tmuxinator](docs/migrating_from_tmuxinator.md) - -**Configuration** - -- [Changing the default key bindings](docs/custom_key_bindings.md). -- [Setting up hooks on save & restore](docs/hooks.md). -- Only a conservative list of programs is restored by default:
- `vi vim nvim emacs man less more tail top htop irssi weechat mutt`.
- [Restoring programs doc](docs/restoring_programs.md) explains how to restore - additional programs. -- [Change a directory](docs/save_dir.md) where `tmux-resurrect` saves tmux - environment. - -**Optional features** - -- [Restoring vim and neovim sessions](docs/restoring_vim_and_neovim_sessions.md) - is nice if you're a vim/neovim user. -- [Restoring pane contents](docs/restoring_pane_contents.md) feature. - -**Experimental features (also optional)** - -- [restoring shell history](docs/restoring_shell_history.md) - -### Other goodies - -- [tmux-copycat](https://github.com/tmux-plugins/tmux-copycat) - a plugin for - regex searches in tmux and fast match selection -- [tmux-yank](https://github.com/tmux-plugins/tmux-yank) - enables copying - highlighted text to system clipboard -- [tmux-open](https://github.com/tmux-plugins/tmux-open) - a plugin for quickly - opening highlighted file or a url -- [tmux-continuum](https://github.com/tmux-plugins/tmux-continuum) - automatic - restoring and continuous saving of tmux env - -### Reporting bugs and contributing - -Both contributing and bug reports are welcome. Please check out -[contributing guidelines](CONTRIBUTING.md). - -### Credits - -[Mislav Marohnić](https://github.com/mislav) - the idea for the plugin came from his -[tmux-session script](https://github.com/mislav/dotfiles/blob/2036b5e03fb430bbcbc340689d63328abaa28876/bin/tmux-session). - -### License -[MIT](LICENSE.md) diff --git a/tmux/plugins/tmux-ressurect/docs/custom_key_bindings.md b/tmux/plugins/tmux-ressurect/docs/custom_key_bindings.md deleted file mode 100644 index 99bfc2c..0000000 --- a/tmux/plugins/tmux-ressurect/docs/custom_key_bindings.md +++ /dev/null @@ -1,11 +0,0 @@ -# Custom key bindings - -The default key bindings are: - -- `prefix + Ctrl-s` - save -- `prefix + Ctrl-r` - restore - -To change these, add to `.tmux.conf`: - - set -g @resurrect-save 'S' - set -g @resurrect-restore 'R' diff --git a/tmux/plugins/tmux-ressurect/docs/hooks.md b/tmux/plugins/tmux-ressurect/docs/hooks.md deleted file mode 100644 index cb4e7a3..0000000 --- a/tmux/plugins/tmux-ressurect/docs/hooks.md +++ /dev/null @@ -1,39 +0,0 @@ -# Save & Restore Hooks - -Hooks allow to set custom commands that will be executed during session save -and restore. Most hooks are called with zero arguments, unless explicitly -stated otherwise. - -Currently the following hooks are supported: - -- `@resurrect-hook-post-save-layout` - - Called after all sessions, panes and windows have been saved. - - Passed single argument of the state file. - -- `@resurrect-hook-post-save-all` - - Called at end of save process right before the spinner is turned off. - -- `@resurrect-hook-pre-restore-all` - - Called before any tmux state is altered. - -- `@resurrect-hook-pre-restore-history` - - Called after panes and layout have been restores, but before bash history is - restored (if it is enabled) -- the hook is always called even if history - saving is disabled. - -- `@resurrect-hook-pre-restore-pane-processes` - - Called after history is restored, but before running processes are restored. - -### Examples - -Here is an example how to save and restore window geometry for most terminals in X11. -Add this to `.tmux.conf`: - - set -g @resurrect-hook-post-save-all 'eval $(xdotool getwindowgeometry --shell $WINDOWID); echo 0,$X,$Y,$WIDTH,$HEIGHT > $HOME/.tmux/resurrect/geometry' - set -g @resurrect-hook-pre-restore-all 'wmctrl -i -r $WINDOWID -e $(cat $HOME/.tmux/resurrect/geometry)' diff --git a/tmux/plugins/tmux-ressurect/docs/migrating_from_tmuxinator.md b/tmux/plugins/tmux-ressurect/docs/migrating_from_tmuxinator.md deleted file mode 100644 index f59f90f..0000000 --- a/tmux/plugins/tmux-ressurect/docs/migrating_from_tmuxinator.md +++ /dev/null @@ -1,72 +0,0 @@ -# Migrating from `tmuxinator` - -### Why migrate to `tmux-resurrect`? - -Here are some reasons why you'd want to migrate from `tmuxinator` to -`tmux-resurrect`: - -- **Less dependencies**
- `tmuxinator` depends on `ruby` which can be a hassle to set up if you're not a - rubyist.
- `tmux-resurrect` depends just on `bash` which is virtually - omnipresent. - -- **Simplicity**
- `tmuxinator` has an executable, CLI interface with half dozen commands and - command completion.
- `tmux-resurrect` defines just 2 tmux key bindings. - -- **No configuration**
- `tmuxinator` is all about config files (and their constant updating).
- `tmux-resurrect` requires no configuration to work. - -- **Better change handling**
- When you make a change to any aspect of tmux layout, you also have to - update related `tmuxinator` project file (and test to make sure change is - ok).
- With `tmux-resurrect` there's nothing to do: your change will be - remembered on the next save. - -### How to migrate? - -1. Install `tmux-resurrect`. -2. Open \*all* existing `tmuxinator` projects.
- Verify all projects are open by pressing `prefix + s` and checking they are - all on the list. -3. Perform a `tmux-resurrect` save. - -That's it! You can continue using just `tmux-resurrect` should you choose so. - -Note: it probably makes no sense to use both tools at the same time as they do -the same thing (creating tmux environment for you to work in). -Technically however, there should be no issues. - -### Usage differences - -`tmuxinator` focuses on managing individual tmux sessions (projects). -`tmux-resurrect` keeps track of the \*whole* tmux environment: all sessions are -saved and restored together. - -A couple tips if you decide to switch to `tmux-resurrect`: - -- Keep all tmux sessions (projects) running all the time.
- If you want to work on an existing project, you should be able to just - \*switch* to an already open session using `prefix + s`.
- This is different from `tmuxinator` where you'd usually run `mux new [project]` - in order to start working on something. - -- No need to kill sessions with `tmux kill-session` (unless you really don't - want to work on it ever).
- It's the recurring theme by now: just keep all the sessions running all the - time. This is convenient and also cheap in terms of resources. - -- The only 2 situations when you need `tmux-resurrect`:
- 1) Save tmux environment just before restarting/shutting down your - computer.
- 2) Restore tmux env after you turn the computer on. - -### Other questions? - -Still have questions? Feel free to open an -[issue](ihttps://github.com/tmux-plugins/tmux-resurrect/issues). We'll try to -answer it and also update this doc. diff --git a/tmux/plugins/tmux-ressurect/docs/restoring_pane_contents.md b/tmux/plugins/tmux-ressurect/docs/restoring_pane_contents.md deleted file mode 100644 index 2dff59a..0000000 --- a/tmux/plugins/tmux-ressurect/docs/restoring_pane_contents.md +++ /dev/null @@ -1,31 +0,0 @@ -# Restoring pane contents - -This plugin enables saving and restoring tmux pane contents. - -This feature can be enabled by adding this line to `.tmux.conf`: - - set -g @resurrect-capture-pane-contents 'on' - -##### Known issue - -When using this feature, please check the value of `default-command` -tmux option. That can be done with `$ tmux show -g default-command`. - -The value should NOT contain `&&` or `||` operators. If it does, simplify the -option so those operators are removed. - -Example: - -- this will cause issues (notice the `&&` and `||` operators): - - set -g default-command "which reattach-to-user-namespace > /dev/null && reattach-to-user-namespace -l $SHELL || $SHELL -l" - -- this is ok: - - set -g default-command "reattach-to-user-namespace -l $SHELL" - -Related [bug](https://github.com/tmux-plugins/tmux-resurrect/issues/98). - -Alternatively, you can let -[tmux-sensible](https://github.com/tmux-plugins/tmux-sensible) -handle this option in a cross-platform way and you'll have no problems. diff --git a/tmux/plugins/tmux-ressurect/docs/restoring_programs.md b/tmux/plugins/tmux-ressurect/docs/restoring_programs.md deleted file mode 100644 index 995d0a7..0000000 --- a/tmux/plugins/tmux-ressurect/docs/restoring_programs.md +++ /dev/null @@ -1,179 +0,0 @@ -# Restoring programs - - [General instructions](#general-instructions) - - [Clarifications](#clarifications) - - [Working with NodeJS](#nodejs) - - [Restoring Mosh](#mosh) - -### General instructions -Only a conservative list of programs is restored by default:
-`vi vim nvim emacs man less more tail top htop irssi weechat mutt`. - -This can be configured with `@resurrect-processes` option in `.tmux.conf`. It -contains space-separated list of additional programs to restore. - -- Example restoring additional programs: - - set -g @resurrect-processes 'ssh psql mysql sqlite3' - -- Programs with arguments should be double quoted: - - set -g @resurrect-processes 'some_program "git log"' - -- Start with tilde to restore a program whose process contains target name: - - set -g @resurrect-processes 'irb pry "~rails server" "~rails console"' - -- Use `->` to specify a command to be used when restoring a program (useful if - the default restore command fails ): - - set -g @resurrect-processes 'some_program "grunt->grunt development"' - -- Don't restore any programs: - - set -g @resurrect-processes 'false' - -- Restore **all** programs (be careful with this!): - - set -g @resurrect-processes ':all:' - -### Clarifications - -> I don't understand tilde `~`, what is it and why is it used when restoring - programs? - -Let's say you use `rails server` command often. You want `tmux-resurrect` to -save and restore it automatically. You might try adding `rails server` to the -list of programs that will be restored: - - set -g @resurrect-processes '"rails server"' # will NOT work - -Upon save, `rails server` command will actually be saved as this command: -`/Users/user/.rbenv/versions/2.0.0-p481/bin/ruby script/rails server` -(if you wanna see how is any command saved, check it yourself in -`~/.tmux/resurrect/last` file). - -When programs are restored, the `rails server` command will NOT be restored -because it does not **strictly** match the long -`/Users/user/.rbenv/versions/2.0.0-p481/bin/ruby script/rails server` string. - -The tilde `~` at the start of the string relaxes process name matching. - - set -g @resurrect-processes '"~rails server"' # OK - -The above option says: "restore full process if `rails server` string is found -ANYWHERE in the process name". - -If you check long process string, there is in fact a `rails server` string at -the end, so now the process will be successfully restored. - -> What is arrow `->` and why is is used? - -(Please read the above clarification about tilde `~`). - -Continuing with our `rails server` example, when the process is finally restored -correctly it might not look pretty as you'll see the whole -`/Users/user/.rbenv/versions/2.0.0-p481/bin/ruby script/rails server` string in -the command line. - -Naturally, you'd rather want to see just `rails server` (what you initially -typed), but that information is now unfortunately lost. - -To aid this, you can use arrow `->`: (**note**: there is no space before and after `->`) - - set -g @resurrect-processes '"~rails server->rails server"' # OK - -This option says: "when this process is restored use `rails server` as the -command name". - -Full (long) process name is now ignored and you'll see just `rails server` in -the command line when the program is restored. - -> Now I understand the tilde and the arrow, but things still don't work for me - -Here's the general workflow for figuring this out: - -- Set up your whole tmux environment manually.
- In our example case, we'd type `rails server` in a pane where we want it to - run. -- Save tmux env (it will get saved to `~/.tmux/resurrect/last`). -- Open `~/.tmux/resurrect/last` file and try to find full process string for - your program.
- Unfortunately this is a little vague but it should be easy. A smart - thing to do for our example is to search for string `rails` in the `last` - file. -- Now that you know the full and the desired process string use tilde `~` and - arrow `->` in `.tmux.conf` to make things work. - -### Working with NodeJS -If you are working with NodeJS, you may get some troubles with configuring restoring programs. - -Particularly, some programs like `gulp`, `grunt` or `npm` are not saved with parameters so tmux-resurrect cannot restore it. This is actually **not tmux-resurrect's issue** but more likely, those programs' issues. For example if you run `gulp watch` or `npm start` and then try to look at `ps` or `pgrep`, you will only see `gulp` or `npm`. - -To deal with these issues, one solution is to use [yarn](https://yarnpkg.com/en/docs/install) which a package manager for NodeJS and an alternative for `npm`. It's nearly identical to `npm` and very easy to use. Therefore you don't have to do any migration, you can simply use it immediately. For example: -- `npm test` is equivalent to `yarn test`, -- `npm run watch:dev` is equivalent to `yarn watch:dev` -- more interestingly, `gulp watch:dev` is equivalent to `yarn gulp watch:dev` - -Before continuing, please ensure that you understand the [clarifications](#clarifications) section about `~` and `->` - -#### yarn -It's fairly straight forward if you have been using `yarn` already. - - set -g @resurrect-processes '"~yarn watch"' - set -g @resurrect-processes '"~yarn watch->yarn watch"' - - -#### npm -Instead of - - set -g @resurrect-processes '"~npm run watch"' # will NOT work - -we use - - set -g @resurrect-processes '"~yarn watch"' # OK - - -#### gulp -Instead of - - set -g @resurrect-processes '"~gulp test"' # will NOT work - -we use - - set -g @resurrect-processes '"~yarn gulp test"' # OK - - -#### nvm -If you use `nvm` in your project, here is how you could config tmux-resurrect: - - set -g @resurrect-processes '"~yarn gulp test->nvm use && gulp test"' - -#### Another problem -Let take a look at this example - - set -g @resurrect-processes '\ - "~yarn gulp test->gulp test" \ - "~yarn gulp test-it->gulp test-it" \ - ' -**This will not work properly**, only `gulp test` is run, although you can see the command `node /path/to/yarn gulp test-it` is added correctly in `.tmux/resurrect/last` file. - -The reason is when restoring program, the **command part after the dash `-` is ignored** so instead of command `gulp test-it`, the command `gulp test` which will be run. - -A work around, for this problem until it's fixed, is: -- the config should be like this: - - set -g @resurrect-processes '\ - "~yarn gulp test->gulp test" \ - "~yarn gulp \"test-it\"->gulp test-it" \ - -- and in `.tmux/resurrect/last`, we should add quote to `test-it` word - - ... node:node /path/to/yarn gulp "test-it" - - -### Restoring Mosh -Mosh spawns a `mosh-client` process, so we need to specify that as the process to be resurrected. - - set -g @resurrect-processes 'mosh-client' - -Additionally a mosh-client strategy is provided to handle extracting the original arguments and re-run Mosh. diff --git a/tmux/plugins/tmux-ressurect/docs/restoring_shell_history.md b/tmux/plugins/tmux-ressurect/docs/restoring_shell_history.md deleted file mode 100644 index 62fc1e2..0000000 --- a/tmux/plugins/tmux-ressurect/docs/restoring_shell_history.md +++ /dev/null @@ -1,19 +0,0 @@ -# Restoring shell history (experimental) - -**Supported shells**: `bash` and `zsh`. - -Enable feature with this option in `.tmux.conf`: - - set -g @resurrect-save-shell-history 'on' - -**Note**: the older `@resurrect-save-bash-history` is now an alias to -`@resurrect-save-shell-history`. - -Shell `history` for individual panes will now be saved and restored. Due to -technical limitations, this only works for panes which have no program running -in foreground when saving. `tmux-resurrect` will send history write command to -each such pane. - -To prevent these commands from being added to `bash` history -themselves, add `HISTCONTROL=ignoreboth` to your `.bashrc` -(this is set by default in Ubuntu). diff --git a/tmux/plugins/tmux-ressurect/docs/restoring_vim_and_neovim_sessions.md b/tmux/plugins/tmux-ressurect/docs/restoring_vim_and_neovim_sessions.md deleted file mode 100644 index f92587f..0000000 --- a/tmux/plugins/tmux-ressurect/docs/restoring_vim_and_neovim_sessions.md +++ /dev/null @@ -1,15 +0,0 @@ -# Restoring vim and neovim sessions - -- save vim/neovim sessions. I recommend - [tpope/vim-obsession](https://github.com/tpope/vim-obsession) (as almost every - plugin, it works for both vim and neovim). -- in `.tmux.conf`: - - # for vim - set -g @resurrect-strategy-vim 'session' - # for neovim - set -g @resurrect-strategy-nvim 'session' - -`tmux-resurrect` will now restore vim and neovim sessions if `Session.vim` file -is present. - diff --git a/tmux/plugins/tmux-ressurect/docs/save_dir.md b/tmux/plugins/tmux-ressurect/docs/save_dir.md deleted file mode 100644 index bf724c6..0000000 --- a/tmux/plugins/tmux-ressurect/docs/save_dir.md +++ /dev/null @@ -1,15 +0,0 @@ -# Resurrect save dir - -By default Tmux environment is saved to a file in `~/.tmux/resurrect` dir. -Change this with: - - set -g @resurrect-dir '/some/path' - -Using environment variables or shell interpolation in this option is not -allowed as the string is used literally. So the following won't do what is -expected: - - set -g @resurrect-dir '/path/$MY_VAR/$(some_executable)' - -Only the following variables and special chars are allowed: -`$HOME`, `$HOSTNAME`, and `~`. diff --git a/tmux/plugins/tmux-ressurect/resurrect.tmux b/tmux/plugins/tmux-ressurect/resurrect.tmux deleted file mode 100755 index 21fed7e..0000000 --- a/tmux/plugins/tmux-ressurect/resurrect.tmux +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/scripts/variables.sh" -source "$CURRENT_DIR/scripts/helpers.sh" - -set_save_bindings() { - local key_bindings=$(get_tmux_option "$save_option" "$default_save_key") - local key - for key in $key_bindings; do - tmux bind-key "$key" run-shell "$CURRENT_DIR/scripts/save.sh" - done -} - -set_restore_bindings() { - local key_bindings=$(get_tmux_option "$restore_option" "$default_restore_key") - local key - for key in $key_bindings; do - tmux bind-key "$key" run-shell "$CURRENT_DIR/scripts/restore.sh" - done -} - -set_default_strategies() { - tmux set-option -gq "${restore_process_strategy_option}irb" "default_strategy" - tmux set-option -gq "${restore_process_strategy_option}mosh-client" "default_strategy" -} - -set_script_path_options() { - tmux set-option -gq "$save_path_option" "$CURRENT_DIR/scripts/save.sh" - tmux set-option -gq "$restore_path_option" "$CURRENT_DIR/scripts/restore.sh" -} - -main() { - set_save_bindings - set_restore_bindings - set_default_strategies - set_script_path_options -} -main diff --git a/tmux/plugins/tmux-ressurect/save_command_strategies/gdb.sh b/tmux/plugins/tmux-ressurect/save_command_strategies/gdb.sh deleted file mode 100755 index 2f0ab56..0000000 --- a/tmux/plugins/tmux-ressurect/save_command_strategies/gdb.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -PANE_PID="$1" - -exit_safely_if_empty_ppid() { - if [ -z "$PANE_PID" ]; then - exit 0 - fi -} - -full_command() { - gdb -batch --eval "attach $PANE_PID" --eval "call write_history(\"/tmp/bash_history-${PANE_PID}.txt\")" --eval 'detach' --eval 'q' >/dev/null 2>&1 - \tail -1 "/tmp/bash_history-${PANE_PID}.txt" -} - -main() { - exit_safely_if_empty_ppid - full_command -} -main diff --git a/tmux/plugins/tmux-ressurect/save_command_strategies/pgrep.sh b/tmux/plugins/tmux-ressurect/save_command_strategies/pgrep.sh deleted file mode 100755 index 15d98b3..0000000 --- a/tmux/plugins/tmux-ressurect/save_command_strategies/pgrep.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -PANE_PID="$1" - -exit_safely_if_empty_ppid() { - if [ -z "$PANE_PID" ]; then - exit 0 - fi -} - -full_command() { - \pgrep -lf -P "$PANE_PID" | - cut -d' ' -f2- -} - -main() { - exit_safely_if_empty_ppid - full_command -} -main diff --git a/tmux/plugins/tmux-ressurect/save_command_strategies/ps.sh b/tmux/plugins/tmux-ressurect/save_command_strategies/ps.sh deleted file mode 100755 index 544426c..0000000 --- a/tmux/plugins/tmux-ressurect/save_command_strategies/ps.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -PANE_PID="$1" - -exit_safely_if_empty_ppid() { - if [ -z "$PANE_PID" ]; then - exit 0 - fi -} - -full_command() { - ps -ao "ppid command" | - sed "s/^ *//" | - grep "^${PANE_PID}" | - cut -d' ' -f2- -} - -main() { - exit_safely_if_empty_ppid - full_command -} -main diff --git a/tmux/plugins/tmux-ressurect/scripts/check_tmux_version.sh b/tmux/plugins/tmux-ressurect/scripts/check_tmux_version.sh deleted file mode 100755 index b0aedec..0000000 --- a/tmux/plugins/tmux-ressurect/scripts/check_tmux_version.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env bash - -VERSION="$1" -UNSUPPORTED_MSG="$2" - -get_tmux_option() { - local option=$1 - local default_value=$2 - local option_value=$(tmux show-option -gqv "$option") - if [ -z "$option_value" ]; then - echo "$default_value" - else - echo "$option_value" - fi -} - -# Ensures a message is displayed for 5 seconds in tmux prompt. -# Does not override the 'display-time' tmux option. -display_message() { - local message="$1" - - # display_duration defaults to 5 seconds, if not passed as an argument - if [ "$#" -eq 2 ]; then - local display_duration="$2" - else - local display_duration="5000" - fi - - # saves user-set 'display-time' option - local saved_display_time=$(get_tmux_option "display-time" "750") - - # sets message display time to 5 seconds - tmux set-option -gq display-time "$display_duration" - - # displays message - tmux display-message "$message" - - # restores original 'display-time' value - tmux set-option -gq display-time "$saved_display_time" -} - -# this is used to get "clean" integer version number. Examples: -# `tmux 1.9` => `19` -# `1.9a` => `19` -get_digits_from_string() { - local string="$1" - local only_digits="$(echo "$string" | tr -dC '[:digit:]')" - echo "$only_digits" -} - -tmux_version_int() { - local tmux_version_string=$(tmux -V) - echo "$(get_digits_from_string "$tmux_version_string")" -} - -unsupported_version_message() { - if [ -n "$UNSUPPORTED_MSG" ]; then - echo "$UNSUPPORTED_MSG" - else - echo "Error, Tmux version unsupported! Please install Tmux version $VERSION or greater!" - fi -} - -exit_if_unsupported_version() { - local current_version="$1" - local supported_version="$2" - if [ "$current_version" -lt "$supported_version" ]; then - display_message "$(unsupported_version_message)" - exit 1 - fi -} - -main() { - local supported_version_int="$(get_digits_from_string "$VERSION")" - local current_version_int="$(tmux_version_int)" - exit_if_unsupported_version "$current_version_int" "$supported_version_int" -} -main diff --git a/tmux/plugins/tmux-ressurect/scripts/helpers.sh b/tmux/plugins/tmux-ressurect/scripts/helpers.sh deleted file mode 100644 index 8a8ea12..0000000 --- a/tmux/plugins/tmux-ressurect/scripts/helpers.sh +++ /dev/null @@ -1,168 +0,0 @@ -default_resurrect_dir="$HOME/.tmux/resurrect" -resurrect_dir_option="@resurrect-dir" - -SUPPORTED_VERSION="1.9" -RESURRECT_FILE_PREFIX="tmux_resurrect" -RESURRECT_FILE_EXTENSION="txt" -_RESURRECT_DIR="" -_RESURRECT_FILE_PATH="" - -d=$'\t' - -# helper functions -get_tmux_option() { - local option="$1" - local default_value="$2" - local option_value=$(tmux show-option -gqv "$option") - if [ -z "$option_value" ]; then - echo "$default_value" - else - echo "$option_value" - fi -} - -# Ensures a message is displayed for 5 seconds in tmux prompt. -# Does not override the 'display-time' tmux option. -display_message() { - local message="$1" - - # display_duration defaults to 5 seconds, if not passed as an argument - if [ "$#" -eq 2 ]; then - local display_duration="$2" - else - local display_duration="5000" - fi - - # saves user-set 'display-time' option - local saved_display_time=$(get_tmux_option "display-time" "750") - - # sets message display time to 5 seconds - tmux set-option -gq display-time "$display_duration" - - # displays message - tmux display-message "$message" - - # restores original 'display-time' value - tmux set-option -gq display-time "$saved_display_time" -} - - -supported_tmux_version_ok() { - $CURRENT_DIR/check_tmux_version.sh "$SUPPORTED_VERSION" -} - -remove_first_char() { - echo "$1" | cut -c2- -} - -capture_pane_contents_option_on() { - local option="$(get_tmux_option "$pane_contents_option" "off")" - [ "$option" == "on" ] -} - -files_differ() { - ! cmp -s "$1" "$2" -} - -save_shell_history_option_on() { - local option_shell="$(get_tmux_option "$shell_history_option" "off")" - local option_bash="$(get_tmux_option "$bash_history_option" "off")" - - [ "$option_shell" == "on" ] || [ "$option_bash" == "on" ] -} - -get_grouped_sessions() { - local grouped_sessions_dump="$1" - export GROUPED_SESSIONS="${d}$(echo "$grouped_sessions_dump" | cut -f2 -d"$d" | tr "\\n" "$d")" -} - -is_session_grouped() { - local session_name="$1" - [[ "$GROUPED_SESSIONS" == *"${d}${session_name}${d}"* ]] -} - -# pane content file helpers - -pane_contents_create_archive() { - tar cf - -C "$(resurrect_dir)/save/" ./pane_contents/ | - gzip > "$(pane_contents_archive_file)" -} - -pane_content_files_restore_from_archive() { - local archive_file="$(pane_contents_archive_file)" - if [ -f "$archive_file" ]; then - mkdir -p "$(pane_contents_dir "restore")" - gzip -d < "$archive_file" | - tar xf - -C "$(resurrect_dir)/restore/" - fi -} - -# path helpers - -resurrect_dir() { - if [ -z "$_RESURRECT_DIR" ]; then - local path="$(get_tmux_option "$resurrect_dir_option" "$default_resurrect_dir")" - # expands tilde, $HOME and $HOSTNAME if used in @resurrect-dir - echo "$path" | sed "s,\$HOME,$HOME,g; s,\$HOSTNAME,$(hostname),g; s,\~,$HOME,g" - else - echo "$_RESURRECT_DIR" - fi -} -_RESURRECT_DIR="$(resurrect_dir)" - -resurrect_file_path() { - if [ -z "$_RESURRECT_FILE_PATH" ]; then - local timestamp="$(date +"%Y%m%dT%H%M%S")" - echo "$(resurrect_dir)/${RESURRECT_FILE_PREFIX}_${timestamp}.${RESURRECT_FILE_EXTENSION}" - else - echo "$_RESURRECT_FILE_PATH" - fi -} -_RESURRECT_FILE_PATH="$(resurrect_file_path)" - -last_resurrect_file() { - echo "$(resurrect_dir)/last" -} - -pane_contents_dir() { - echo "$(resurrect_dir)/$1/pane_contents/" -} - -pane_contents_file() { - local save_or_restore="$1" - local pane_id="$2" - echo "$(pane_contents_dir "$save_or_restore")/pane-${pane_id}" -} - -pane_contents_file_exists() { - local pane_id="$1" - [ -f "$(pane_contents_file "restore" "$pane_id")" ] -} - -pane_contents_archive_file() { - echo "$(resurrect_dir)/pane_contents.tar.gz" -} - -resurrect_history_file() { - local pane_id="$1" - local shell_name="$2" - echo "$(resurrect_dir)/${shell_name}_history-${pane_id}" -} - -execute_hook() { - local kind="$1" - shift - local args="" hook="" - - hook=$(get_tmux_option "$hook_prefix$kind" "") - - # If there are any args, pass them to the hook (in a way that preserves/copes - # with spaces and unusual characters. - if [ "$#" -gt 0 ]; then - printf -v args "%q " "$@" - fi - - if [ -n "$hook" ]; then - eval "$hook $args" - fi -} diff --git a/tmux/plugins/tmux-ressurect/scripts/process_restore_helpers.sh b/tmux/plugins/tmux-ressurect/scripts/process_restore_helpers.sh deleted file mode 100644 index 0b88177..0000000 --- a/tmux/plugins/tmux-ressurect/scripts/process_restore_helpers.sh +++ /dev/null @@ -1,172 +0,0 @@ -restore_pane_processes_enabled() { - local restore_processes="$(get_tmux_option "$restore_processes_option" "$restore_processes")" - if [ "$restore_processes" == "false" ]; then - return 1 - else - return 0 - fi -} - -restore_pane_process() { - local pane_full_command="$1" - local session_name="$2" - local window_number="$3" - local pane_index="$4" - local dir="$5" - local command - if _process_should_be_restored "$pane_full_command" "$session_name" "$window_number" "$pane_index"; then - tmux switch-client -t "${session_name}:${window_number}" - tmux select-pane -t "$pane_index" - - local inline_strategy="$(_get_inline_strategy "$pane_full_command")" # might not be defined - if [ -n "$inline_strategy" ]; then - # inline strategy exists - # check for additional "expansion" of inline strategy, e.g. `vim` to `vim -S` - if _strategy_exists "$inline_strategy"; then - local strategy_file="$(_get_strategy_file "$inline_strategy")" - local inline_strategy="$($strategy_file "$pane_full_command" "$dir")" - fi - command="$inline_strategy" - elif _strategy_exists "$pane_full_command"; then - local strategy_file="$(_get_strategy_file "$pane_full_command")" - local strategy_command="$($strategy_file "$pane_full_command" "$dir")" - command="$strategy_command" - else - # just invoke the raw command - command="$pane_full_command" - fi - tmux send-keys -t "${session_name}:${window_number}.${pane_index}" "$command" "C-m" - fi -} - -# private functions below - -_process_should_be_restored() { - local pane_full_command="$1" - local session_name="$2" - local window_number="$3" - local pane_index="$4" - if is_pane_registered_as_existing "$session_name" "$window_number" "$pane_index"; then - # Scenario where pane existed before restoration, so we're not - # restoring the proces either. - return 1 - elif ! pane_exists "$session_name" "$window_number" "$pane_index"; then - # pane number limit exceeded, pane does not exist - return 1 - elif _restore_all_processes; then - return 0 - elif _process_on_the_restore_list "$pane_full_command"; then - return 0 - else - return 1 - fi -} - -_restore_all_processes() { - local restore_processes="$(get_tmux_option "$restore_processes_option" "$restore_processes")" - if [ "$restore_processes" == ":all:" ]; then - return 0 - else - return 1 - fi -} - -_process_on_the_restore_list() { - local pane_full_command="$1" - # TODO: make this work without eval - eval set $(_restore_list) - local proc - local match - for proc in "$@"; do - match="$(_get_proc_match_element "$proc")" - if _proc_matches_full_command "$pane_full_command" "$match"; then - return 0 - fi - done - return 1 -} - -_proc_matches_full_command() { - local pane_full_command="$1" - local match="$2" - if _proc_starts_with_tildae "$match"; then - match="$(remove_first_char "$match")" - # regex matching the command makes sure `$match` string is somewhere in the command string - if [[ "$pane_full_command" =~ ($match) ]]; then - return 0 - fi - else - # regex matching the command makes sure process is a "word" - if [[ "$pane_full_command" =~ (^${match} ) ]] || [[ "$pane_full_command" =~ (^${match}$) ]]; then - return 0 - fi - fi - return 1 -} - -_get_proc_match_element() { - echo "$1" | sed "s/${inline_strategy_token}.*//" -} - -_get_proc_restore_element() { - echo "$1" | sed "s/.*${inline_strategy_token}//" -} - -_restore_list() { - local user_processes="$(get_tmux_option "$restore_processes_option" "$restore_processes")" - local default_processes="$(get_tmux_option "$default_proc_list_option" "$default_proc_list")" - if [ -z "$user_processes" ]; then - # user didn't define any processes - echo "$default_processes" - else - echo "$default_processes $user_processes" - fi -} - -_proc_starts_with_tildae() { - [[ "$1" =~ (^~) ]] -} - -_get_inline_strategy() { - local pane_full_command="$1" - # TODO: make this work without eval - eval set $(_restore_list) - local proc - local match - for proc in "$@"; do - if [[ "$proc" =~ "$inline_strategy_token" ]]; then - match="$(_get_proc_match_element "$proc")" - if _proc_matches_full_command "$pane_full_command" "$match"; then - echo "$(_get_proc_restore_element "$proc")" - fi - fi - done -} - -_strategy_exists() { - local pane_full_command="$1" - local strategy="$(_get_command_strategy "$pane_full_command")" - if [ -n "$strategy" ]; then # strategy set? - local strategy_file="$(_get_strategy_file "$pane_full_command")" - [ -e "$strategy_file" ] # strategy file exists? - else - return 1 - fi -} - -_get_command_strategy() { - local pane_full_command="$1" - local command="$(_just_command "$pane_full_command")" - get_tmux_option "${restore_process_strategy_option}${command}" "" -} - -_just_command() { - echo "$1" | cut -d' ' -f1 -} - -_get_strategy_file() { - local pane_full_command="$1" - local strategy="$(_get_command_strategy "$pane_full_command")" - local command="$(_just_command "$pane_full_command")" - echo "$CURRENT_DIR/../strategies/${command}_${strategy}.sh" -} diff --git a/tmux/plugins/tmux-ressurect/scripts/restore.exp b/tmux/plugins/tmux-ressurect/scripts/restore.exp deleted file mode 100755 index 8664b1d..0000000 --- a/tmux/plugins/tmux-ressurect/scripts/restore.exp +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env expect - -# start tmux -spawn tmux -S/tmp/foo - -# delay with sleep to compensate for tmux starting time -sleep 2 - -# run restore script directly -send "~/.tmux/plugins/tmux-resurrect/scripts/restore.sh\r" - -# long wait until tmux restore is complete -# (things get messed up if expect client isn't attached) -sleep 100 diff --git a/tmux/plugins/tmux-ressurect/scripts/restore.sh b/tmux/plugins/tmux-ressurect/scripts/restore.sh deleted file mode 100755 index 4104af3..0000000 --- a/tmux/plugins/tmux-ressurect/scripts/restore.sh +++ /dev/null @@ -1,369 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/variables.sh" -source "$CURRENT_DIR/helpers.sh" -source "$CURRENT_DIR/process_restore_helpers.sh" -source "$CURRENT_DIR/spinner_helpers.sh" - -# delimiter -d=$'\t' - -# Global variable. -# Used during the restore: if a pane already exists from before, it is -# saved in the array in this variable. Later, process running in existing pane -# is also not restored. That makes the restoration process more idempotent. -EXISTING_PANES_VAR="" - -RESTORING_FROM_SCRATCH="false" - -RESTORE_PANE_CONTENTS="false" - -is_line_type() { - local line_type="$1" - local line="$2" - echo "$line" | - \grep -q "^$line_type" -} - -check_saved_session_exists() { - local resurrect_file="$(last_resurrect_file)" - if [ ! -f $resurrect_file ]; then - display_message "Tmux resurrect file not found!" - return 1 - fi -} - -pane_exists() { - local session_name="$1" - local window_number="$2" - local pane_index="$3" - tmux list-panes -t "${session_name}:${window_number}" -F "#{pane_index}" 2>/dev/null | - \grep -q "^$pane_index$" -} - -register_existing_pane() { - local session_name="$1" - local window_number="$2" - local pane_index="$3" - local pane_custom_id="${session_name}:${window_number}:${pane_index}" - local delimiter=$'\t' - EXISTING_PANES_VAR="${EXISTING_PANES_VAR}${delimiter}${pane_custom_id}" -} - -is_pane_registered_as_existing() { - local session_name="$1" - local window_number="$2" - local pane_index="$3" - local pane_custom_id="${session_name}:${window_number}:${pane_index}" - [[ "$EXISTING_PANES_VAR" =~ "$pane_custom_id" ]] -} - -restore_from_scratch_true() { - RESTORING_FROM_SCRATCH="true" -} - -is_restoring_from_scratch() { - [ "$RESTORING_FROM_SCRATCH" == "true" ] -} - -restore_pane_contents_true() { - RESTORE_PANE_CONTENTS="true" -} - -is_restoring_pane_contents() { - [ "$RESTORE_PANE_CONTENTS" == "true" ] -} - -window_exists() { - local session_name="$1" - local window_number="$2" - tmux list-windows -t "$session_name" -F "#{window_index}" 2>/dev/null | - \grep -q "^$window_number$" -} - -session_exists() { - local session_name="$1" - tmux has-session -t "$session_name" 2>/dev/null -} - -first_window_num() { - tmux show -gv base-index -} - -tmux_socket() { - echo $TMUX | cut -d',' -f1 -} - -# Tmux option stored in a global variable so that we don't have to "ask" -# tmux server each time. -cache_tmux_default_command() { - local default_shell="$(get_tmux_option "default-shell" "")" - export TMUX_DEFAULT_COMMAND="$(get_tmux_option "default-command" "$default_shell")" -} - -tmux_default_command() { - echo "$TMUX_DEFAULT_COMMAND" -} - -pane_creation_command() { - echo "cat '$(pane_contents_file "restore" "${1}:${2}.${3}")'; exec $(tmux_default_command)" -} - -new_window() { - local session_name="$1" - local window_number="$2" - local window_name="$3" - local dir="$4" - local pane_index="$5" - local pane_id="${session_name}:${window_number}.${pane_index}" - if is_restoring_pane_contents && pane_contents_file_exists "$pane_id"; then - local pane_creation_command="$(pane_creation_command "$session_name" "$window_number" "$pane_index")" - tmux new-window -d -t "${session_name}:${window_number}" -n "$window_name" -c "$dir" "$pane_creation_command" - else - tmux new-window -d -t "${session_name}:${window_number}" -n "$window_name" -c "$dir" - fi -} - -new_session() { - local session_name="$1" - local window_number="$2" - local window_name="$3" - local dir="$4" - local pane_index="$5" - local pane_id="${session_name}:${window_number}.${pane_index}" - if is_restoring_pane_contents && pane_contents_file_exists "$pane_id"; then - local pane_creation_command="$(pane_creation_command "$session_name" "$window_number" "$pane_index")" - TMUX="" tmux -S "$(tmux_socket)" new-session -d -s "$session_name" -n "$window_name" -c "$dir" "$pane_creation_command" - else - TMUX="" tmux -S "$(tmux_socket)" new-session -d -s "$session_name" -n "$window_name" -c "$dir" - fi - # change first window number if necessary - local created_window_num="$(first_window_num)" - if [ $created_window_num -ne $window_number ]; then - tmux move-window -s "${session_name}:${created_window_num}" -t "${session_name}:${window_number}" - fi -} - -new_pane() { - local session_name="$1" - local window_number="$2" - local window_name="$3" - local dir="$4" - local pane_index="$5" - local pane_id="${session_name}:${window_number}.${pane_index}" - if is_restoring_pane_contents && pane_contents_file_exists "$pane_id"; then - local pane_creation_command="$(pane_creation_command "$session_name" "$window_number" "$pane_index")" - tmux split-window -t "${session_name}:${window_number}" -c "$dir" "$pane_creation_command" - else - tmux split-window -t "${session_name}:${window_number}" -c "$dir" - fi - # minimize window so more panes can fit - tmux resize-pane -t "${session_name}:${window_number}" -U "999" -} - -restore_pane() { - local pane="$1" - while IFS=$d read line_type session_name window_number window_name window_active window_flags pane_index dir pane_active pane_command pane_full_command; do - dir="$(remove_first_char "$dir")" - window_name="$(remove_first_char "$window_name")" - pane_full_command="$(remove_first_char "$pane_full_command")" - if pane_exists "$session_name" "$window_number" "$pane_index"; then - tmux rename-window -t "$window_number" "$window_name" - if is_restoring_from_scratch; then - # overwrite the pane - # happens only for the first pane if it's the only registered pane for the whole tmux server - local pane_id="$(tmux display-message -p -F "#{pane_id}" -t "$session_name:$window_number")" - new_pane "$session_name" "$window_number" "$window_name" "$dir" "$pane_index" - tmux kill-pane -t "$pane_id" - else - # Pane exists, no need to create it! - # Pane existence is registered. Later, its process also won't be restored. - register_existing_pane "$session_name" "$window_number" "$pane_index" - fi - elif window_exists "$session_name" "$window_number"; then - tmux rename-window -t "$window_number" "$window_name" - new_pane "$session_name" "$window_number" "$window_name" "$dir" "$pane_index" - elif session_exists "$session_name"; then - new_window "$session_name" "$window_number" "$window_name" "$dir" "$pane_index" - else - new_session "$session_name" "$window_number" "$window_name" "$dir" "$pane_index" - fi - done < <(echo "$pane") -} - -restore_state() { - local state="$1" - echo "$state" | - while IFS=$d read line_type client_session client_last_session; do - tmux switch-client -t "$client_last_session" - tmux switch-client -t "$client_session" - done -} - -restore_grouped_session() { - local grouped_session="$1" - echo "$grouped_session" | - while IFS=$d read line_type grouped_session original_session alternate_window active_window; do - TMUX="" tmux -S "$(tmux_socket)" new-session -d -s "$grouped_session" -t "$original_session" - done -} - -restore_active_and_alternate_windows_for_grouped_sessions() { - local grouped_session="$1" - echo "$grouped_session" | - while IFS=$d read line_type grouped_session original_session alternate_window_index active_window_index; do - alternate_window_index="$(remove_first_char "$alternate_window_index")" - active_window_index="$(remove_first_char "$active_window_index")" - if [ -n "$alternate_window_index" ]; then - tmux switch-client -t "${grouped_session}:${alternate_window_index}" - fi - if [ -n "$active_window_index" ]; then - tmux switch-client -t "${grouped_session}:${active_window_index}" - fi - done -} - -never_ever_overwrite() { - local overwrite_option_value="$(get_tmux_option "$overwrite_option" "")" - [ -n "$overwrite_option_value" ] -} - -detect_if_restoring_from_scratch() { - if never_ever_overwrite; then - return - fi - local total_number_of_panes="$(tmux list-panes -a | wc -l | sed 's/ //g')" - if [ "$total_number_of_panes" -eq 1 ]; then - restore_from_scratch_true - fi -} - -detect_if_restoring_pane_contents() { - if capture_pane_contents_option_on; then - cache_tmux_default_command - restore_pane_contents_true - fi -} - -# functions called from main (ordered) - -restore_all_panes() { - detect_if_restoring_from_scratch # sets a global variable - detect_if_restoring_pane_contents # sets a global variable - if is_restoring_pane_contents; then - pane_content_files_restore_from_archive - fi - while read line; do - if is_line_type "pane" "$line"; then - restore_pane "$line" - fi - done < $(last_resurrect_file) - if is_restoring_pane_contents; then - rm "$(pane_contents_dir "restore")"/* - fi -} - -restore_pane_layout_for_each_window() { - \grep '^window' $(last_resurrect_file) | - while IFS=$d read line_type session_name window_number window_active window_flags window_layout; do - tmux select-layout -t "${session_name}:${window_number}" "$window_layout" - done -} - -restore_shell_history() { - awk 'BEGIN { FS="\t"; OFS="\t" } /^pane/ { print $2, $3, $7, $10; }' $(last_resurrect_file) | - while IFS=$d read session_name window_number pane_index pane_command; do - if ! is_pane_registered_as_existing "$session_name" "$window_number" "$pane_index"; then - local pane_id="$session_name:$window_number.$pane_index" - local history_file="$(resurrect_history_file "$pane_id" "$pane_command")" - - if [ "$pane_command" = "bash" ]; then - local read_command="history -r '$history_file'" - tmux send-keys -t "$pane_id" "$read_command" C-m - elif [ "$pane_command" = "zsh" ]; then - local accept_line="$(expr "$(zsh -i -c bindkey | grep -m1 '\saccept-line$')" : '^"\(.*\)".*')" - local read_command="fc -R '$history_file'; clear" - tmux send-keys -t "$pane_id" "$read_command" "$accept_line" - fi - fi - done -} - -restore_all_pane_processes() { - if restore_pane_processes_enabled; then - local pane_full_command - awk 'BEGIN { FS="\t"; OFS="\t" } /^pane/ && $11 !~ "^:$" { print $2, $3, $7, $8, $11; }' $(last_resurrect_file) | - while IFS=$d read session_name window_number pane_index dir pane_full_command; do - dir="$(remove_first_char "$dir")" - pane_full_command="$(remove_first_char "$pane_full_command")" - restore_pane_process "$pane_full_command" "$session_name" "$window_number" "$pane_index" "$dir" - done - fi -} - -restore_active_pane_for_each_window() { - awk 'BEGIN { FS="\t"; OFS="\t" } /^pane/ && $9 == 1 { print $2, $3, $7; }' $(last_resurrect_file) | - while IFS=$d read session_name window_number active_pane; do - tmux switch-client -t "${session_name}:${window_number}" - tmux select-pane -t "$active_pane" - done -} - -restore_zoomed_windows() { - awk 'BEGIN { FS="\t"; OFS="\t" } /^pane/ && $6 ~ /Z/ && $9 == 1 { print $2, $3; }' $(last_resurrect_file) | - while IFS=$d read session_name window_number; do - tmux resize-pane -t "${session_name}:${window_number}" -Z - done -} - -restore_grouped_sessions() { - while read line; do - if is_line_type "grouped_session" "$line"; then - restore_grouped_session "$line" - restore_active_and_alternate_windows_for_grouped_sessions "$line" - fi - done < $(last_resurrect_file) -} - -restore_active_and_alternate_windows() { - awk 'BEGIN { FS="\t"; OFS="\t" } /^window/ && $5 ~ /[*-]/ { print $2, $4, $3; }' $(last_resurrect_file) | - sort -u | - while IFS=$d read session_name active_window window_number; do - tmux switch-client -t "${session_name}:${window_number}" - done -} - -restore_active_and_alternate_sessions() { - while read line; do - if is_line_type "state" "$line"; then - restore_state "$line" - fi - done < $(last_resurrect_file) -} - -main() { - if supported_tmux_version_ok && check_saved_session_exists; then - start_spinner "Restoring..." "Tmux restore complete!" - execute_hook "pre-restore-all" - restore_all_panes - restore_pane_layout_for_each_window >/dev/null 2>&1 - execute_hook "pre-restore-history" - if save_shell_history_option_on; then - restore_shell_history - fi - execute_hook "pre-restore-pane-processes" - restore_all_pane_processes - # below functions restore exact cursor positions - restore_active_pane_for_each_window - restore_zoomed_windows - restore_grouped_sessions # also restores active and alt windows for grouped sessions - restore_active_and_alternate_windows - restore_active_and_alternate_sessions - execute_hook "post-restore-all" - stop_spinner - display_message "Tmux restore complete!" - fi -} -main diff --git a/tmux/plugins/tmux-ressurect/scripts/save.sh b/tmux/plugins/tmux-ressurect/scripts/save.sh deleted file mode 100755 index 9d80af7..0000000 --- a/tmux/plugins/tmux-ressurect/scripts/save.sh +++ /dev/null @@ -1,322 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/variables.sh" -source "$CURRENT_DIR/helpers.sh" -source "$CURRENT_DIR/spinner_helpers.sh" - -# delimiters -d=$'\t' -delimiter=$'\t' - -# if "quiet" script produces no output -SCRIPT_OUTPUT="$1" - -grouped_sessions_format() { - local format - format+="#{session_grouped}" - format+="${delimiter}" - format+="#{session_group}" - format+="${delimiter}" - format+="#{session_id}" - format+="${delimiter}" - format+="#{session_name}" - echo "$format" -} - -pane_format() { - local format - format+="pane" - format+="${delimiter}" - format+="#{session_name}" - format+="${delimiter}" - format+="#{window_index}" - format+="${delimiter}" - format+=":#{window_name}" - format+="${delimiter}" - format+="#{window_active}" - format+="${delimiter}" - format+=":#{window_flags}" - format+="${delimiter}" - format+="#{pane_index}" - format+="${delimiter}" - format+=":#{pane_current_path}" - format+="${delimiter}" - format+="#{pane_active}" - format+="${delimiter}" - format+="#{pane_current_command}" - format+="${delimiter}" - format+="#{pane_pid}" - format+="${delimiter}" - format+="#{history_size}" - echo "$format" -} - -window_format() { - local format - format+="window" - format+="${delimiter}" - format+="#{session_name}" - format+="${delimiter}" - format+="#{window_index}" - format+="${delimiter}" - format+="#{window_active}" - format+="${delimiter}" - format+=":#{window_flags}" - format+="${delimiter}" - format+="#{window_layout}" - echo "$format" -} - -state_format() { - local format - format+="state" - format+="${delimiter}" - format+="#{client_session}" - format+="${delimiter}" - format+="#{client_last_session}" - echo "$format" -} - -dump_panes_raw() { - tmux list-panes -a -F "$(pane_format)" -} - -dump_windows_raw(){ - tmux list-windows -a -F "$(window_format)" -} - -toggle_window_zoom() { - local target="$1" - tmux resize-pane -Z -t "$target" -} - -_save_command_strategy_file() { - local save_command_strategy="$(get_tmux_option "$save_command_strategy_option" "$default_save_command_strategy")" - local strategy_file="$CURRENT_DIR/../save_command_strategies/${save_command_strategy}.sh" - local default_strategy_file="$CURRENT_DIR/../save_command_strategies/${default_save_command_strategy}.sh" - if [ -e "$strategy_file" ]; then # strategy file exists? - echo "$strategy_file" - else - echo "$default_strategy_file" - fi -} - -pane_full_command() { - local pane_pid="$1" - local strategy_file="$(_save_command_strategy_file)" - # execute strategy script to get pane full command - $strategy_file "$pane_pid" -} - -number_nonempty_lines_on_screen() { - local pane_id="$1" - tmux capture-pane -pJ -t "$pane_id" | - sed '/^$/d' | - wc -l | - sed 's/ //g' -} - -# tests if there was any command output in the current pane -pane_has_any_content() { - local pane_id="$1" - local history_size="$(tmux display -p -t "$pane_id" -F "#{history_size}")" - local cursor_y="$(tmux display -p -t "$pane_id" -F "#{cursor_y}")" - # doing "cheap" tests first - [ "$history_size" -gt 0 ] || # history has any content? - [ "$cursor_y" -gt 0 ] || # cursor not in first line? - [ "$(number_nonempty_lines_on_screen "$pane_id")" -gt 1 ] -} - -capture_pane_contents() { - local pane_id="$1" - local start_line="-$2" - local pane_contents_area="$3" - if pane_has_any_content "$pane_id"; then - if [ "$pane_contents_area" = "visible" ]; then - start_line="0" - fi - # the printf hack below removes *trailing* empty lines - printf '%s\n' "$(tmux capture-pane -epJ -S "$start_line" -t "$pane_id")" > "$(pane_contents_file "save" "$pane_id")" - fi -} - -save_shell_history() { - if [ "$pane_command" = "bash" ]; then - local history_w='history -w' - local history_r='history -r' - local accept_line='C-m' - local end_of_line='C-e' - local backward_kill_line='C-u' - elif [ "$pane_command" = "zsh" ]; then - # fc -W does not work with -L - # fc -l format is different from what's written by fc -W - # fc -R either reads the format produced by fc -W or considers - # the entire line to be a command. That's why we need -n. - # fc -l only list the last 16 items by default, I think 64 is more reasonable. - local history_w='fc -lLn -64 >' - local history_r='fc -R' - - local zsh_bindkey="$(zsh -i -c bindkey)" - local accept_line="$(expr "$(echo "$zsh_bindkey" | grep -m1 '\saccept-line$')" : '^"\(.*\)".*')" - local end_of_line="$(expr "$(echo "$zsh_bindkey" | grep -m1 '\send-of-line$')" : '^"\(.*\)".*')" - local backward_kill_line="$(expr "$(echo "$zsh_bindkey" | grep -m1 '\sbackward-kill-line$')" : '^"\(.*\)".*')" - else - return - fi - - local pane_id="$1" - local pane_command="$2" - local full_command="$3" - if [ "$full_command" = ":" ]; then - # leading space prevents the command from being saved to history - # (assuming default HISTCONTROL settings) - local write_command=" $history_w '$(resurrect_history_file "$pane_id" "$pane_command")'" - local read_command=" $history_r '$(resurrect_history_file "$pane_id" "$pane_command")'" - # C-e C-u is a Bash shortcut sequence to clear whole line. It is necessary to - # delete any pending input so it does not interfere with our history command. - tmux send-keys -t "$pane_id" "$end_of_line" "$backward_kill_line" "$write_command" "$accept_line" - # Immediately restore after saving - tmux send-keys -t "$pane_id" "$end_of_line" "$backward_kill_line" "$read_command" "$accept_line" - fi -} - -get_active_window_index() { - local session_name="$1" - tmux list-windows -t "$session_name" -F "#{window_flags} #{window_index}" | - awk '$1 ~ /\*/ { print $2; }' -} - -get_alternate_window_index() { - local session_name="$1" - tmux list-windows -t "$session_name" -F "#{window_flags} #{window_index}" | - awk '$1 ~ /-/ { print $2; }' -} - -dump_grouped_sessions() { - local current_session_group="" - local original_session - tmux list-sessions -F "$(grouped_sessions_format)" | - grep "^1" | - cut -c 3- | - sort | - while IFS=$d read session_group session_id session_name; do - if [ "$session_group" != "$current_session_group" ]; then - # this session is the original/first session in the group - original_session="$session_name" - current_session_group="$session_group" - else - # this session "points" to the original session - active_window_index="$(get_active_window_index "$session_name")" - alternate_window_index="$(get_alternate_window_index "$session_name")" - echo "grouped_session${d}${session_name}${d}${original_session}${d}:${alternate_window_index}${d}:${active_window_index}" - fi - done -} - -fetch_and_dump_grouped_sessions(){ - local grouped_sessions_dump="$(dump_grouped_sessions)" - get_grouped_sessions "$grouped_sessions_dump" - if [ -n "$grouped_sessions_dump" ]; then - echo "$grouped_sessions_dump" - fi -} - -# translates pane pid to process command running inside a pane -dump_panes() { - local full_command - dump_panes_raw | - while IFS=$d read line_type session_name window_number window_name window_active window_flags pane_index dir pane_active pane_command pane_pid history_size; do - # not saving panes from grouped sessions - if is_session_grouped "$session_name"; then - continue - fi - full_command="$(pane_full_command $pane_pid)" - dir=$(echo $dir | sed 's/ /\\ /') # escape all spaces in directory path - echo "${line_type}${d}${session_name}${d}${window_number}${d}${window_name}${d}${window_active}${d}${window_flags}${d}${pane_index}${d}${dir}${d}${pane_active}${d}${pane_command}${d}:${full_command}" - done -} - -dump_windows() { - dump_windows_raw | - while IFS=$d read line_type session_name window_index window_active window_flags window_layout; do - # not saving windows from grouped sessions - if is_session_grouped "$session_name"; then - continue - fi - echo "${line_type}${d}${session_name}${d}${window_index}${d}${window_active}${d}${window_flags}${d}${window_layout}" - done -} - -dump_state() { - tmux display-message -p "$(state_format)" -} - -dump_pane_contents() { - local pane_contents_area="$(get_tmux_option "$pane_contents_area_option" "$default_pane_contents_area")" - dump_panes_raw | - while IFS=$d read line_type session_name window_number window_name window_active window_flags pane_index dir pane_active pane_command pane_pid history_size; do - capture_pane_contents "${session_name}:${window_number}.${pane_index}" "$history_size" "$pane_contents_area" - done -} - -dump_shell_history() { - dump_panes | - while IFS=$d read line_type session_name window_number window_name window_active window_flags pane_index dir pane_active pane_command full_command; do - save_shell_history "$session_name:$window_number.$pane_index" "$pane_command" "$full_command" - done -} - -remove_old_backups() { - # remove resurrect files older than 30 days, but keep at least 5 copies of backup. - local -a files - files=($(ls -t $(resurrect_dir)/${RESURRECT_FILE_PREFIX}_*.${RESURRECT_FILE_EXTENSION} | tail -n +6)) - [[ ${#files[@]} -eq 0 ]] || - find "${files[@]}" -type f -mtime +30 -exec rm -v "{}" \; -} - -save_all() { - local resurrect_file_path="$(resurrect_file_path)" - local last_resurrect_file="$(last_resurrect_file)" - mkdir -p "$(resurrect_dir)" - fetch_and_dump_grouped_sessions > "$resurrect_file_path" - dump_panes >> "$resurrect_file_path" - dump_windows >> "$resurrect_file_path" - dump_state >> "$resurrect_file_path" - execute_hook "post-save-layout" "$resurrect_file_path" - if files_differ "$resurrect_file_path" "$last_resurrect_file"; then - ln -fs "$(basename "$resurrect_file_path")" "$last_resurrect_file" - else - rm "$resurrect_file_path" - fi - if capture_pane_contents_option_on; then - mkdir -p "$(pane_contents_dir "save")" - dump_pane_contents - pane_contents_create_archive - rm "$(pane_contents_dir "save")"/* - fi - if save_shell_history_option_on; then - dump_shell_history - fi - remove_old_backups - execute_hook "post-save-all" -} - -show_output() { - [ "$SCRIPT_OUTPUT" != "quiet" ] -} - -main() { - if supported_tmux_version_ok; then - if show_output; then - start_spinner "Saving..." "Tmux environment saved!" - fi - save_all - if show_output; then - stop_spinner - display_message "Tmux environment saved!" - fi - fi -} -main diff --git a/tmux/plugins/tmux-ressurect/scripts/spinner_helpers.sh b/tmux/plugins/tmux-ressurect/scripts/spinner_helpers.sh deleted file mode 100644 index fe73cd7..0000000 --- a/tmux/plugins/tmux-ressurect/scripts/spinner_helpers.sh +++ /dev/null @@ -1,8 +0,0 @@ -start_spinner() { - $CURRENT_DIR/tmux_spinner.sh "$1" "$2" & - export SPINNER_PID=$! -} - -stop_spinner() { - kill $SPINNER_PID -} diff --git a/tmux/plugins/tmux-ressurect/scripts/tmux_spinner.sh b/tmux/plugins/tmux-ressurect/scripts/tmux_spinner.sh deleted file mode 100755 index 9b1b979..0000000 --- a/tmux/plugins/tmux-ressurect/scripts/tmux_spinner.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -# This script shows tmux spinner with a message. It is intended to be running -# as a background process which should be `kill`ed at the end. -# -# Example usage: -# -# ./tmux_spinner.sh "Working..." "End message!" & -# SPINNER_PID=$! -# .. -# .. execute commands here -# .. -# kill $SPINNER_PID # Stops spinner and displays 'End message!' - -MESSAGE="$1" -END_MESSAGE="$2" -SPIN='-\|/' - -trap "tmux display-message '$END_MESSAGE'; exit" SIGINT SIGTERM - -main() { - local i=0 - while true; do - i=$(( (i+1) %4 )) - tmux display-message " ${SPIN:$i:1} $MESSAGE" - sleep 0.1 - done -} -main diff --git a/tmux/plugins/tmux-ressurect/scripts/variables.sh b/tmux/plugins/tmux-ressurect/scripts/variables.sh deleted file mode 100644 index 9436957..0000000 --- a/tmux/plugins/tmux-ressurect/scripts/variables.sh +++ /dev/null @@ -1,47 +0,0 @@ -# key bindings -default_save_key="C-s" -save_option="@resurrect-save" -save_path_option="@resurrect-save-script-path" - -default_restore_key="C-r" -restore_option="@resurrect-restore" -restore_path_option="@resurrect-restore-script-path" - -# default processes that are restored -default_proc_list_option="@resurrect-default-processes" -default_proc_list='vi vim nvim emacs man less more tail top htop irssi weechat mutt' - -# User defined processes that are restored -# 'false' - nothing is restored -# ':all:' - all processes are restored -# -# user defined list of programs that are restored: -# 'my_program foo another_program' -restore_processes_option="@resurrect-processes" -restore_processes="" - -# Defines part of the user variable. Example usage: -# set -g @resurrect-strategy-vim "session" -restore_process_strategy_option="@resurrect-strategy-" - -inline_strategy_token="->" - -save_command_strategy_option="@resurrect-save-command-strategy" -default_save_command_strategy="ps" - -# Pane contents capture options. -# @resurrect-pane-contents-area option can be: -# 'visible' - capture only the visible pane area -# 'full' - capture the full pane contents -pane_contents_option="@resurrect-capture-pane-contents" -pane_contents_area_option="@resurrect-pane-contents-area" -default_pane_contents_area="full" - -bash_history_option="@resurrect-save-bash-history" # deprecated -shell_history_option="@resurrect-save-shell-history" - -# set to 'on' to ensure panes are never ever overwritten -overwrite_option="@resurrect-never-overwrite" - -# Hooks are set via ${hook_prefix}${name}, i.e. "@resurrect-hook-post-save-all" -hook_prefix="@resurrect-hook-" diff --git a/tmux/plugins/tmux-ressurect/strategies/irb_default_strategy.sh b/tmux/plugins/tmux-ressurect/strategies/irb_default_strategy.sh deleted file mode 100755 index 897f5bb..0000000 --- a/tmux/plugins/tmux-ressurect/strategies/irb_default_strategy.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -# "irb default strategy" -# -# Example irb process with junk variables: -# irb RBENV_VERSION=1.9.3-p429 GREP_COLOR=34;47 TERM_PROGRAM=Apple_Terminal -# -# When executed, the above will fail. This strategy handles that. - -ORIGINAL_COMMAND="$1" -DIRECTORY="$2" - -original_command_wo_junk_vars() { - echo "$ORIGINAL_COMMAND" | - sed 's/RBENV_VERSION[^ ]*//' | - sed 's/GREP_COLOR[^ ]*//' | - sed 's/TERM_PROGRAM[^ ]*//' -} - -main() { - echo "$(original_command_wo_junk_vars)" -} -main diff --git a/tmux/plugins/tmux-ressurect/strategies/mosh-client_default_strategy.sh b/tmux/plugins/tmux-ressurect/strategies/mosh-client_default_strategy.sh deleted file mode 100755 index 4d2f06b..0000000 --- a/tmux/plugins/tmux-ressurect/strategies/mosh-client_default_strategy.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -# "mosh-client default strategy" -# -# Example mosh-client process: -# mosh-client -# charm tmux at | 198.199.104.142 60001 -# -# When executed, the above will fail. This strategy handles that. - -ORIGINAL_COMMAND="$1" -DIRECTORY="$2" - -mosh_command() { - local args="$ORIGINAL_COMMAND" - - args="${args#*-#}" - args="${args%|*}" - - echo "mosh $args" -} - -main() { - echo "$(mosh_command)" -} -main diff --git a/tmux/plugins/tmux-ressurect/strategies/nvim_session.sh b/tmux/plugins/tmux-ressurect/strategies/nvim_session.sh deleted file mode 100755 index 4987c68..0000000 --- a/tmux/plugins/tmux-ressurect/strategies/nvim_session.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash - -# "nvim session strategy" -# -# Same as vim strategy, see file 'vim_session.sh' - -ORIGINAL_COMMAND="$1" -DIRECTORY="$2" - -nvim_session_file_exists() { - [ -e "${DIRECTORY}/Session.vim" ] -} - -original_command_contains_session_flag() { - [[ "$ORIGINAL_COMMAND" =~ "-S" ]] -} - -main() { - if nvim_session_file_exists; then - echo "nvim -S" - elif original_command_contains_session_flag; then - # Session file does not exist, yet the original nvim command contains - # session flag `-S`. This will cause an error, so we're falling back to - # starting plain nvim. - echo "nvim" - else - echo "$ORIGINAL_COMMAND" - fi -} -main diff --git a/tmux/plugins/tmux-ressurect/strategies/vim_session.sh b/tmux/plugins/tmux-ressurect/strategies/vim_session.sh deleted file mode 100755 index 8121344..0000000 --- a/tmux/plugins/tmux-ressurect/strategies/vim_session.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -# "vim session strategy" -# -# Restores a vim session from 'Session.vim' file, if it exists. -# If 'Session.vim' does not exist, it falls back to invoking the original -# command (without the `-S` flag). - -ORIGINAL_COMMAND="$1" -DIRECTORY="$2" - -vim_session_file_exists() { - [ -e "${DIRECTORY}/Session.vim" ] -} - -original_command_contains_session_flag() { - [[ "$ORIGINAL_COMMAND" =~ "-S" ]] -} - -main() { - if vim_session_file_exists; then - echo "vim -S" - elif original_command_contains_session_flag; then - # Session file does not exist, yet the original vim command contains - # session flag `-S`. This will cause an error, so we're falling back to - # starting plain vim. - echo "vim" - else - echo "$ORIGINAL_COMMAND" - fi -} -main diff --git a/tmux/plugins/tmux-sidebar/LICENSE.md b/tmux/plugins/tmux-sidebar/LICENSE.md deleted file mode 100644 index 40f6ddd..0000000 --- a/tmux/plugins/tmux-sidebar/LICENSE.md +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (C) 2014 Bruno Sutic - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE -OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tmux/plugins/tmux-sidebar/README.md b/tmux/plugins/tmux-sidebar/README.md deleted file mode 100644 index bfefb1a..0000000 --- a/tmux/plugins/tmux-sidebar/README.md +++ /dev/null @@ -1,74 +0,0 @@ -# Tmux Sidebar - -`tmux-sidebar` does one thing: it opens a tree directory listing for the current -path. It's fast, convenient and works great with vim. - -![screenshot](/screenshot.gif) - -Some of the features that make the plugin more appealing than doing the same -thing manually each time: - -- **fast**
- Much faster than doing each step manually. -- **smart sizing**
- Sidebar remembers its size, so the next time you open it, it will have the - **exact same** width. This is a per-directory property, so you can have just - the right size for multiple dirs. -- **toggling**
- The same key binding opens and closes the sidebar. -- **uninterrupted workflow**
- The main `prefix + Tab` key binding opens a sidebar but **does not** move - cursor to it. -- **pane layout stays the same**
- No matter which pane layout you prefer, sidebar tries hard not to mess your - pane splits. Open, then close the sidebar and everything should look the same. - -Requirements: `tmux 1.9` or higher, `tree` recommended but not required - -Tested and working on Linux, OSX and Cygwin. - -### Key bindings - -- `prefix + Tab` - toggle sidebar with a directory tree -- `prefix + Backspace` - toggle sidebar and move cursor to it (focus it) - -### Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (recommended) - -Add plugin to the list of TPM plugins in `.tmux.conf`: - - set -g @plugin 'tmux-plugins/tmux-sidebar' - -Hit `prefix + I` to fetch the plugin and source it. You should now be able to -use the plugin. - -### Manual Installation - -Clone the repo: - - $ git clone https://github.com/tmux-plugins/tmux-sidebar ~/clone/path - -Add this line to the bottom of `.tmux.conf`: - - run-shell ~/clone/path/sidebar.tmux - -Reload TMUX environment: - - # type this in terminal - $ tmux source-file ~/.tmux.conf - -You should now be able to use the plugin. - -### Docs - -- [customization options](docs/options.md) - -### Other goodies - -- [tmux-copycat](https://github.com/tmux-plugins/tmux-copycat) - a plugin for - regex searches in tmux and fast match selection -- [tmux-resurrect](https://github.com/tmux-plugins/tmux-resurrect) - restore - tmux environment after a system restart - -### License - -[MIT](LICENSE.md) diff --git a/tmux/plugins/tmux-sidebar/docs/options.md b/tmux/plugins/tmux-sidebar/docs/options.md deleted file mode 100644 index a05f57a..0000000 --- a/tmux/plugins/tmux-sidebar/docs/options.md +++ /dev/null @@ -1,41 +0,0 @@ -## Options - -Customize `tmux-sidebar` by placing options in `.tmux.conf` and reloading Tmux -environment. - -> How can I run some other command in the sidebar? - - set -g @sidebar-tree-command 'ls -1' - -> Can I have the sidebar on the right? - - set -g @sidebar-tree-position 'right' - -> I don't like the default 'prefix + Tab' key binding. Can I change it to be -'prefix + e'? - - set -g @sidebar-tree 'e' - -> How can I change the default 'prefix + Backspace' to be 'prefix + w'? - - set -g @sidebar-tree-focus 'w' - -> I see the tree sidebar uses 'less' as a pager. I would like to use 'view'. - - set -g @sidebar-tree-pager 'view -' - -> The default sidebar width is 40 columns. I want the sidebar to be wider by -default! - - set -g @sidebar-tree-width '60' - -> Can I colorize the ``tree`` directory listing in the sidebar? - - set -g @sidebar-tree-command 'tree -C' - -### Notes - -The command used to display the directory listing -(`@sidebar-tree-pager`, if set) must support color codes. If it does not, -unusual characters - the color control codes - will be visible in the sidebar. - diff --git a/tmux/plugins/tmux-sidebar/scripts/check_tmux_version.sh b/tmux/plugins/tmux-sidebar/scripts/check_tmux_version.sh deleted file mode 100755 index b0aedec..0000000 --- a/tmux/plugins/tmux-sidebar/scripts/check_tmux_version.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env bash - -VERSION="$1" -UNSUPPORTED_MSG="$2" - -get_tmux_option() { - local option=$1 - local default_value=$2 - local option_value=$(tmux show-option -gqv "$option") - if [ -z "$option_value" ]; then - echo "$default_value" - else - echo "$option_value" - fi -} - -# Ensures a message is displayed for 5 seconds in tmux prompt. -# Does not override the 'display-time' tmux option. -display_message() { - local message="$1" - - # display_duration defaults to 5 seconds, if not passed as an argument - if [ "$#" -eq 2 ]; then - local display_duration="$2" - else - local display_duration="5000" - fi - - # saves user-set 'display-time' option - local saved_display_time=$(get_tmux_option "display-time" "750") - - # sets message display time to 5 seconds - tmux set-option -gq display-time "$display_duration" - - # displays message - tmux display-message "$message" - - # restores original 'display-time' value - tmux set-option -gq display-time "$saved_display_time" -} - -# this is used to get "clean" integer version number. Examples: -# `tmux 1.9` => `19` -# `1.9a` => `19` -get_digits_from_string() { - local string="$1" - local only_digits="$(echo "$string" | tr -dC '[:digit:]')" - echo "$only_digits" -} - -tmux_version_int() { - local tmux_version_string=$(tmux -V) - echo "$(get_digits_from_string "$tmux_version_string")" -} - -unsupported_version_message() { - if [ -n "$UNSUPPORTED_MSG" ]; then - echo "$UNSUPPORTED_MSG" - else - echo "Error, Tmux version unsupported! Please install Tmux version $VERSION or greater!" - fi -} - -exit_if_unsupported_version() { - local current_version="$1" - local supported_version="$2" - if [ "$current_version" -lt "$supported_version" ]; then - display_message "$(unsupported_version_message)" - exit 1 - fi -} - -main() { - local supported_version_int="$(get_digits_from_string "$VERSION")" - local current_version_int="$(tmux_version_int)" - exit_if_unsupported_version "$current_version_int" "$supported_version_int" -} -main diff --git a/tmux/plugins/tmux-sidebar/scripts/custom_tree.sh b/tmux/plugins/tmux-sidebar/scripts/custom_tree.sh deleted file mode 100755 index 41fa246..0000000 --- a/tmux/plugins/tmux-sidebar/scripts/custom_tree.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -find . -path '*/.git*' -prune -o -print | - sed -e 's;[^/]*/;|___;g;s;___|; |;g' diff --git a/tmux/plugins/tmux-sidebar/scripts/helpers.sh b/tmux/plugins/tmux-sidebar/scripts/helpers.sh deleted file mode 100644 index 4593095..0000000 --- a/tmux/plugins/tmux-sidebar/scripts/helpers.sh +++ /dev/null @@ -1,101 +0,0 @@ -get_tmux_option() { - local option=$1 - local default_value=$2 - local option_value=$(tmux show-option -gqv "$option") - if [ -z "$option_value" ]; then - echo "$default_value" - else - echo "$option_value" - fi -} - -set_tmux_option() { - local option=$1 - local value=$2 - tmux set-option -gq "$option" "$value" -} - -# Ensures a message is displayed for 5 seconds in tmux prompt. -# Does not override the 'display-time' tmux option. -display_message() { - local message="$1" - - # display_duration defaults to 5 seconds, if not passed as an argument - if [ "$#" -eq 2 ]; then - local display_duration="$2" - else - local display_duration="5000" - fi - - # saves user-set 'display-time' option - local saved_display_time=$(get_tmux_option "display-time" "750") - - # sets message display time to 5 seconds - tmux set-option -gq display-time "$display_duration" - - # displays message - tmux display-message "$message" - - # restores original 'display-time' value - tmux set-option -gq display-time "$saved_display_time" -} - -stored_key_vars() { - tmux show-options -g | - \grep -i "^${VAR_KEY_PREFIX}-" | - cut -d ' ' -f1 | # cut just the variable names - xargs # splat var names in one line -} - -# get the key from the variable name -get_key_from_option_name() { - local option="$1" - echo "$option" | - sed "s/^${VAR_KEY_PREFIX}-//" -} - -get_value_from_option_name() { - local option="$1" - echo "$(get_tmux_option "$option" "")" -} - -get_pane_info() { - local pane_id="$1" - local format_strings="#{pane_id},$2" - tmux list-panes -t "$pane_id" -F "$format_strings" | - \grep "$pane_id" | - cut -d',' -f2- -} - -sidebar_dir() { - echo "$SIDEBAR_DIR" -} - -sidebar_file() { - echo "$(sidebar_dir)/directory_widths.txt" -} - -directory_in_sidebar_file() { - local pane_current_path="$1" - grep -q "^${pane_current_path}\t" $(sidebar_file) 2>/dev/null -} - -width_from_sidebar_file() { - local pane_current_path="$1" - grep "^${pane_current_path}\t" $(sidebar_file) | - cut -f2 -} - -# function is used to get "clean" integer version number. Examples: -# `tmux 1.9` => `19` -# `1.9a` => `19` -_get_digits_from_string() { - local string="$1" - local only_digits="$(echo "$string" | tr -dC '[:digit:]')" - echo "$only_digits" -} - -tmux_version_int() { - local tmux_version_string=$(tmux -V) - echo "$(_get_digits_from_string "$tmux_version_string")" -} diff --git a/tmux/plugins/tmux-sidebar/scripts/save_sidebar_width.sh b/tmux/plugins/tmux-sidebar/scripts/save_sidebar_width.sh deleted file mode 100755 index 51eaf87..0000000 --- a/tmux/plugins/tmux-sidebar/scripts/save_sidebar_width.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" -source "$CURRENT_DIR/variables.sh" - -DIR_PATH="$(echo "$1" | tail -1)" # fixes a bug with invalid param -WIDTH="$2" -delimiter=$'\t' - -replace_directory_width() { - sed "s|^${DIR_PATH}${delimiter}.*|${DIR_PATH}${delimiter}${WIDTH}|g" $(sidebar_file) > $(sidebar_file).bak - mv $(sidebar_file).bak $(sidebar_file) -} - -add_directory_width() { - mkdir -p "$(sidebar_dir)" - echo "${DIR_PATH}${delimiter}${WIDTH}" >> $(sidebar_file) -} - -save_sidebar_width() { - if directory_in_sidebar_file "$DIR_PATH"; then - replace_directory_width - else - add_directory_width - fi -} - -main() { - save_sidebar_width -} -main diff --git a/tmux/plugins/tmux-sidebar/scripts/toggle.sh b/tmux/plugins/tmux-sidebar/scripts/toggle.sh deleted file mode 100755 index 1c27b8a..0000000 --- a/tmux/plugins/tmux-sidebar/scripts/toggle.sh +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -source "$CURRENT_DIR/helpers.sh" -source "$CURRENT_DIR/variables.sh" - -# script global vars -ARGS="$1" # example args format: "tree | less,right,20,focus" -PANE_ID="$2" -COMMAND="$(echo "$ARGS" | cut -d',' -f1)" # "tree | less" -POSITION="$(echo "$ARGS" | cut -d',' -f2)" # "right" -SIZE="$(echo "$ARGS" | cut -d',' -f3)" # "20" -FOCUS="$(echo "$ARGS" | cut -d',' -f4)" # "focus" - -PANE_WIDTH="$(get_pane_info "$PANE_ID" "#{pane_width}")" -PANE_CURRENT_PATH="$(get_pane_info "$PANE_ID" "#{pane_current_path}")" - -supported_tmux_version_ok() { - $CURRENT_DIR/check_tmux_version.sh "$SUPPORTED_TMUX_VERSION" -} - -sidebar_registration() { - get_tmux_option "${REGISTERED_PANE_PREFIX}-${PANE_ID}" "" -} - -sidebar_pane_id() { - sidebar_registration | - cut -d',' -f1 -} - -sidebar_pane_args() { - echo "$(sidebar_registration)" | - cut -d',' -f2- -} - -register_sidebar() { - local sidebar_id="$1" - set_tmux_option "${REGISTERED_SIDEBAR_PREFIX}-${sidebar_id}" "$PANE_ID" - set_tmux_option "${REGISTERED_PANE_PREFIX}-${PANE_ID}" "${sidebar_id},${ARGS}" -} - -registration_not_for_the_same_command() { - local registered_args="$(sidebar_registration | cut -d',' -f2-)" - [[ $ARGS != $registered_args ]] -} - -sidebar_exists() { - local pane_id="$(sidebar_pane_id)" - tmux list-panes -F "#{pane_id}" 2>/dev/null | - \grep -q "^${pane_id}$" -} - -has_sidebar() { - if [ -n "$(sidebar_registration)" ] && sidebar_exists; then - return 0 - else - return 1 - fi -} - -current_pane_width_not_changed() { - if [ $PANE_WIDTH -eq $1 ]; then - return 0 - else - return 1 - fi -} - -kill_sidebar() { - # get data before killing the sidebar - local sidebar_pane_id="$(sidebar_pane_id)" - local sidebar_args="$(sidebar_pane_args)" - local sidebar_position="$(echo "$sidebar_args" | cut -d',' -f2)" # left or defults to right - local sidebar_width="$(get_pane_info "$sidebar_pane_id" "#{pane_width}")" - - $CURRENT_DIR/save_sidebar_width.sh "$PANE_CURRENT_PATH" "$sidebar_width" - - # kill the sidebar - tmux kill-pane -t "$sidebar_pane_id" - - # check current pane "expanded" properly - local new_current_pane_width="$(get_pane_info "$PANE_ID" "#{pane_width}")" - if current_pane_width_not_changed "$new_current_pane_width"; then - # need to expand current pane manually - local direction_flag - if [[ "$sidebar_position" =~ "left" ]]; then - direction_flag="-L" - else - direction_flag="-R" - fi - # compensate 1 column - tmux resize-pane "$direction_flag" "$((sidebar_width + 1))" - fi - PANE_WIDTH="$new_current_pane_width" -} - -sidebar_left() { - [[ $POSITION =~ "left" ]] -} - -no_focus() { - if [[ $FOCUS =~ (^focus) ]]; then - return 1 - else - return 0 - fi -} - -size_defined() { - [ -n $SIZE ] -} - -desired_sidebar_size() { - local half_pane="$((PANE_WIDTH / 2))" - if directory_in_sidebar_file "$PANE_CURRENT_PATH"; then - # use stored sidebar width for the directory - echo "$(width_from_sidebar_file "$PANE_CURRENT_PATH")" - elif size_defined && [ $SIZE -lt $half_pane ]; then - echo "$SIZE" - else - echo "$half_pane" - fi -} - -# tmux version 2.0 and below requires different argument for `join-pane` -use_inverted_size() { - [ tmux_version_int -le 20 ] -} - -split_sidebar_left() { - local sidebar_size=$(desired_sidebar_size) - if use_inverted_size; then - sidebar_size=$((PANE_WIDTH - $sidebar_size - 1)) - fi - local sidebar_id="$(tmux new-window -c "$PANE_CURRENT_PATH" -P -F "#{pane_id}" "$COMMAND")" - tmux join-pane -hb -l "$sidebar_size" -t "$PANE_ID" -s "$sidebar_id" - echo "$sidebar_id" -} - -split_sidebar_right() { - local sidebar_size=$(desired_sidebar_size) - tmux split-window -h -l "$sidebar_size" -c "$PANE_CURRENT_PATH" -P -F "#{pane_id}" "$COMMAND" -} - -create_sidebar() { - local position="$1" # left / right - local sidebar_id="$(split_sidebar_${position})" - register_sidebar "$sidebar_id" - if no_focus; then - tmux last-pane - fi -} - -current_pane_is_sidebar() { - local var="$(get_tmux_option "${REGISTERED_SIDEBAR_PREFIX}-${PANE_ID}" "")" - [ -n "$var" ] -} - -current_pane_too_narrow() { - [ $PANE_WIDTH -lt $MINIMUM_WIDTH_FOR_SIDEBAR ] -} - -execute_command_from_main_pane() { - # get pane_id for this sidebar - local main_pane_id="$(get_tmux_option "${REGISTERED_SIDEBAR_PREFIX}-${PANE_ID}" "")" - # execute the same command as if from the "main" pane - $CURRENT_DIR/toggle.sh "$ARGS" "$main_pane_id" -} - -exit_if_pane_too_narrow() { - if current_pane_too_narrow; then - display_message "Pane too narrow for the sidebar" - exit - fi -} - -toggle_sidebar() { - if has_sidebar; then - kill_sidebar - # if using different sidebar command automatically open a new sidebar - # if registration_not_for_the_same_command; then - # create_sidebar - # fi - else - exit_if_pane_too_narrow - if sidebar_left; then - create_sidebar "left" - else - create_sidebar "right" - fi - fi -} - -main() { - if supported_tmux_version_ok; then - if current_pane_is_sidebar; then - execute_command_from_main_pane - else - toggle_sidebar - fi - fi -} -main diff --git a/tmux/plugins/tmux-sidebar/scripts/tree_helpers.sh b/tmux/plugins/tmux-sidebar/scripts/tree_helpers.sh deleted file mode 100644 index 41e39d3..0000000 --- a/tmux/plugins/tmux-sidebar/scripts/tree_helpers.sh +++ /dev/null @@ -1,42 +0,0 @@ -# file sourced from ./sidebar.tmux -custom_tree_command="$CURRENT_DIR/scripts/custom_tree.sh" - -command_exists() { - local command="$1" - type "$command" >/dev/null 2>&1 -} - -tree_command() { - local user_command="$(tree_user_command)" - if [ -n "$user_command" ]; then - echo "$user_command" - elif command_exists "tree"; then - echo "$TREE_COMMAND" - else - echo "$custom_tree_command" - fi -} - -tree_user_command() { - get_tmux_option "$TREE_COMMAND_OPTION" "" -} - -tree_key() { - get_tmux_option "$TREE_OPTION" "$TREE_KEY" -} - -tree_focus_key() { - get_tmux_option "$TREE_FOCUS_OPTION" "$TREE_FOCUS_KEY" -} - -tree_pager() { - get_tmux_option "$TREE_PAGER_OPTION" "$TREE_PAGER" -} - -tree_position() { - get_tmux_option "$TREE_POSITION_OPTION" "$TREE_POSITION" -} - -tree_width() { - get_tmux_option "$TREE_WIDTH_OPTION" "$TREE_WIDTH" -} diff --git a/tmux/plugins/tmux-sidebar/scripts/variables.sh b/tmux/plugins/tmux-sidebar/scripts/variables.sh deleted file mode 100644 index 9d7c3fc..0000000 --- a/tmux/plugins/tmux-sidebar/scripts/variables.sh +++ /dev/null @@ -1,26 +0,0 @@ -VAR_KEY_PREFIX="@sidebar-key" -REGISTERED_PANE_PREFIX="@-sidebar-registered-pane" -REGISTERED_SIDEBAR_PREFIX="@-sidebar-is-sidebar" -MINIMUM_WIDTH_FOR_SIDEBAR="71" - -TREE_KEY="Tab" -TREE_OPTION="@sidebar-tree" - -TREE_FOCUS_KEY="Bspace" -TREE_FOCUS_OPTION="@sidebar-tree-focus" - -TREE_COMMAND="tree" -TREE_COMMAND_OPTION="@sidebar-tree-command" - -TREE_PAGER='sh -c "LESS= less --dumb --chop-long-lines --tilde --IGNORE-CASE --RAW-CONTROL-CHARS"' -TREE_PAGER_OPTION="@sidebar-tree-pager" - -TREE_POSITION="left" -TREE_POSITION_OPTION="@sidebar-tree-position" - -TREE_WIDTH="40" -TREE_WIDTH_OPTION="@sidebar-tree-width" - -SUPPORTED_TMUX_VERSION="1.9" - -SIDEBAR_DIR="$HOME/.tmux/sidebar" diff --git a/tmux/plugins/tmux-sidebar/sidebar.tmux b/tmux/plugins/tmux-sidebar/sidebar.tmux deleted file mode 100755 index 61b973d..0000000 --- a/tmux/plugins/tmux-sidebar/sidebar.tmux +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -SCRIPTS_DIR="$CURRENT_DIR/scripts" - -source "$SCRIPTS_DIR/helpers.sh" -source "$SCRIPTS_DIR/variables.sh" -source "$SCRIPTS_DIR/tree_helpers.sh" - -set_default_key_binding_options() { - local tree_command="$(tree_command)" - local tree_key="$(tree_key)" - local tree_focus_key="$(tree_focus_key)" - local tree_pager="$(tree_pager)" - local tree_position="$(tree_position)" - local tree_width="$(tree_width)" - - set_tmux_option "${VAR_KEY_PREFIX}-${tree_key}" "$tree_command | ${tree_pager},${tree_position},${tree_width}" - set_tmux_option "${VAR_KEY_PREFIX}-${tree_focus_key}" "$tree_command | ${tree_pager},${tree_position},${tree_width},focus" -} - -set_key_bindings() { - local stored_key_vars="$(stored_key_vars)" - local search_var - local key - local pattern - for option in $stored_key_vars; do - key="$(get_key_from_option_name "$option")" - value="$(get_value_from_option_name "$option")" - tmux bind-key "$key" run-shell "$SCRIPTS_DIR/toggle.sh '$value' '#{pane_id}'" - done -} - -main() { - set_default_key_binding_options - set_key_bindings -} -main diff --git a/tmux/plugins/tmux-yank/LICENSE.md b/tmux/plugins/tmux-yank/LICENSE.md deleted file mode 100644 index a898835..0000000 --- a/tmux/plugins/tmux-yank/LICENSE.md +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (C) 2014, 2017 Bruno Sutic -Copyright (C) 2017 Christian Höltje - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE -OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tmux/plugins/tmux-yank/README.md b/tmux/plugins/tmux-yank/README.md deleted file mode 100644 index b6d8916..0000000 --- a/tmux/plugins/tmux-yank/README.md +++ /dev/null @@ -1,288 +0,0 @@ -[![Build -Status](https://travis-ci.org/tmux-plugins/tmux-yank.svg?branch=master)](https://travis-ci.org/tmux-plugins/tmux-yank) -[![GitHub -release](https://img.shields.io/github/release/tmux-plugins/tmux-yank.svg)](https://github.com/tmux-plugins/tmux-yank/releases) -[![GitHub -issues](https://img.shields.io/github/issues/tmux-plugins/tmux-yank.svg)](https://github.com/tmux-plugins/tmux-yank/issues) - -tmux-yank -========= - -Copy to the system clipboard in [`tmux`](https://tmux.github.io/). - -Supports: - -- Linux -- macOS -- Cygwin -- Windows Subsystem for Linux (WSL) - -Installing ----------- - -### Via TPM (recommended) - -The easiest way to install `tmux-yank` is via the [Tmux Plugin -Manager](https://github.com/tmux-plugins/tpm). - -1. Add plugin to the list of TPM plugins in `.tmux.conf`: - - ``` tmux - set -g @plugin 'tmux-plugins/tmux-yank' - ``` - -2. Use prefixI install `tmux-yank`. You should now - be able to `tmux-yank` immediately. -3. When you want to update `tmux-yank` use prefixU. - -### Manual Installation - -1. Clone the repository - - ``` sh - $ git clone https://github.com/tmux-plugins/tmux-yank ~/clone/path - ``` - -2. Add this line to the bottom of `.tmux.conf` - - ``` tmux - run-shell ~/clone/path/yank.tmux - ``` - -3. Reload the `tmux` environment - - ``` sh - # type this inside tmux - $ tmux source-file ~/.tmux.conf - ``` - -You should now be able to use `tmux-yank` immediately. - -Requirements ------------- - -In order for `tmux-yank` to work, there must be a program that store data in -the system clipboard. - -### macOS - -- [`reattach-to-user-namespace`](https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard) - -**Note**: Some versions of macOS (aka OS X) have been reported to work -without `reattach-to-user-namespace`. It doesn't hurt to have it installed. - -- OS X 10.8: Mountain Lion – *required* -- OS X 10.9: Mavericks – *required* -- OS X 10.10: Yosemite – *not required* -- OS X 10.11: El Capitan – *not required* -- macOS 10.12: Sierra – *required* - -The easiest way to use `reattach-to-user-namespace` with `tmux` is use to -use the [`tmux-sensible`](https://github.com/tmux-plugins/tmux-sensible) -plugin. - -To use it manually, use: - -``` tmux -# ~/.tmux.conf -set-option -g default-command "reattach-to-user-namespace -l $SHELL" -``` - -If you have `tmux` 1.5 or newer and are using -[iTerm2](https://www.iterm2.com/) version 3 or newer then the y -in `copy-mode` and mouse selection will work without `tmux-yank`. - -To enable this: - -1. Go into iTerm2's preferences. -2. Go to the "General" tab. -3. Check "Applications in terminal may access clipboard" -4. In `tmux`, ensure `set-clipboard` is turned on: - - ``` sh - $ tmux show-options -g -s set-clipboard - set-clipboard on - ``` - -#### [HomeBrew](https://brew.sh/) (recommended) - -``` sh -$ brew install reattach-to-user-namespace -``` - -#### MacPorts - -``` sh -$ sudo port install tmux-pasteboard -``` - -### Linux - -- `xsel` (recommended) or `xclip` (for X). -- `wl-copy` from [wl-clipboard](https://github.com/bugaevc/wl-clipboard) (for Wayland) - -If you have `tmux` 1.5 or newer and are using `xterm`, the y in -`copy-mode` and mouse selection will work without `tmux-yank`. See the -`tmux(1)` man page entry for the `set-clipboard` option. - -#### Debian & Ubuntu - -``` sh -$ sudo apt-get install xsel # or xclip -``` - -#### RedHat & CentOS - -``` sh -$ sudo yum install xsel # or xclip -``` - -### Cygwin - -- (*optional*) `putclip` which is part of the `cygutils-extra` package. - -### Windows Subsystem for Linux (WSL) - -- `clip.exe` is shipped with Windows Subsystem for Linux. - -Configuration -------------- - -### Key bindings - -- Normal Mode - - prefixy — copies text from the command line - to the clipboard. - - Works with all popular shells/repls. Tested with: - - - shells: `bash`, `zsh` (with `bindkey -e`), `tcsh` - - repls: `irb`, `pry`, `node`, `psql`, `python`, `php -a`, - `coffee` - - remote shells: `ssh`, [mosh](http://mosh.mit.edu/) - - vim/neovim command line (requires - [vim-husk](https://github.com/bruno-/vim-husk) or - [vim-rsi](https://github.com/tpope/vim-rsi) plugin) - - - prefixY — copy the current pane's current - working directory to the clipboard. - -- Copy Mode - - y — copy selection to system clipboard. - - Y (shift-y) — "put" selection. Equivalent to copying a - selection, and pasting it to the command line. - - -### Default and Preferred Clipboard Programs - -tmux-yank does its best to detect a reasonable choice for a clipboard -program on your OS. - -If tmux-yank can't detect a known clipboard program then it uses the -`@custom_copy_command` tmux option as your clipboard program if set. - -If you need to always override tmux-yank's choice for a clipboard program, -then you can set `@override_copy_command` to force tmux-yank to use whatever -you want. - -Note that both programs _must_ accept `STDIN` for the text to be copied. - -An example of setting `@override_copy_command`: - -``` tmux -# ~/.tmux.conf - -set -g @custom_copy_command 'my-clipboard-copy --some-arg' -# or -set -g @override_copy_command 'my-clipboard-copy --some-arg' -``` - -### Linux Clipboards - -Linux has several cut-and-paste clipboards: `primary`, `secondary`, and -`clipboard` (default in tmux-yank is `clipboard`). - -You can change this by setting `@yank_selection`: - -``` tmux -# ~/.tmux.conf - -set -g @yank_selection 'primary' # or 'secondary' or 'clipboard' -``` - -With mouse support turned on (see below) the default clipboard for mouse -selections is `primary`. - -You can change this by setting `@yank_selection_mouse`: - -``` tmux -# ~/.tmux.conf - -set -g @yank_selection_mouse 'clipboard' # or 'primary' or 'secondary' -``` - -### Controlling Yank Behavior - -By default, `tmux-yank` will exit copy mode after yanking text. If you wish to -remain in copy mode, you can set `@yank_action`: - -``` tmux -# ~/.tmux.conf - -set -g @yank_action 'copy-pipe' # or 'copy-pipe-and-cancel' for the default -``` - -### Mouse Support - -`tmux-yank` has mouse support enabled by default. It will only work if `tmux`'s -built-in mouse support is also enabled (with `mouse on` since `tmux` 2.1, or -`mode-mouse on` in older versions). - -To yank with the mouse, click and drag with the primary button to begin -selection, and release to yank. - -If you would prefer to disable this behavior, or provide your own bindings for -the `MouseDragEnd1Pane` event, you can do so with: - -``` tmux -# ~/.tmux.conf - -set -g @yank_with_mouse off # or 'on' -``` - -If you want to remain in copy mode after making a mouse selection, set -`@yank_action` as described above. - -### vi mode support - -If using `tmux` 2.3 or older *and* using vi keys then you'll have add the -following configuration setting: - -``` tmux -# ~/.tmux.conf - -set -g @shell_mode 'vi' -``` - -This isn't needed with `tmux` 2.4 or newer. - -### Screen-cast - -[![screencast -screenshot](/video/screencast_img.png)](https://vimeo.com/102039099) - -**Note**: The screen-cast uses Controly for -"put selection". Use Y in `v2.0.0` and later. - -### Other tmux plugins - -- [tmux-copycat](https://github.com/tmux-plugins/tmux-copycat) - a plugin - for regular expression searches in tmux and fast match selection -- [tmux-open](https://github.com/tmux-plugins/tmux-open) - a plugin for - quickly opening highlighted file or a URL -- [tmux-continuum](https://github.com/tmux-plugins/tmux-continuum) - - automatic restoring and continuous saving of tmux environment. - -### License - -[MIT](LICENSE.md) diff --git a/tmux/plugins/tmux-yank/scripts/copy_line.sh b/tmux/plugins/tmux-yank/scripts/copy_line.sh deleted file mode 100755 index 20a70e1..0000000 --- a/tmux/plugins/tmux-yank/scripts/copy_line.sh +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -HELPERS_DIR="$CURRENT_DIR" -TMUX_COPY_MODE="" - -REMOTE_SHELL_WAIT_TIME="0.4" - -# shellcheck source=scripts/helpers.sh -source "${HELPERS_DIR}/helpers.sh" - -# sets a TMUX_COPY_MODE that is used as a global variable -get_tmux_copy_mode() { - TMUX_COPY_MODE="$(tmux show-option -gwv mode-keys)" -} - -# The command when on ssh with latency. To make it work in this case too, -# sleep is added. -add_sleep_for_remote_shells() { - local pane_command - pane_command="$(tmux display-message -p '#{pane_current_command}')" - if [[ $pane_command =~ (ssh|mosh) ]]; then - sleep "$REMOTE_SHELL_WAIT_TIME" - fi -} - -go_to_the_beginning_of_current_line() { - if [ "$(shell_mode)" == "emacs" ]; then - tmux send-key 'C-a' - else - tmux send-key 'Escape' '0' - fi -} - -enter_tmux_copy_mode() { - tmux copy-mode -} - -start_tmux_selection() { - if tmux_is_at_least 2.4; then - tmux send -X begin-selection - elif [ "$TMUX_COPY_MODE" == "vi" ]; then - # vi copy mode - tmux send-key 'Space' - else - # emacs copy mode - tmux send-key 'C-Space' - fi -} - -# works when command spans accross multiple lines -end_of_line_in_copy_mode() { - if tmux_is_at_least 2.4; then - tmux send -X -N 150 'cursor-down' # 'down' key. 'vi' mode is faster so we're - # jumping more lines than emacs. - tmux send -X 'end-of-line' # End of line (just in case we are already at the last line). - tmux send -X 'previous-word' # Beginning of the previous word. - tmux send -X 'next-word-end' # End of next word. - elif [ "$TMUX_COPY_MODE" == "vi" ]; then - # vi copy mode - # This sequence of keys consistently selects multiple lines - tmux send-key '150' # Go to the bottom of scrollback buffer by using - tmux send-key 'j' # 'down' key. 'vi' mode is faster so we're - # jumping more lines than emacs. - tmux send-key '$' # End of line (just in case we are already at the last line). - tmux send-key 'b' # Beginning of the previous word. - tmux send-key 'e' # End of next word. - else - # emacs copy mode - for ((c = 1; c <= '30'; c++)); do # go to the bottom of scrollback buffer - tmux send-key 'C-n' - done - tmux send-key 'C-e' - tmux send-key 'M-b' - tmux send-key 'M-f' - fi -} - -yank_to_clipboard() { - if tmux_is_at_least 2.4; then - # shellcheck disable=SC2119 - tmux send -X copy-pipe-and-cancel "$(clipboard_copy_command)" - else - tmux send-key "$(yank_wo_newline_key)" - fi -} - -go_to_the_end_of_current_line() { - if [ "$(shell_mode)" == "emacs" ]; then - tmux send-keys 'C-e' - else - tmux send-keys '$' 'a' - fi -} - -yank_current_line() { - go_to_the_beginning_of_current_line - add_sleep_for_remote_shells - enter_tmux_copy_mode - start_tmux_selection - end_of_line_in_copy_mode - yank_to_clipboard - go_to_the_end_of_current_line - display_message 'Line copied to clipboard!' -} - -main() { - get_tmux_copy_mode - yank_current_line -} -main diff --git a/tmux/plugins/tmux-yank/scripts/copy_pane_pwd.sh b/tmux/plugins/tmux-yank/scripts/copy_pane_pwd.sh deleted file mode 100755 index 1db321f..0000000 --- a/tmux/plugins/tmux-yank/scripts/copy_pane_pwd.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -HELPERS_DIR="$CURRENT_DIR" - -# shellcheck source=scripts/helpers.sh -source "${HELPERS_DIR}/helpers.sh" - -pane_current_path() { - tmux display -p -F "#{pane_current_path}" -} - -display_notice() { - display_message 'PWD copied to clipboard!' -} - -main() { - local copy_command - local payload - # shellcheck disable=SC2119 - copy_command="$(clipboard_copy_command)" - payload="$(pane_current_path | tr -d '\n')" - # $copy_command below should not be quoted - echo "$payload" | $copy_command - tmux set-buffer "$payload" - display_notice -} -main diff --git a/tmux/plugins/tmux-yank/scripts/helpers.sh b/tmux/plugins/tmux-yank/scripts/helpers.sh deleted file mode 100644 index 66beeec..0000000 --- a/tmux/plugins/tmux-yank/scripts/helpers.sh +++ /dev/null @@ -1,208 +0,0 @@ -#!bash -# shellcheck disable=SC2239 - -yank_line="y" -yank_line_option="@yank_line" - -yank_pane_pwd="Y" -yank_pane_pwd_option="@yank_pane_pwd" - -yank_default="y" -yank_option="@copy_mode_yank" - -put_default="Y" -put_option="@copy_mode_put" - -yank_put_default="M-y" -yank_put_option="@copy_mode_yank_put" - -yank_wo_newline_default="!" -yank_wo_newline_option="@copy_mode_yank_wo_newline" - -yank_selection_default="clipboard" -yank_selection_option="@yank_selection" - -yank_selection_mouse_default="primary" -yank_selection_mouse_option="@yank_selection_mouse" - -yank_with_mouse_default="on" -yank_with_mouse_option="@yank_with_mouse" - -yank_action_default="copy-pipe-and-cancel" -yank_action_option="@yank_action" - -shell_mode_default="emacs" -shell_mode_option="@shell_mode" - -custom_copy_command_default="" -custom_copy_command_option="@custom_copy_command" - -override_copy_command_default="" -override_copy_command_option="@override_copy_command" - -# helper functions -get_tmux_option() { - local option="$1" - local default_value="$2" - local option_value - option_value=$(tmux show-option -gqv "$option") - if [ -z "$option_value" ]; then - echo "$default_value" - else - echo "$option_value" - fi -} - -yank_line_key() { - get_tmux_option "$yank_line_option" "$yank_line" -} - -yank_pane_pwd_key() { - get_tmux_option "$yank_pane_pwd_option" "$yank_pane_pwd" -} - -yank_key() { - get_tmux_option "$yank_option" "$yank_default" -} - -put_key() { - get_tmux_option "$put_option" "$put_default" -} - -yank_put_key() { - get_tmux_option "$yank_put_option" "$yank_put_default" -} - -yank_wo_newline_key() { - get_tmux_option "$yank_wo_newline_option" "$yank_wo_newline_default" -} - -yank_selection() { - get_tmux_option "$yank_selection_option" "$yank_selection_default" -} - -yank_selection_mouse() { - get_tmux_option "$yank_selection_mouse_option" "$yank_selection_mouse_default" -} - -yank_with_mouse() { - get_tmux_option "$yank_with_mouse_option" "$yank_with_mouse_default" -} - -yank_action() { - get_tmux_option "$yank_action_option" "$yank_action_default" -} - -shell_mode() { - get_tmux_option "$shell_mode_option" "$shell_mode_default" -} - -custom_copy_command() { - get_tmux_option "$custom_copy_command_option" "$custom_copy_command_default" -} - -override_copy_command() { - get_tmux_option "$override_copy_command_option" "$override_copy_command_default" -} -# Ensures a message is displayed for 5 seconds in tmux prompt. -# Does not override the 'display-time' tmux option. -display_message() { - local message="$1" - - # display_duration defaults to 5 seconds, if not passed as an argument - if [ "$#" -eq 2 ]; then - local display_duration="$2" - else - local display_duration="5000" - fi - - # saves user-set 'display-time' option - local saved_display_time - saved_display_time=$(get_tmux_option "display-time" "750") - - # sets message display time to 5 seconds - tmux set-option -gq display-time "$display_duration" - - # displays message - tmux display-message "$message" - - # restores original 'display-time' value - tmux set-option -gq display-time "$saved_display_time" -} - -command_exists() { - local command="$1" - type "$command" >/dev/null 2>&1 -} - -clipboard_copy_command() { - local mouse="${1:-false}" - # installing reattach-to-user-namespace is recommended on OS X - if [ -n "$(override_copy_command)" ]; then - override_copy_command - elif command_exists "pbcopy"; then - if command_exists "reattach-to-user-namespace"; then - echo "reattach-to-user-namespace pbcopy" - else - echo "pbcopy" - fi - elif command_exists "clip.exe"; then # WSL clipboard command - echo "cat | clip.exe" - elif command_exists "wl-copy"; then # wl-clipboard: Wayland clipboard utilities - echo "wl-copy" - elif command_exists "xsel"; then - local xsel_selection - if [[ $mouse == "true" ]]; then - xsel_selection="$(yank_selection_mouse)" - else - xsel_selection="$(yank_selection)" - fi - echo "xsel -i --$xsel_selection" - elif command_exists "xclip"; then - local xclip_selection - if [[ $mouse == "true" ]]; then - xclip_selection="$(yank_selection_mouse)" - else - xclip_selection="$(yank_selection)" - fi - echo "xclip -selection $xclip_selection" - elif command_exists "putclip"; then # cygwin clipboard command - echo "putclip" - elif [ -n "$(custom_copy_command)" ]; then - custom_copy_command - fi -} - -# Cache the TMUX version for speed. -tmux_version="$(tmux -V | cut -d ' ' -f 2 | sed 's/next-//')" - -tmux_is_at_least() { - if [[ $tmux_version == "$1" ]] || [[ $tmux_version == master ]]; then - return 0 - fi - - local i - local -a current_version wanted_version - IFS='.' read -ra current_version <<<"$tmux_version" - IFS='.' read -ra wanted_version <<<"$1" - - # fill empty fields in current_version with zeros - for ((i = ${#current_version[@]}; i < ${#wanted_version[@]}; i++)); do - current_version[i]=0 - done - - # fill empty fields in wanted_version with zeros - for ((i = ${#wanted_version[@]}; i < ${#current_version[@]}; i++)); do - wanted_version[i]=0 - done - - for ((i = 0; i < ${#current_version[@]}; i++)); do - if ((10#${current_version[i]} < 10#${wanted_version[i]})); then - return 1 - fi - if ((10#${current_version[i]} > 10#${wanted_version[i]})); then - return 0 - fi - done - return 0 -} diff --git a/tmux/plugins/tmux-yank/yank.tmux b/tmux/plugins/tmux-yank/yank.tmux deleted file mode 100755 index 3ca43c5..0000000 --- a/tmux/plugins/tmux-yank/yank.tmux +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env bash - -CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -SCRIPTS_DIR="${CURRENT_DIR}/scripts" -HELPERS_DIR="${CURRENT_DIR}/scripts" - -# shellcheck source=scripts/helpers.sh -source "${HELPERS_DIR}/helpers.sh" - -clipboard_copy_without_newline_command() { - local copy_command="$1" - printf "tr -d '\\n' | %s" "$copy_command" -} - -set_error_bindings() { - local key_bindings key - key_bindings="$(yank_key) $(put_key) $(yank_put_key)" - for key in $key_bindings; do - if tmux_is_at_least 2.4; then - tmux bind-key -T copy-mode-vi "$key" send-keys -X copy-pipe-and-cancel "tmux display-message 'Error! tmux-yank dependencies not installed!'" - tmux bind-key -T copy-mode "$key" send-keys -X copy-pipe-and-cancel "tmux display-message 'Error! tmux-yank dependencies not installed!'" - else - tmux bind-key -t vi-copy "$key" copy-pipe "tmux display-message 'Error! tmux-yank dependencies not installed!'" - tmux bind-key -t emacs-copy "$key" copy-pipe "tmux display-message 'Error! tmux-yank dependencies not installed!'" - fi - done -} - -error_handling_if_command_not_present() { - local copy_command="$1" - if [ -z "$copy_command" ]; then - set_error_bindings - exit 0 - fi -} - -# `yank_without_newline` binding isn't intended to be used by the user. It is -# a helper for `copy_line` command. -set_copy_mode_bindings() { - local copy_command="$1" - local copy_wo_newline_command - copy_wo_newline_command="$(clipboard_copy_without_newline_command "$copy_command")" - local copy_command_mouse - copy_command_mouse="$(clipboard_copy_command "true")" - if tmux_is_at_least 2.4; then - tmux bind-key -T copy-mode-vi "$(yank_key)" send-keys -X "$(yank_action)" "$copy_command" - tmux bind-key -T copy-mode-vi "$(put_key)" send-keys -X copy-pipe-and-cancel "tmux paste-buffer" - tmux bind-key -T copy-mode-vi "$(yank_put_key)" send-keys -X copy-pipe-and-cancel "$copy_command; tmux paste-buffer" - tmux bind-key -T copy-mode-vi "$(yank_wo_newline_key)" send-keys -X "$(yank_action)" "$copy_wo_newline_command" - if [[ "$(yank_with_mouse)" == "on" ]]; then - tmux bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X "$(yank_action)" "$copy_command_mouse" - fi - - tmux bind-key -T copy-mode "$(yank_key)" send-keys -X "$(yank_action)" "$copy_command" - tmux bind-key -T copy-mode "$(put_key)" send-keys -X copy-pipe-and-cancel "tmux paste-buffer" - tmux bind-key -T copy-mode "$(yank_put_key)" send-keys -X copy-pipe-and-cancel "$copy_command; tmux paste-buffer" - tmux bind-key -T copy-mode "$(yank_wo_newline_key)" send-keys -X "$(yank_action)" "$copy_wo_newline_command" - if [[ "$(yank_with_mouse)" == "on" ]]; then - tmux bind-key -T copy-mode MouseDragEnd1Pane send-keys -X "$(yank_action)" "$copy_command_mouse" - fi - else - tmux bind-key -t vi-copy "$(yank_key)" copy-pipe "$copy_command" - tmux bind-key -t vi-copy "$(put_key)" copy-pipe "tmux paste-buffer" - tmux bind-key -t vi-copy "$(yank_put_key)" copy-pipe "$copy_command; tmux paste-buffer" - tmux bind-key -t vi-copy "$(yank_wo_newline_key)" copy-pipe "$copy_wo_newline_command" - if [[ "$(yank_with_mouse)" == "on" ]]; then - tmux bind-key -t vi-copy MouseDragEnd1Pane copy-pipe "$copy_command_mouse" - fi - - tmux bind-key -t emacs-copy "$(yank_key)" copy-pipe "$copy_command" - tmux bind-key -t emacs-copy "$(put_key)" copy-pipe "tmux paste-buffer" - tmux bind-key -t emacs-copy "$(yank_put_key)" copy-pipe "$copy_command; tmux paste-buffer" - tmux bind-key -t emacs-copy "$(yank_wo_newline_key)" copy-pipe "$copy_wo_newline_command" - if [[ "$(yank_with_mouse)" == "on" ]]; then - tmux bind-key -t emacs-copy MouseDragEnd1Pane copy-pipe "$copy_command_mouse" - fi - fi -} - -set_normal_bindings() { - tmux bind-key "$(yank_line_key)" run-shell -b "$SCRIPTS_DIR/copy_line.sh" - tmux bind-key "$(yank_pane_pwd_key)" run-shell -b "$SCRIPTS_DIR/copy_pane_pwd.sh" -} - -main() { - local copy_command - copy_command="$(clipboard_copy_command)" - error_handling_if_command_not_present "$copy_command" - set_copy_mode_bindings "$copy_command" - set_normal_bindings -} -main diff --git a/tmux/tmux.conf b/tmux/tmux.conf index aa1b106..d8ffa80 100644 --- a/tmux/tmux.conf +++ b/tmux/tmux.conf @@ -17,7 +17,7 @@ setw -g aggressive-resize on unbind C-b set -g prefix C-a -# Set parent terminal title to reflect current window in tmux session +# Set parent terminal title to reflect current window in tmux session set -g set-titles on set -g set-titles-string "#I:#W" @@ -28,6 +28,7 @@ setw -g pane-base-index 1 # Enable mouse support set -g mouse on + # ========================== # === Key bindings === # ========================== @@ -37,10 +38,10 @@ unbind "\$" # rename-session unbind , # rename-window unbind % # split-window -h unbind '"' # split-window -unbind '}' # swap-pane -D -unbind '{' # swap-pane -U +unbind '}' # swap-pane -D +unbind '{' # swap-pane -U unbind [ # paste-buffer -unbind ] +unbind ] unbind "'" # select-window unbind n # next-window unbind p # previous-window @@ -49,17 +50,19 @@ unbind M-n # next window with alert unbind M-p # next window with alert unbind o # focus thru panes unbind & # kill-window -unbind "#" # list-buffer +unbind "#" # list-buffer unbind = # choose-buffer +unbind z # zoom-pane unbind M-Up # resize 5 rows up unbind M-Down # resize 5 rows down unbind M-Right # resize 5 rows right unbind M-Left # resize 5 rows left + # Edit configuration and reload bind C-e new-window -n 'tmux.conf' "sh -c '\${EDITOR:-vim} ~/.tmux.conf && tmux source ~/.tmux.conf && tmux display \"Config reloaded\"'" -# Reload tmux configuration +# Reload tmux configuration bind C-w source-file ~/.tmux.conf \; display "Config reloaded" # New window and retain cwd @@ -84,6 +87,9 @@ bind -r ] select-pane -t :.+ bind -r Tab last-window # cycle thru MRU tabs bind -r C-o swap-pane -D +# Zoom pane +bind + resize-pane -Z + # Link window bind L command-prompt -p "Link window from (session:window): " "link-window -s %% -a" @@ -305,6 +311,18 @@ bind '$' run "~/.dots/tmux/utils/renew_env.sh" # === Plugins === # ============================ +set -g @plugin 'tmux-plugins/tpm' +set -g @plugin 'tmux-plugins/tmux-battery' +set -g @plugin 'tmux-plugins/tmux-prefix-highlight' +set -g @plugin 'tmux-plugins/tmux-online-status' +set -g @plugin 'tmux-plugins/tmux-sidebar' +set -g @plugin 'tmux-plugins/tmux-copycat' +set -g @plugin 'tmux-plugins/tmux-open' +set -g @plugin 'samoshkin/tmux-plugin-sysstat' +set -g @plugin 'tmux-plugins/tmux-yank' +set -g @plugin 'tmux-plugins/tmux-ressurect' +set -g @plugin 'tmux-plugins/tmux-continuum' + # Plugin properties set -g @sidebar-tree 't' set -g @sidebar-tree-focus 'T' @@ -314,10 +332,6 @@ set -g @continuum-restore 'on' set -g @open-S 'https://www.google.com/search?q=' -# tmux-yank -#set -g @custom_copy_command 'xsel' # xclip or something else -#set -g @yank_action 'copy-pipe' # or 'copy-pipe-and-cancel' for the default - # ============================================== # === Nesting local and remote sessions === # ============================================== @@ -341,7 +355,7 @@ bind -T root F12 \ if -F '#{pane_in_mode}' 'send-keys -X cancel' \;\ refresh-client -S \;\ -bind -T off F12 \ +bind -T off F12\ set -u prefix \;\ set -u key-table \;\ set -u status-style \;\ @@ -349,16 +363,22 @@ bind -T off F12 \ set -u window-status-current-format \;\ refresh-client -S -# Run all plugins' scripts -run '~/.dots/tmux/plugins/tmux-battery/battery.tmux' -run '~/.dots/tmux/plugins/tmux-online-status/online_status.tmux' -run '~/.dots/tmux/plugins/tmux-plugin-sysstat/sysstat.tmux' -run '~/.dots/tmux/plugins/tmux-prefix-highlight/prefix_highlight.tmux' -run '~/.dots/tmux/plugins/tmux-copycat/copycat.tmux' -run '~/.dots/tmux/plugins/tmux-open/open.tmux' -run '~/.dots/tmux/plugins/tmux-sidebar/sidebar.tmux' -run '~/.dots/tmux/plugins/tmux-yank/yank.tmux' +bind -T root C-q \ + set prefix None \;\ + set key-table off \;\ + set status-style "fg=$color_status_text,bg=$color_window_off_status_bg" \;\ + set window-status-current-format "#[fg=$color_window_off_status_bg,bg=$color_window_off_status_current_bg]$separator_powerline_right#[default] #I:#W# #[fg=$color_window_off_status_current_bg,bg=$color_window_off_status_bg]$separator_powerline_right#[default]" \;\ + set window-status-current-style "fg=$color_dark,bold,bg=$color_window_off_status_current_bg" \;\ + if -F '#{pane_in_mode}' 'send-keys -X cancel' \;\ + refresh-client -S \;\ -run '~/.dots/tmux/plugins/tmux-ressurect/resurrect.tmux' -run '~/.dots/tmux/plugins/tmux-continuum/continuum.tmux' +bind -T off C-q \ + set -u prefix \;\ + set -u key-table \;\ + set -u status-style \;\ + set -u window-status-current-style \;\ + set -u window-status-current-format \;\ + refresh-client -S +# Initialize TPM (must be last) +run '~/.tmux/plugins/tpm/tpm' diff --git a/zsh/.devcontainer/devcontainer.json b/zsh/.devcontainer/devcontainer.json new file mode 100644 index 0000000..d3ad1a3 --- /dev/null +++ b/zsh/.devcontainer/devcontainer.json @@ -0,0 +1,20 @@ +{ + "image": "mcr.microsoft.com/devcontainers/base:noble", + "features": { + "ghcr.io/devcontainers/features/common-utils": { + "installZsh": true, + "configureZshAsDefaultShell": true, + "username": "vscode", + "userUid": 1000, + "userGid": 1000 + } + }, + "postCreateCommand": "dir=/workspaces/ohmyzsh; rm -rf $HOME/.oh-my-zsh && ln -s $dir $HOME/.oh-my-zsh && cp $dir/templates/minimal.zshrc $HOME/.zshrc && chgrp -R 1000 $dir && chmod g-w,o-w $dir", + "customizations": { + "codespaces": { + "openFiles": [ + "README.md" + ] + } + } +} diff --git a/zsh/.editorconfig b/zsh/.editorconfig index b5321de..797fb62 100644 --- a/zsh/.editorconfig +++ b/zsh/.editorconfig @@ -6,3 +6,10 @@ insert_final_newline = true charset = utf-8 indent_size = 2 indent_style = space + +[*.py] +indent_size = 4 + +[devcontainer.json] +indent_size = 4 +indent_style = tab diff --git a/zsh/.github/CODEOWNERS b/zsh/.github/CODEOWNERS index c6b3e8c..17e8b43 100644 --- a/zsh/.github/CODEOWNERS +++ b/zsh/.github/CODEOWNERS @@ -1,12 +1,19 @@ # Plugin owners plugins/archlinux/ @ratijas -plugins/aws/ @maksyms +plugins/dbt/ @msempere +plugins/eza/ @pepoluan plugins/genpass/ @atoponce plugins/git-lfs/ @hellovietduc plugins/gitfast/ @felipec +plugins/kube-ps1/ @mcornella +plugins/kubectl/ @mcornella +plugins/kubectx/ @mcornella +plugins/opentofu/ @mcornella plugins/react-native @esthor plugins/sdk/ @rgoldberg plugins/shell-proxy/ @septs +plugins/starship/ @axieax +plugins/terraform/ @mcornella plugins/universalarchive/ @Konfekt plugins/wp-cli/ @joshmedeski plugins/zoxide/ @ajeetdsouza diff --git a/zsh/.github/FUNDING.yml b/zsh/.github/FUNDING.yml index 6c86ac4..e91717d 100644 --- a/zsh/.github/FUNDING.yml +++ b/zsh/.github/FUNDING.yml @@ -1,2 +1,6 @@ -github: [ohmyzsh, robbyrussell, mcornella, larson-carter, carlosala] +github: + - ohmyzsh + - robbyrussell + - mcornella + - carlosala open_collective: ohmyzsh diff --git a/zsh/.github/INCIDENT_RESPONSE_PLAN.md b/zsh/.github/INCIDENT_RESPONSE_PLAN.md new file mode 100644 index 0000000..3f0b493 --- /dev/null +++ b/zsh/.github/INCIDENT_RESPONSE_PLAN.md @@ -0,0 +1,87 @@ +# Incident Response Plan + +## Reporting a Vulnerability + +Please see [the latest guidelines](https://github.com/ohmyzsh/ohmyzsh/blob/master/SECURITY.md) for instructions. + +## Phases + +### Triage + +1. Is this a valid security vulnerability? + + - [ ] It affects our CI/CD or any of our repositories. + - [ ] For ohmyzsh/ohmyzsh, it affects the latest commit. + - [ ] For others, it affects the latest commit on the default branch. + - [ ] It affects a third-party dependency: + - [ ] Zsh or git + - [ ] For a plugin, the vulnerability is a result of our usage of the dependency. + +2. What's the scope of the vulnerability? + + - [ ] Our codebase. + - [ ] A direct third-party dependency (Zsh, git, other plugins). + - [ ] An indirect third-party dependency. + - [ ] Out of scope, a third-party dependency that is the responsibility of the user. + - [ ] Out of scope, any other case (edit this plan and add the details). + +3. Is the vulnerability actionable? + + - [ ] Yes, we can submit a fix. + - [ ] Yes, we can disable a feature. + - [ ] Yes, we can mitigate the risk. + - [ ] Yes, we can remove a vulnerable dependency. + - [ ] Yes, we can apply a workaround. + - [ ] Yes, we can apply a patch to a vulnerable dependency ([example for CVE-2021-45444](https://github.com/ohmyzsh/ohmyzsh/blob/cb72d7dcbf08b435c7f8a6470802b207b2aa02c3/lib/vcs_info.zsh)). + - [ ] No, the vulnerability is not actionable. + +4. What's the impact of the vulnerability? + + Assess using the *CIA* triad: + + - **Confidentiality**: example: report or sharing of secrets. + - **Integrity**: affects the integrity of the system (deletion, corruption or encryption of data, OS file corruption, etc.). + - **Availability**: denial of login, deletion of required files to boot / login, etc. + +5. What's the exploitability of the vulnerability? + + Consider how easy it is to exploit, and if it affects all users or requires specific configurations. + +6. What's the severity of the vulnerability? + + You can use the [CVSS v3.1](https://www.first.org/cvss/specification-document) to assess the severity of the vulnerability. + +7. When was the vulnerability introduced? + + - Find the responsible code path. + - Find the commit or Pull Request that introduced the vulnerability. + +8. Who are our security contacts? + + Assess upstream or downstream contacts, and their desired channels of security. + + > TODO: add a list of contacts. + +### Mitigation + +- **Primary focus:** removing possibility of exploitation fast. +- **Secondary focus:** addressing the root cause. + +> [!IMPORTANT] +> Make sure to test that the mitigation works as expected, and does not introduce new vulnerabilities. +> When deploying a patch, make sure not to disclose the vulnerability in the commit message or PR description. + +> TODO: introduce a fast-track update process for security patches. + +### Disclosure + +Primary goal: inform our users about the vulnerability, and whether they are affected or not affected based on information they should be able to check themselves in a straightforward way. + +> TODO: add a vulnerability disclosure template. + +### Learn + +- Document the vulnerability, steps performed, and lessons learned. +- Document the timeline of events. +- Document and address improvements on the Security Incident Response Plan. +- Depending on the severity of the vulnerability, consider disclosing the root cause or not based on likely impact on users and estimated potential victims still affected. diff --git a/zsh/.github/PULL_REQUEST_TEMPLATE.md b/zsh/.github/PULL_REQUEST_TEMPLATE.md index 5c94cae..4d4b784 100644 --- a/zsh/.github/PULL_REQUEST_TEMPLATE.md +++ b/zsh/.github/PULL_REQUEST_TEMPLATE.md @@ -7,6 +7,7 @@ - [ ] I have read the contribution guide and followed all the instructions. - [ ] The code follows the code style guide detailed in the wiki. - [ ] The code is mine or it's from somewhere with an MIT-compatible license. +- [ ] If I used AI tools (ChatGPT, Claude, Gemini, etc.) to assist with this contribution, I've disclosed it below. - [ ] The code is efficient, to the best of my ability, and does not waste computer resources. - [ ] The code is stable and I have tested it myself, to the best of my abilities. - [ ] If the code introduces new aliases, I provide a valid use case for all plugin users down below. diff --git a/zsh/.github/dependabot.yml b/zsh/.github/dependabot.yml new file mode 100644 index 0000000..ebdb804 --- /dev/null +++ b/zsh/.github/dependabot.yml @@ -0,0 +1,14 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: "weekly" + day: "sunday" + labels: [] + - package-ecosystem: "pip" + directory: "/.github/workflows/dependencies" + schedule: + interval: "weekly" + day: "sunday" + labels: [] diff --git a/zsh/.github/dependencies.yml b/zsh/.github/dependencies.yml new file mode 100644 index 0000000..4f4fef9 --- /dev/null +++ b/zsh/.github/dependencies.yml @@ -0,0 +1,56 @@ +dependencies: + plugins/gitfast: + repo: felipec/git-completion + branch: master + version: tag:v2.2 + postcopy: | + set -e + rm -rf git-completion.plugin.zsh Makefile t tools + mv README.adoc MANUAL.adoc + mv -f src/* . + rmdir src + plugins/gradle: + repo: gradle/gradle-completion + branch: master + version: dd3a8adb47e51b1f6e4dc180cb04bd02d5fccd4a + precopy: | + set -e + find . ! -name _gradle ! -name LICENSE -delete + plugins/history-substring-search: + repo: zsh-users/zsh-history-substring-search + branch: master + version: 14c8d2e0ffaee98f2df9850b19944f32546fdea5 + precopy: | + set -e + rm -f zsh-history-substring-search.plugin.zsh + test -e zsh-history-substring-search.zsh && mv zsh-history-substring-search.zsh history-substring-search.zsh + postcopy: | + set -e + test -e dependencies/OMZ-README.md && cat dependencies/OMZ-README.md >> README.md + plugins/kube-ps1: + repo: jonmosco/kube-ps1 + branch: master + version: 9b41c091d5dd4a99e58cf58b5d98a4847937b1bb + precopy: | + set -e + find . ! -name kube-ps1.sh ! -name LICENSE ! -name README.md -delete + test -e kube-ps1.sh && mv kube-ps1.sh kube-ps1.plugin.zsh + plugins/wd: + repo: mfaerevaag/wd + branch: master + version: tag:v0.10.1 + precopy: | + set -e + rm -r test + rm install.sh tty.gif wd.1 + plugins/z: + branch: master + repo: agkozak/zsh-z + version: cf9225feebfae55e557e103e95ce20eca5eff270 + precopy: | + set -e + test -e README.md && mv -f README.md MANUAL.md + postcopy: | + set -e + test -e _zshz && mv -f _zshz _z + test -e zsh-z.plugin.zsh && mv -f zsh-z.plugin.zsh z.plugin.zsh diff --git a/zsh/.github/workflows/dependencies.yml b/zsh/.github/workflows/dependencies.yml new file mode 100644 index 0000000..8053b7a --- /dev/null +++ b/zsh/.github/workflows/dependencies.yml @@ -0,0 +1,43 @@ +name: Update dependencies +on: + workflow_dispatch: {} + schedule: + - cron: "0 6 * * 0" + +jobs: + check: + name: Check for updates + runs-on: ubuntu-latest + if: github.repository == 'ohmyzsh/ohmyzsh' + permissions: + contents: write # this is needed to push commits and branches + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + with: + egress-policy: audit + + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + - name: Authenticate as @ohmyzsh + id: generate-token + uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0 + with: + app-id: ${{ secrets.OHMYZSH_APP_ID }} + private-key: ${{ secrets.OHMYZSH_APP_PRIVATE_KEY }} + - name: Setup Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: "3.12" + cache: "pip" + - name: Process dependencies + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + GIT_APP_NAME: ohmyzsh[bot] + GIT_APP_EMAIL: 54982679+ohmyzsh[bot]@users.noreply.github.com + TMP_DIR: ${{ runner.temp }} + run: | + pip install -r .github/workflows/dependencies/requirements.txt + python3 .github/workflows/dependencies/updater.py diff --git a/zsh/.github/workflows/dependencies/.gitignore b/zsh/.github/workflows/dependencies/.gitignore new file mode 100644 index 0000000..1d17dae --- /dev/null +++ b/zsh/.github/workflows/dependencies/.gitignore @@ -0,0 +1 @@ +.venv diff --git a/zsh/.github/workflows/dependencies/requirements.txt b/zsh/.github/workflows/dependencies/requirements.txt new file mode 100644 index 0000000..359cee6 --- /dev/null +++ b/zsh/.github/workflows/dependencies/requirements.txt @@ -0,0 +1,7 @@ +certifi==2026.2.25 +charset-normalizer==3.4.6 +idna==3.11 +PyYAML==6.0.3 +requests==2.33.0 +semver==3.0.4 +urllib3==2.6.3 diff --git a/zsh/.github/workflows/dependencies/updater.py b/zsh/.github/workflows/dependencies/updater.py new file mode 100644 index 0000000..b61e585 --- /dev/null +++ b/zsh/.github/workflows/dependencies/updater.py @@ -0,0 +1,619 @@ +import json +import os +import re +import shutil +import subprocess +import sys +import timeit +from copy import deepcopy +from typing import Literal, NotRequired, Optional, TypedDict + +import requests +import yaml +from semver import Version + +# Get TMP_DIR variable from environment +TMP_DIR = os.path.join(os.environ.get("TMP_DIR", "/tmp"), "ohmyzsh") +# Relative path to dependencies.yml file +DEPS_YAML_FILE = ".github/dependencies.yml" +# Dry run flag +DRY_RUN = os.environ.get("DRY_RUN", "0") == "1" +# GitHub Token is needed to avoid rate limiting +GH_TOKEN = os.environ.get("GH_TOKEN") +HEADERS = { + "Accept": "application/vnd.github+json", +} +if GH_TOKEN: + HEADERS["Authorization"] = f"Bearer {GH_TOKEN}" + +# utils for tag comparison +BASEVERSION = re.compile( + r"""[vV]? + (?P(0|[1-9])\d*) + (\. + (?P(0|[1-9])\d*) + (\. + (?P(0|[1-9])\d*) + )? + )? + """, + re.VERBOSE, +) + + +def coerce(version: str) -> Optional[Version]: + match = BASEVERSION.search(version) + if not match: + return None + + # BASEVERSION looks for `MAJOR.minor.patch` in the string given + # it fills with None if any of them is missing (for example `2.1`) + ver = { + key: 0 if value is None else value for key, value in match.groupdict().items() + } + # Version takes `major`, `minor`, `patch` arguments + ver = Version(**ver) # pyright: ignore[reportArgumentType] + return ver + + +class CodeTimer: + def __init__(self, name=None): + self.name = " '" + name + "'" if name else "" + + def __enter__(self): + self.start = timeit.default_timer() + + def __exit__(self, exc_type, exc_value, traceback): + self.took = (timeit.default_timer() - self.start) * 1000.0 + print("Code block" + self.name + " took: " + str(self.took) + " ms") + + +### YAML representation +def str_presenter(dumper, data): + """ + Configures yaml for dumping multiline strings + Ref: https://stackoverflow.com/a/33300001 + """ + if len(data.splitlines()) > 1: # check for multiline string + return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|") + return dumper.represent_scalar("tag:yaml.org,2002:str", data) + + +yaml.add_representer(str, str_presenter) +yaml.representer.SafeRepresenter.add_representer(str, str_presenter) + + +# Types +class DependencyDict(TypedDict): + repo: str + branch: str + version: str + precopy: NotRequired[str] + postcopy: NotRequired[str] + + +class DependencyYAML(TypedDict): + dependencies: dict[str, DependencyDict] + + +class UpdateStatusFalse(TypedDict): + has_updates: Literal[False] + + +class UpdateStatusTrue(TypedDict): + has_updates: Literal[True] + version: str + compare_url: str + head_ref: str + head_url: str + + +class CommandRunner: + class Exception(Exception): + def __init__(self, message, returncode, stage, stdout, stderr): + super().__init__(message) + self.returncode = returncode + self.stage = stage + self.stdout = stdout + self.stderr = stderr + + @staticmethod + def run_or_fail(command: list[str], stage: str, *args, **kwargs): + if DRY_RUN and command[0] == "gh": + command.insert(0, "echo") + + result = subprocess.run(command, *args, capture_output=True, **kwargs) + + if result.returncode != 0: + raise CommandRunner.Exception( + f"{stage} command failed with exit code {result.returncode}", + returncode=result.returncode, + stage=stage, + stdout=result.stdout.decode("utf-8"), + stderr=result.stderr.decode("utf-8"), + ) + + return result + + +class DependencyStore: + store: DependencyYAML = {"dependencies": {}} + + @staticmethod + def set(data: DependencyYAML): + DependencyStore.store = data + + @staticmethod + def update_dependency_version(path: str, version: str) -> DependencyYAML: + with CodeTimer(f"store deepcopy: {path}"): + store_copy = deepcopy(DependencyStore.store) + + dependency = store_copy["dependencies"].get(path) + if dependency is None: + raise ValueError(f"Dependency {path} {version} not found") + dependency["version"] = version + store_copy["dependencies"][path] = dependency + + return store_copy + + @staticmethod + def write_store(file: str, data: DependencyYAML): + with open(file, "w") as yaml_file: + yaml.safe_dump(data, yaml_file, sort_keys=False) + + +class Dependency: + def __init__(self, path: str, values: DependencyDict): + self.path = path + self.values = values + + self.name: str = "" + self.desc: str = "" + self.kind: str = "" + + match path.split("/"): + case ["plugins", name]: + self.name = name + self.kind = "plugin" + self.desc = f"{name} plugin" + case ["themes", name]: + self.name = name.replace(".zsh-theme", "") + self.kind = "theme" + self.desc = f"{self.name} theme" + case _: + self.name = self.desc = path + + def __str__(self): + output: str = "" + for key in DependencyDict.__dict__["__annotations__"].keys(): + if key not in self.values: + output += f"{key}: None\n" + continue + + value = self.values[key] + if "\n" not in value: + output += f"{key}: {value}\n" + else: + output += f"{key}:\n " + output += value.replace("\n", "\n ", value.count("\n") - 1) + return output + + def update_or_notify(self): + # Print dependency settings + print(f"Processing {self.desc}...", file=sys.stderr) + print(self, file=sys.stderr) + + # Check for updates + repo = self.values["repo"] + remote_branch = self.values["branch"] + version = self.values["version"] + is_tag = version.startswith("tag:") + + try: + with CodeTimer(f"update check: {repo}"): + if is_tag: + status = GitHub.check_newer_tag(repo, version.replace("tag:", "")) + else: + status = GitHub.check_updates(repo, remote_branch, version) + + if status["has_updates"] is True: + short_sha = status["head_ref"][:8] + new_version = status["version"] if is_tag else short_sha + + try: + branch_name = f"update/{self.path}/{new_version}" + + # Create new branch + branch = Git.checkout_or_create_branch(branch_name) + + # Update dependency files + self.__apply_upstream_changes() + + if not Git.repo_is_clean(): + # Update dependencies.yml file + self.__update_yaml( + f"tag:{new_version}" if is_tag else status["version"] + ) + + # Add all changes and commit + has_new_commit = Git.add_and_commit(self.name, new_version) + + if has_new_commit: + # Push changes to remote + Git.push(branch) + + # Create GitHub PR + GitHub.create_pr( + branch, + f"chore({self.name}): update to version {new_version}", + f"""## Description + +Update for **{self.desc}**: update to version [{new_version}]({status["head_url"]}). +Check out the [list of changes]({status["compare_url"]}). +""", + ) + + # Clean up repository + Git.clean_repo() + except (CommandRunner.Exception, shutil.Error) as e: + # Handle exception on automatic update + match type(e): + case CommandRunner.Exception: + # Print error message + print( + f"Error running {e.stage} command: {e.returncode}", # pyright: ignore[reportAttributeAccessIssue] + file=sys.stderr, + ) + print(e.stderr, file=sys.stderr) # pyright: ignore[reportAttributeAccessIssue] + case shutil.Error: + print(f"Error copying files: {e}", file=sys.stderr) + + try: + Git.clean_repo() + except CommandRunner.Exception as e: + print( + f"Error reverting repository to clean state: {e}", + file=sys.stderr, + ) + sys.exit(1) + + # Create a GitHub issue to notify maintainer + title = f"{self.path}: update to {new_version}" + body = f"""## Description + +There is a new version of `{self.name}` {self.kind} available. + +New version: [{new_version}]({status["head_url"]}) +Check out the [list of changes]({status["compare_url"]}). +""" + + print("Creating GitHub issue", file=sys.stderr) + print(f"{title}\n\n{body}", file=sys.stderr) + GitHub.create_issue(title, body) + except Exception as e: + print(e, file=sys.stderr) + + def __update_yaml(self, new_version: str) -> None: + dep_yaml = DependencyStore.update_dependency_version(self.path, new_version) + DependencyStore.write_store(DEPS_YAML_FILE, dep_yaml) + + def __apply_upstream_changes(self) -> None: + # Patterns to ignore in copying files from upstream repo + GLOBAL_IGNORE = [".git", ".github", ".gitignore"] + + path = os.path.abspath(self.path) + precopy = self.values.get("precopy") + postcopy = self.values.get("postcopy") + + repo = self.values["repo"] + branch = self.values["branch"] + remote_url = f"https://github.com/{repo}.git" + repo_dir = os.path.join(TMP_DIR, repo) + + # Clone repository + Git.clone(remote_url, branch, repo_dir, reclone=True) + + # Run precopy on tmp repo + if precopy is not None: + print("Running precopy script:", end="\n ", file=sys.stderr) + print( + precopy.replace("\n", "\n ", precopy.count("\n") - 1), file=sys.stderr + ) + CommandRunner.run_or_fail( + ["bash", "-c", precopy], cwd=repo_dir, stage="Precopy" + ) + + # Copy files from upstream repo + print(f"Copying files from {repo_dir} to {path}", file=sys.stderr) + shutil.copytree( + repo_dir, + path, + dirs_exist_ok=True, + ignore=shutil.ignore_patterns(*GLOBAL_IGNORE), + ) + + # Run postcopy on our repository + if postcopy is not None: + print("Running postcopy script:", end="\n ", file=sys.stderr) + print( + postcopy.replace("\n", "\n ", postcopy.count("\n") - 1), + file=sys.stderr, + ) + CommandRunner.run_or_fail( + ["bash", "-c", postcopy], cwd=path, stage="Postcopy" + ) + + +class Git: + default_branch = "master" + + @staticmethod + def clone(remote_url: str, branch: str, repo_dir: str, reclone=False): + # If repo needs to be fresh + if reclone and os.path.exists(repo_dir): + shutil.rmtree(repo_dir) + + # Clone repo in tmp directory and checkout branch + if not os.path.exists(repo_dir): + print( + f"Cloning {remote_url} to {repo_dir} and checking out {branch}", + file=sys.stderr, + ) + CommandRunner.run_or_fail( + ["git", "clone", "--depth=1", "-b", branch, remote_url, repo_dir], + stage="Clone", + ) + + @staticmethod + def checkout_or_create_branch(branch_name: str): + # Get current branch name + result = CommandRunner.run_or_fail( + ["git", "rev-parse", "--abbrev-ref", "HEAD"], stage="GetDefaultBranch" + ) + Git.default_branch = result.stdout.decode("utf-8").strip() + + # Create new branch and return created branch name + try: + # try to checkout already existing branch + CommandRunner.run_or_fail( + ["git", "checkout", branch_name], stage="CreateBranch" + ) + except CommandRunner.Exception: + # otherwise create new branch + CommandRunner.run_or_fail( + ["git", "checkout", "-b", branch_name], stage="CreateBranch" + ) + return branch_name + + @staticmethod + def repo_is_clean() -> bool: + """ + Returns `True` if the repo is clean. + Returns `False` if the repo is dirty. + """ + try: + CommandRunner.run_or_fail( + ["git", "diff", "--exit-code"], stage="CheckRepoClean" + ) + return True + except CommandRunner.Exception: + return False + + @staticmethod + def add_and_commit(scope: str, version: str) -> bool: + """ + Returns `True` if there were changes and were indeed commited. + Returns `False` if the repo was clean and no changes were commited. + """ + if Git.repo_is_clean(): + return False + + user_name = os.environ.get("GIT_APP_NAME") + user_email = os.environ.get("GIT_APP_EMAIL") + + # Add all files to git staging + CommandRunner.run_or_fail(["git", "add", "-A", "-v"], stage="AddFiles") + + # Reset environment and git config + clean_env = os.environ.copy() + clean_env["LANG"] = "C.UTF-8" + clean_env["GIT_CONFIG_GLOBAL"] = "/dev/null" + clean_env["GIT_CONFIG_NOSYSTEM"] = "1" + + # Commit with settings above + CommandRunner.run_or_fail( + [ + "git", + "-c", + f"user.name={user_name}", + "-c", + f"user.email={user_email}", + "commit", + "-m", + f"chore({scope}): update to {version}", + ], + stage="CreateCommit", + env=clean_env, + ) + return True + + @staticmethod + def push(branch: str): + CommandRunner.run_or_fail( + ["git", "push", "-u", "origin", branch], stage="PushBranch" + ) + + @staticmethod + def clean_repo(): + CommandRunner.run_or_fail( + ["git", "reset", "--hard", "HEAD"], stage="ResetRepository" + ) + CommandRunner.run_or_fail( + ["git", "checkout", Git.default_branch], stage="CheckoutDefaultBranch" + ) + + +class GitHub: + @staticmethod + def check_newer_tag(repo, current_tag) -> UpdateStatusFalse | UpdateStatusTrue: + # GET /repos/:owner/:repo/git/refs/tags + url = f"https://api.github.com/repos/{repo}/git/refs/tags" + + # Send a GET request to the GitHub API + response = requests.get(url, headers=HEADERS) + current_version = coerce(current_tag) + if current_version is None: + raise ValueError( + f"Stored {current_version} from {repo} does not follow semver" + ) + + # If the request was successful + if response.status_code == 200: + # Parse the JSON response + data = response.json() + + if len(data) == 0: + return { + "has_updates": False, + } + + latest_ref = None + latest_version: Optional[Version] = None + for ref in data: + # we find the tag since GitHub returns it as plain git ref + tag_version = coerce(ref["ref"].replace("refs/tags/", "")) + if tag_version is None: + # we skip every tag that is not semver-complaint + continue + if latest_version is None or tag_version.compare(latest_version) > 0: + # if we have a "greater" semver version, set it as latest + latest_version = tag_version + latest_ref = ref + + # raise if no valid semver tag is found + if latest_ref is None or latest_version is None: + raise ValueError(f"No tags following semver found in {repo}") + + # we get the tag since GitHub returns it as plain git ref + latest_tag = latest_ref["ref"].replace("refs/tags/", "") + + if latest_version.compare(current_version) <= 0: + return { + "has_updates": False, + } + + return { + "has_updates": True, + "version": latest_tag, + "compare_url": f"https://github.com/{repo}/compare/{current_tag}...{latest_tag}", + "head_ref": latest_ref["object"]["sha"], + "head_url": f"https://github.com/{repo}/releases/tag/{latest_tag}", + } + else: + # If the request was not successful, raise an exception + raise Exception( + f"GitHub API request failed with status code {response.status_code}: {response.json()}" + ) + + @staticmethod + def check_updates(repo, branch, version) -> UpdateStatusFalse | UpdateStatusTrue: + url = f"https://api.github.com/repos/{repo}/compare/{version}...{branch}" + + # Send a GET request to the GitHub API + response = requests.get(url, headers=HEADERS) + + # If the request was successful + if response.status_code == 200: + # Parse the JSON response + data = response.json() + + # If the base is behind the head, there is a newer version + has_updates = data["status"] != "identical" + + if not has_updates: + return { + "has_updates": False, + } + + return { + "has_updates": data["status"] != "identical", + "version": data["commits"][-1]["sha"], + "compare_url": data["permalink_url"], + "head_ref": data["commits"][-1]["sha"], + "head_url": data["commits"][-1]["html_url"], + } + else: + # If the request was not successful, raise an exception + raise Exception( + f"GitHub API request failed with status code {response.status_code}: {response.json()}" + ) + + @staticmethod + def create_issue(title: str, body: str) -> None: + cmd = ["gh", "issue", "create", "-t", title, "-b", body] + CommandRunner.run_or_fail(cmd, stage="CreateIssue") + + @staticmethod + def create_pr(branch: str, title: str, body: str) -> None: + # first of all let's check if PR is already open + check_cmd = [ + "gh", + "pr", + "list", + "--state", + "open", + "--head", + branch, + "--json", + "title", + ] + # returncode is 0 also if no PRs are found + output = json.loads( + CommandRunner.run_or_fail(check_cmd, stage="CheckPullRequestOpen") + .stdout.decode("utf-8") + .strip() + ) + # we have PR in this case! + if len(output) > 0: + return + cmd = [ + "gh", + "pr", + "create", + "-B", + Git.default_branch, + "-H", + branch, + "-t", + title, + "-b", + body, + ] + CommandRunner.run_or_fail(cmd, stage="CreatePullRequest") + + +def main(): + # Load the YAML file + with open(DEPS_YAML_FILE, "r") as yaml_file: + data: DependencyYAML = yaml.safe_load(yaml_file) + + if "dependencies" not in data: + raise Exception("dependencies.yml not properly formatted") + + # Cache YAML version + DependencyStore.set(data) + + dependencies = data["dependencies"] + if len(sys.argv) > 1: + # argv is list of dependencies to run, default is all of them + dependency_list = sys.argv[1:] + else: + dependency_list = dependencies.keys() + + for path in dependency_list: + dependency = Dependency(path, dependencies[path]) + dependency.update_or_notify() + + +if __name__ == "__main__": + main() diff --git a/zsh/.github/workflows/installer.yml b/zsh/.github/workflows/installer.yml new file mode 100644 index 0000000..cead84c --- /dev/null +++ b/zsh/.github/workflows/installer.yml @@ -0,0 +1,66 @@ +name: Test and Deploy installer +on: + workflow_dispatch: {} + push: + paths: + - 'tools/install.sh' + - '.github/workflows/installer/**' + - '.github/workflows/installer.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: false + +permissions: + contents: read # to checkout + +jobs: + test: + name: Test installer + if: github.repository == 'ohmyzsh/ohmyzsh' + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: + - ubuntu-latest + - macos-latest + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + with: + egress-policy: audit + + - name: Set up git repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Install zsh + if: runner.os == 'Linux' + run: sudo apt-get update; sudo apt-get install zsh + - name: Test installer + run: sh ./tools/install.sh + + deploy: + name: Deploy installer in install.ohmyz.sh + if: github.ref == 'refs/heads/master' + runs-on: ubuntu-latest + environment: vercel + needs: + - test + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + with: + egress-policy: audit + + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Install Vercel CLI + run: npm install -g vercel + - name: Setup project and deploy + env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + run: | + cp tools/install.sh .github/workflows/installer/install.sh + cd .github/workflows/installer + vc deploy --prod -t "$VERCEL_TOKEN" diff --git a/zsh/.github/workflows/installer/.gitignore b/zsh/.github/workflows/installer/.gitignore new file mode 100644 index 0000000..f66fce3 --- /dev/null +++ b/zsh/.github/workflows/installer/.gitignore @@ -0,0 +1 @@ +install.sh diff --git a/zsh/.github/workflows/installer/.vercelignore b/zsh/.github/workflows/installer/.vercelignore new file mode 100644 index 0000000..41b2333 --- /dev/null +++ b/zsh/.github/workflows/installer/.vercelignore @@ -0,0 +1,2 @@ +/* +!/install.sh diff --git a/zsh/.github/workflows/installer/vercel.json b/zsh/.github/workflows/installer/vercel.json new file mode 100644 index 0000000..88ec187 --- /dev/null +++ b/zsh/.github/workflows/installer/vercel.json @@ -0,0 +1,23 @@ +{ + "headers": [ + { + "source": "/(|install.sh)", + "headers": [ + { + "key": "Content-Type", + "value": "text/plain" + }, + { + "key": "Content-Disposition", + "value": "inline; filename=\"install.sh\"" + } + ] + } + ], + "rewrites": [ + { + "source": "/", + "destination": "/install.sh" + } + ] +} diff --git a/zsh/.github/workflows/main.yml b/zsh/.github/workflows/main.yml index 57a1e38..e0d9a72 100644 --- a/zsh/.github/workflows/main.yml +++ b/zsh/.github/workflows/main.yml @@ -7,7 +7,7 @@ on: branches: - master push: - branches: + branches: - master concurrency: @@ -20,19 +20,18 @@ permissions: jobs: tests: name: Run tests - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest if: github.repository == 'ohmyzsh/ohmyzsh' - strategy: - matrix: - os: [ubuntu-latest, macos-latest] steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + with: + egress-policy: audit + - name: Set up git repository - uses: actions/checkout@v2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install zsh - if: runner.os == 'Linux' run: sudo apt-get update; sudo apt-get install zsh - - name: Test installer - run: sh ./tools/install.sh - name: Check syntax run: | for file in ./oh-my-zsh.sh \ diff --git a/zsh/.github/workflows/project.yml b/zsh/.github/workflows/project.yml index 999cc08..ab9d4d1 100644 --- a/zsh/.github/workflows/project.yml +++ b/zsh/.github/workflows/project.yml @@ -15,11 +15,20 @@ jobs: name: Add to project runs-on: ubuntu-latest if: github.repository == 'ohmyzsh/ohmyzsh' - env: - GITHUB_TOKEN: ${{ secrets.PROJECT_TOKEN }} steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + with: + egress-policy: audit + - name: Authenticate as @ohmyzsh + id: generate-token + uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0 + with: + app-id: ${{ secrets.OHMYZSH_APP_ID }} + private-key: ${{ secrets.OHMYZSH_APP_PRIVATE_KEY }} - name: Read project data env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} ORGANIZATION: ohmyzsh PROJECT_NUMBER: "1" run: | @@ -27,77 +36,84 @@ jobs: gh api graphql -f query=' query($org: String!, $number: Int!) { organization(login: $org){ - projectNext(number: $number) { + projectV2(number: $number) { id fields(first:20) { nodes { - id - name + ... on ProjectV2Field { + id + name + } } } } } - } - ' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json + }' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json # Parse project data - cat >> $GITHUB_ENV <> "$GITHUB_ENV" <> $GITHUB_ENV - - name: Classify Pull Request if: github.event_name == 'pull_request_target' + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + PR_NUMBER: ${{ github.event.pull_request.number }} run: | - touch plugins.list themes.list - - gh pr view ${{ github.event.pull_request.number }} \ - --repo ${{ github.repository }} \ + # Get the list of modified files in the PR, and extract plugins and themes + gh pr view "$PR_NUMBER" \ + --repo "$GITHUB_REPOSITORY" \ --json files --jq '.files.[].path' | awk -F/ ' + BEGIN { + plugins = 0 + themes = 0 + } /^plugins\// { - plugins[$2] = 1 + if (plugin == $2) next + plugin = $2 + plugins++ } /^themes\// { gsub(/\.zsh-theme$/, "", $2) - themes[$2] = 1 + if (theme == $2) next + theme = $2 + themes++ } END { - for (plugin in plugins) { - print plugin >> "plugins.list" + # plugin and theme are values controlled by the PR author + # so we should sanitize them before using anywhere else + if (plugins == 1) { + gsub(/[^a-zA-Z0-9._-]/, "", plugin) + print "PLUGIN=" plugin } - for (theme in themes) { - print theme >> "themes.list" + if (themes == 1) { + gsub(/[^a-zA-Z0-9._-]/, "", theme) + print "THEME=" theme } } - ' - # If only one plugin is modified, add it to the plugin field - if [[ $(wc -l < plugins.list) = 1 ]]; then - echo "PLUGIN=$(cat plugins.list)" >> $GITHUB_ENV - fi - # If only one theme is modified, add it to the theme field - if [[ $(wc -l < themes.list) = 1 ]]; then - echo "THEME=$(cat themes.list)" >> $GITHUB_ENV - fi - + ' >> "$GITHUB_ENV" - name: Fill Pull Request fields in project if: github.event_name == 'pull_request_target' + env: + GH_TOKEN: ${{ steps.generate-token.outputs.token }} run: | gh api graphql -f query=' mutation ( @@ -108,29 +124,32 @@ jobs: $theme_field: ID! $theme_value: String! ) { - set_plugin: updateProjectNextItemField(input: { + set_plugin: updateProjectV2ItemFieldValue(input: { projectId: $project itemId: $item fieldId: $plugin_field - value: $plugin_value + value: { + text: $plugin_value + } }) { - projectNextItem { + projectV2Item { id } } - set_theme: updateProjectNextItemField(input: { + set_theme: updateProjectV2ItemFieldValue(input: { projectId: $project itemId: $item fieldId: $theme_field - value: $theme_value + value: { + text: $theme_value + } }) { - projectNextItem { + projectV2Item { id } } } - ' -f project=$PROJECT_ID -f item=$ITEM_ID \ - -f plugin_field=$PLUGIN_FIELD_ID -f plugin_value=$PLUGIN \ - -f theme_field=$THEME_FIELD_ID -f theme_value=$THEME \ + ' -f project="$PROJECT_ID" -f item="$ITEM_ID" \ + -f plugin_field="$PLUGIN_FIELD_ID" -f plugin_value="$PLUGIN" \ + -f theme_field="$THEME_FIELD_ID" -f theme_value="$THEME" \ --silent - diff --git a/zsh/.github/workflows/scorecard.yml b/zsh/.github/workflows/scorecard.yml new file mode 100644 index 0000000..a7d573a --- /dev/null +++ b/zsh/.github/workflows/scorecard.yml @@ -0,0 +1,65 @@ +# This workflow uses actions that are not certified by GitHub. They are provided +# by a third-party and are governed by separate terms of service, privacy +# policy, and support documentation. + +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: '20 7 * * 2' + push: + branches: ["master"] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + contents: read + actions: read + # To allow GraphQL ListCommits to work + issues: read + pull-requests: read + # To detect SAST tools + checks: read + + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + with: + egress-policy: audit + + - name: "Checkout code" + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 + with: + results_file: results.sarif + results_format: sarif + publish_results: true + + - name: "Upload artifact" + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 + with: + sarif_file: results.sarif diff --git a/zsh/.gitignore b/zsh/.gitignore index 71ae444..145ae9c 100644 --- a/zsh/.gitignore +++ b/zsh/.gitignore @@ -4,8 +4,18 @@ custom/ # temp files directories cache/ log/ + +# Vim swap/backup files *.swp +*.swo + +# macOS system files .DS_Store # editor configs -.vscode \ No newline at end of file +.vscode +.idea + +# zcompile cached files +*.zwc +*.zwc.old diff --git a/zsh/.gitpod.Dockerfile b/zsh/.gitpod.Dockerfile deleted file mode 100644 index b35c80d..0000000 --- a/zsh/.gitpod.Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM gitpod/workspace-full - -RUN sudo apt-get update && \ - sudo apt-get install -y zsh && \ - sudo rm -rf /var/lib/apt/lists/* diff --git a/zsh/.gitpod.yml b/zsh/.gitpod.yml deleted file mode 100644 index ccc5724..0000000 --- a/zsh/.gitpod.yml +++ /dev/null @@ -1,9 +0,0 @@ -image: - file: .gitpod.Dockerfile - -tasks: - - init: | - export EDITOR="command gp open -w" VISUAL="command gp open -w" - cp -f /workspace/ohmyzsh/templates/zshrc.zsh-template ~/.zshrc - ln -sf /workspace/ohmyzsh ~/.oh-my-zsh - command: exec zsh diff --git a/zsh/.prettierrc b/zsh/.prettierrc new file mode 100644 index 0000000..a8f5a14 --- /dev/null +++ b/zsh/.prettierrc @@ -0,0 +1,4 @@ +{ + "printWidth": 110, + "proseWrap": "always" +} diff --git a/zsh/CONTRIBUTING.md b/zsh/CONTRIBUTING.md index e78bd81..5168cde 100644 --- a/zsh/CONTRIBUTING.md +++ b/zsh/CONTRIBUTING.md @@ -20,6 +20,7 @@ you would make is not already covered. - [Getting started](#getting-started) - [You have a solution](#you-have-a-solution) - [You have an addition](#you-have-an-addition) +- [A note on AI-assisted contributions](#a-note-on-ai-assisted-contributions) - [Use the Search, Luke](#use-the-search-luke) - [Commit Guidelines](#commit-guidelines) - [Format](#format) @@ -35,13 +36,13 @@ you would make is not already covered. Please be so kind as to [search](#use-the-search-luke) for any open issue already covering your problem. -If you find one, comment on it so we can know there are more people experiencing it. +If you find one, comment on it, so we know more people are experiencing it. If not, look at the [Troubleshooting](https://github.com/ohmyzsh/ohmyzsh/wiki/Troubleshooting) page for instructions on how to gather data to better debug your problem. Then, you can go ahead and create an issue with as much detail as you can provide. -It should include the data gathered as indicated above, along with: +It should include the data gathered as indicated above, along with the following: 1. How to reproduce the problem 2. What the correct behavior should be @@ -57,7 +58,7 @@ We will do our very best to help you. Please be so kind as to [search](#use-the-search-luke) for any open issue already covering your suggestion. -If you find one, comment on it so we can know there are more people supporting it. +If you find one, comment on it, so we know more people are supporting it. If not, you can go ahead and create an issue. Please copy to anyone relevant (e.g. plugin maintainers) by mentioning their GitHub handle (starting with `@`) in your message. @@ -84,7 +85,7 @@ your [problem](#you-have-a-problem), and any pending/merged/rejected PR covering If the solution is already reported, try it out and +1 the pull request if the solution works ok. On the other hand, if you think your solution is better, post -it with a reference to the other one so we can have both solutions to compare. +it with reference to the other one so we can have both solutions to compare. If not, then go ahead and submit a PR. Please copy to anyone relevant (e.g. plugin maintainers) by mentioning their GitHub handle (starting with `@`) in your message. @@ -113,18 +114,42 @@ This has become an issue for two opposing reasons: - Some users want to have their personal aliases in Oh My Zsh. - Some users don't want any aliases at all and feel that there are too many. -Because of this, from now on we're requiring that new aliases follow these conditions: +Because of this, from now on, we require that new aliases follow these conditions: 1. They will be used by many people, not just a few. 2. The aliases will be used many times and for common tasks. 3. Prefer one generic alias over many specific ones. 4. When justifying the need for an alias, talk about workflows where you'll use it, preferably in combination with other aliases. -5. If there exists a command with the same name, look for a different alias name. +5. If a command with the same name exists, look for a different alias name. This list is not exhaustive! Please remember that your alias will be in the machines of many people, so it should be justified why they should have it. +## A note on AI-assisted contributions + +We'll admit it: AI tools can be pretty helpful for coding tasks, and we're not here to gatekeep how you get your work done. We use these tools ourselves! 🤖 + +But here's the thing—Oh My Zsh is maintained by a small team of volunteers who do this in their spare time. We already have hundreds of pending PRs, and we want to make sure we're spending our limited time effectively. + +If you used AI tools meaningfully in your contribution (code generation, agentic coding assistants, etc.), please mention it in your PR description. Basic autocomplete doesn't count, but if an AI wrote substantial parts of your code, just let us know. + +**Examples of good disclosure:** +- "Used ChatGPT to help generate the initial regex pattern for parsing git status output" +- "Claude assisted with writing the unit tests for this feature" +- "Generated with Gemini and then reviewed/tested manually" +- Or simply: "AI-assisted" in your PR description + +Here's what we're looking for: + +- **You understand your code**: You should be able to explain what your contribution does and how it works. We want to collaborate with humans who are invested in the project. +- **Context matters**: Tell us what problem you're solving, how you tested it, and link to relevant docs. Small, incremental changes work better than massive generated overhauls. +- **Quality over quantity**: We'd rather have one thoughtful, well-tested contribution than ten AI-generated PRs that need extensive review. + +The disclosure helps us know how much guidance to offer. If we're just reviewing AI output that you can't explain or improve, that changes the dynamic—and frankly, it's not a great use of anyone's time. + +As always, we reserve the right to decline any contribution. PRs that appear to be unreviewed AI output, or code the contributor can't explain, may be closed without extensive feedback. + ---- ## Use the Search, Luke @@ -214,7 +239,7 @@ type(scope)!: subject ``` - `subject`: a brief description of the changes. This will be displayed in the changelog. If you need - to specify other details you can use the commit body but it won't be visible. + to specify other details, you can use the commit body, but it won't be visible. Formatting tricks: the commit subject may contain: @@ -231,8 +256,8 @@ type(scope)!: subject ### Style -Try to keep the first commit line short. This is harder to do using this commit style but try to be -concise and if you need more space, you can use the commit body. Try to make sure that the commit +Try to keep the first commit line short. It's harder to do using this commit style but try to be +concise, and if you need more space, you can use the commit body. Try to make sure that the commit subject is clear and precise enough that users will know what changed by just looking at the changelog. ---- diff --git a/zsh/LICENSE.txt b/zsh/LICENSE.txt index 2d7ca6f..1ea913a 100644 --- a/zsh/LICENSE.txt +++ b/zsh/LICENSE.txt @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2009-2022 Robby Russell and contributors (https://github.com/ohmyzsh/ohmyzsh/contributors) +Copyright (c) 2009-2026 Robby Russell and contributors (https://github.com/ohmyzsh/ohmyzsh/contributors) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/zsh/README.md b/zsh/README.md index 1e4b7ff..d7f1433 100644 --- a/zsh/README.md +++ b/zsh/README.md @@ -1,50 +1,60 @@

Oh My Zsh

-Oh My Zsh is an open source, community-driven framework for managing your [zsh](https://www.zsh.org/) configuration. +Oh My Zsh is an open source, community-driven framework for managing your [zsh](https://www.zsh.org/) +configuration. Sounds boring. Let's try again. **Oh My Zsh will not make you a 10x developer...but you may feel like one.** -Once installed, your terminal shell will become the talk of the town _or your money back!_ With each keystroke in your command prompt, you'll take advantage of the hundreds of powerful plugins and beautiful themes. Strangers will come up to you in cafés and ask you, _"that is amazing! are you some sort of genius?"_ +Once installed, your terminal shell will become the talk of the town _or your money back!_ With each keystroke +in your command prompt, you'll take advantage of the hundreds of powerful plugins and beautiful themes. +Strangers will come up to you in cafés and ask you, _"that is amazing! are you some sort of genius?"_ -Finally, you'll begin to get the sort of attention that you have always felt you deserved. ...or maybe you'll use the time that you're saving to start flossing more often. 😬 +Finally, you'll begin to get the sort of attention that you have always felt you deserved. ...or maybe you'll +use the time that you're saving to start flossing more often. 😬 -To learn more, visit [ohmyz.sh](https://ohmyz.sh), follow [@ohmyzsh](https://twitter.com/ohmyzsh) on Twitter, and join us on [Discord](https://discord.gg/ohmyzsh). +To learn more, visit [ohmyz.sh](https://ohmyz.sh), follow [@ohmyzsh](https://x.com/ohmyzsh) on X (formerly +Twitter), and join us on [Discord](https://discord.gg/ohmyzsh). [![CI](https://github.com/ohmyzsh/ohmyzsh/workflows/CI/badge.svg)](https://github.com/ohmyzsh/ohmyzsh/actions?query=workflow%3ACI) -[![Follow @ohmyzsh](https://img.shields.io/twitter/follow/ohmyzsh?label=Follow+@ohmyzsh&style=flat)](https://twitter.com/intent/follow?screen_name=ohmyzsh) +[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/10713/badge)](https://www.bestpractices.dev/projects/10713) +[![X (formerly Twitter) Follow](https://img.shields.io/twitter/follow/ohmyzsh?label=%40ohmyzsh&logo=x&style=flat)](https://twitter.com/intent/follow?screen_name=ohmyzsh) +[![Mastodon Follow](https://img.shields.io/mastodon/follow/111169632522566717?label=%40ohmyzsh&domain=https%3A%2F%2Fmstdn.social&logo=mastodon&style=flat)](https://mstdn.social/@ohmyzsh) [![Discord server](https://img.shields.io/discord/642496866407284746)](https://discord.gg/ohmyzsh) -[![Gitpod ready](https://img.shields.io/badge/Gitpod-ready-blue?logo=gitpod)](https://gitpod.io/#https://github.com/ohmyzsh/ohmyzsh) -[![huntr.dev](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev/bounties/disclose/?utm_campaign=ohmyzsh%2Fohmyzsh&utm_medium=social&utm_source=github&target=https%3A%2F%2Fgithub.com%2Fohmyzsh%2Fohmyzsh)
Table of Contents - [Getting Started](#getting-started) + - [Operating System Compatibility](#operating-system-compatibility) - [Prerequisites](#prerequisites) - [Basic Installation](#basic-installation) - - [Manual inspection](#manual-inspection) + - [Manual Inspection](#manual-inspection) - [Using Oh My Zsh](#using-oh-my-zsh) - [Plugins](#plugins) - [Enabling Plugins](#enabling-plugins) - [Using Plugins](#using-plugins) - [Themes](#themes) - - [Selecting a Theme](#selecting-a-theme) + - [Selecting A Theme](#selecting-a-theme) - [FAQ](#faq) - [Advanced Topics](#advanced-topics) - [Advanced Installation](#advanced-installation) - [Custom Directory](#custom-directory) - - [Unattended install](#unattended-install) - - [Installing from a forked repository](#installing-from-a-forked-repository) + - [Unattended Install](#unattended-install) + - [Installing From A Forked Repository](#installing-from-a-forked-repository) - [Manual Installation](#manual-installation) - [Installation Problems](#installation-problems) - - [Custom Plugins and Themes](#custom-plugins-and-themes) + - [Custom Plugins And Themes](#custom-plugins-and-themes) + - [Enable GNU ls In macOS And FreeBSD Systems](#enable-gnu-ls-in-macos-and-freebsd-systems) + - [Skip Aliases](#skip-aliases) + - [Async git prompt](#async-git-prompt) - [Getting Updates](#getting-updates) + - [Updates Verbosity](#updates-verbosity) - [Manual Updates](#manual-updates) - [Uninstalling Oh My Zsh](#uninstalling-oh-my-zsh) -- [How do I contribute to Oh My Zsh?](#how-do-i-contribute-to-oh-my-zsh) - - [Do NOT send us themes](#do-not-send-us-themes) +- [How Do I Contribute To Oh My Zsh?](#how-do-i-contribute-to-oh-my-zsh) + - [Do Not Send Us Themes](#do-not-send-us-themes) - [Contributors](#contributors) - [Follow Us](#follow-us) - [Merchandise](#merchandise) @@ -55,16 +65,30 @@ To learn more, visit [ohmyz.sh](https://ohmyz.sh), follow [@ohmyzsh](https://twi ## Getting Started +### Operating System Compatibility + +| O/S | Status | +| :------------- | :----: | +| Android | ✅ | +| FreeBSD | ✅ | +| LCARS | 🛸 | +| Linux | ✅ | +| macOS | ✅ | +| OS/2 Warp | ❌ | +| Windows (WSL2) | ✅ | + ### Prerequisites -- A Unix-like operating system: macOS, Linux, BSD. On Windows: WSL2 is preferred, but cygwin or msys also mostly work. -- [Zsh](https://www.zsh.org) should be installed (v4.3.9 or more recent is fine but we prefer 5.0.8 and newer). If not pre-installed (run `zsh --version` to confirm), check the following wiki instructions here: [Installing ZSH](https://github.com/ohmyzsh/ohmyzsh/wiki/Installing-ZSH) +- [Zsh](https://www.zsh.org) should be installed (v4.3.9 or more recent is fine but we prefer 5.0.8 and + newer). If not pre-installed (run `zsh --version` to confirm), check the following wiki instructions here: + [Installing ZSH](https://github.com/ohmyzsh/ohmyzsh/wiki/Installing-ZSH) - `curl` or `wget` should be installed - `git` should be installed (recommended v2.4.11 or higher) ### Basic Installation -Oh My Zsh is installed by running one of the following commands in your terminal. You can install this via the command-line with either `curl`, `wget` or another similar tool. +Oh My Zsh is installed by running one of the following commands in your terminal. You can install this via the +command-line with either `curl`, `wget` or another similar tool. | Method | Command | | :-------- | :------------------------------------------------------------------------------------------------ | @@ -72,28 +96,44 @@ Oh My Zsh is installed by running one of the following commands in your terminal | **wget** | `sh -c "$(wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"` | | **fetch** | `sh -c "$(fetch -o - https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"` | -_Note that any previous `.zshrc` will be renamed to `.zshrc.pre-oh-my-zsh`. After installation, you can move the configuration you want to preserve into the new `.zshrc`._ +Alternatively, the installer is also mirrored outside GitHub. Using this URL instead may be required if you're +in a country like China or India (for certain ISPs), that blocks `raw.githubusercontent.com`: -#### Manual inspection +| Method | Command | +| :-------- | :------------------------------------------------ | +| **curl** | `sh -c "$(curl -fsSL https://install.ohmyz.sh/)"` | +| **wget** | `sh -c "$(wget -O- https://install.ohmyz.sh/)"` | +| **fetch** | `sh -c "$(fetch -o - https://install.ohmyz.sh/)"` | -It's a good idea to inspect the install script from projects you don't yet know. You can do -that by downloading the install script first, looking through it so everything looks normal, -then running it: +_Note that any previous `.zshrc` will be renamed to `.zshrc.pre-oh-my-zsh`. After installation, you can move +the configuration you want to preserve into the new `.zshrc`._ + +#### Manual Inspection + +It's a good idea to inspect the install script from projects you don't yet know. You can do that by +downloading the install script first, looking through it so everything looks normal, then running it: ```sh wget https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh sh install.sh ``` +If the above URL times out or otherwise fails, you may have to substitute the URL for +`https://install.ohmyz.sh` to be able to get the script. + ## Using Oh My Zsh ### Plugins -Oh My Zsh comes with a shitload of plugins for you to take advantage of. You can take a look in the [plugins](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins) directory and/or the [wiki](https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins) to see what's currently available. +Oh My Zsh comes with a shitload of plugins for you to take advantage of. You can take a look in the +[plugins](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins) directory and/or the +[wiki](https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins) to see what's currently available. #### Enabling Plugins -Once you spot a plugin (or several) that you'd like to use with Oh My Zsh, you'll need to enable them in the `.zshrc` file. You'll find the zshrc file in your `$HOME` directory. Open it with your favorite text editor and you'll see a spot to list all the plugins you want to load. +Once you spot a plugin (or several) that you'd like to use with Oh My Zsh, you'll need to enable them in the +`.zshrc` file. You'll find the zshrc file in your `$HOME` directory. Open it with your favorite text editor +and you'll see a spot to list all the plugins you want to load. ```sh vi ~/.zshrc @@ -113,21 +153,28 @@ plugins=( ) ``` -_Note that the plugins are separated by whitespace (spaces, tabs, new lines...). **Do not** use commas between them or it will break._ +_Note that the plugins are separated by whitespace (spaces, tabs, new lines...). **Do not** use commas between +them or it will break._ #### Using Plugins -Each built-in plugin includes a **README**, documenting it. This README should show the aliases (if the plugin adds any) and extra goodies that are included in that particular plugin. +Each built-in plugin includes a **README**, documenting it. This README should show the aliases (if the plugin +adds any) and extra goodies that are included in that particular plugin. ### Themes -We'll admit it. Early in the Oh My Zsh world, we may have gotten a bit too theme happy. We have over one hundred and fifty themes now bundled. Most of them have [screenshots](https://github.com/ohmyzsh/ohmyzsh/wiki/Themes) on the wiki (We are working on updating this!). Check them out! +We'll admit it. Early in the Oh My Zsh world, we may have gotten a bit too theme-happy. We have over one +hundred and fifty themes now bundled. Most of them have +[screenshots](https://github.com/ohmyzsh/ohmyzsh/wiki/Themes) on the wiki (We are working on updating this!). +Check them out! -#### Selecting a Theme +#### Selecting A Theme -_Robby's theme is the default one. It's not the fanciest one. It's not the simplest one. It's just the right one (for him)._ +_Robby's theme is the default one. It's not the fanciest one. It's not the simplest one. It's just the right +one (for him)._ -Once you find a theme that you'd like to use, you will need to edit the `~/.zshrc` file. You'll see an environment variable (all caps) in there that looks like: +Once you find a theme that you'd like to use, you will need to edit the `~/.zshrc` file. You'll see an +environment variable (all caps) in there that looks like: ```sh ZSH_THEME="robbyrussell" @@ -140,21 +187,38 @@ ZSH_THEME="agnoster" # (this is one of the fancy ones) # see https://github.com/ohmyzsh/ohmyzsh/wiki/Themes#agnoster ``` -_Note: many themes require installing a [Powerline Font](https://github.com/powerline/fonts) or a [Nerd Font](https://github.com/ryanoasis/nerd-fonts) in order to render properly. Without them, these themes will render [weird prompt symbols](https://github.com/ohmyzsh/ohmyzsh/wiki/FAQ#i-have-a-weird-character-in-my-prompt)_ + +> [!NOTE] +> You will many times see screenshots for a zsh theme, and try it out, and find that it doesn't look the same for you. +> +> This is because many themes require installing a [Powerline Font](https://github.com/powerline/fonts) or a +> [Nerd Font](https://github.com/ryanoasis/nerd-fonts) in order to render properly. Without them, these themes +> will render weird prompt symbols. Check out +> [the FAQ](https://github.com/ohmyzsh/ohmyzsh/wiki/FAQ#i-have-a-weird-character-in-my-prompt) for more +> information. +> +> Also, beware that themes only control what your prompt looks like. This is, the text you see before or after +> your cursor, where you'll type your commands. Themes don't control things such as the colors of your +> terminal window (known as _color scheme_) or the font of your terminal. These are settings that you can +> change in your terminal emulator. For more information, see +> [what is a zsh theme](https://github.com/ohmyzsh/ohmyzsh/wiki/FAQ#what-is-a-zsh-theme). + Open up a new terminal window and your prompt should look something like this: ![Agnoster theme](https://cloud.githubusercontent.com/assets/2618447/6316862/70f58fb6-ba03-11e4-82c9-c083bf9a6574.png) -In case you did not find a suitable theme for your needs, please have a look at the wiki for [more of them](https://github.com/ohmyzsh/ohmyzsh/wiki/External-themes). +In case you did not find a suitable theme for your needs, please have a look at the wiki for +[more of them](https://github.com/ohmyzsh/ohmyzsh/wiki/External-themes). -If you're feeling feisty, you can let the computer select one randomly for you each time you open a new terminal window. +If you're feeling feisty, you can let the computer select one randomly for you each time you open a new +terminal window. ```sh ZSH_THEME="random" # (...please let it be pie... please be some pie..) ``` -And if you want to pick random theme from a list of your favorite themes: +And if you want to pick a random theme from a list of your favorite themes: ```sh ZSH_THEME_RANDOM_CANDIDATES=( @@ -171,7 +235,8 @@ ZSH_THEME_RANDOM_IGNORED=(pygmalion tjkirch_mod) ### FAQ -If you have some more questions or issues, you might find a solution in our [FAQ](https://github.com/ohmyzsh/ohmyzsh/wiki/FAQ). +If you have some more questions or issues, you might find a solution in our +[FAQ](https://github.com/ohmyzsh/ohmyzsh/wiki/FAQ). ## Advanced Topics @@ -179,47 +244,50 @@ If you're the type that likes to get their hands dirty, these sections might res ### Advanced Installation -Some users may want to manually install Oh My Zsh, or change the default path or other settings that -the installer accepts (these settings are also documented at the top of the install script). +Some users may want to manually install Oh My Zsh, or change the default path or other settings that the +installer accepts (these settings are also documented at the top of the install script). #### Custom Directory -The default location is `~/.oh-my-zsh` (hidden in your home directory, you can access it with `cd ~/.oh-my-zsh`) +The default location is `~/.oh-my-zsh` (hidden in your home directory, you can access it with +`cd ~/.oh-my-zsh`) If you'd like to change the install directory with the `ZSH` environment variable, either by running -`export ZSH=/your/path` before installing, or by setting it before the end of the install pipeline -like this: +`export ZSH=/your/path` before installing, or by setting it before the end of the install pipeline like this: ```sh ZSH="$HOME/.dotfiles/oh-my-zsh" sh install.sh ``` -#### Unattended install +#### Unattended Install -If you're running the Oh My Zsh install script as part of an automated install, you can pass the `--unattended` -flag to the `install.sh` script. This will have the effect of not trying to change -the default shell, and it also won't run `zsh` when the installation has finished. +If you're running the Oh My Zsh install script as part of an automated install, you can pass the +`--unattended` flag to the `install.sh` script. This will have the effect of not trying to change the default +shell, and it also won't run `zsh` when the installation has finished. ```sh sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended ``` -#### Installing from a forked repository +If you're in China, India, or another country that blocks `raw.githubusercontent.com`, you may have to +substitute the URL for `https://install.ohmyz.sh` for it to install. -The install script also accepts these variables to allow installation of a different repository: +#### Installing From A Forked Repository -- `REPO` (default: `ohmyzsh/ohmyzsh`): this takes the form of `owner/repository`. If you set - this variable, the installer will look for a repository at `https://github.com/{owner}/{repository}`. +The install script also accepts these variables to allow the installation of a different repository: -- `REMOTE` (default: `https://github.com/${REPO}.git`): this is the full URL of the git repository - clone. You can use this setting if you want to install from a fork that is not on GitHub (GitLab, - Bitbucket...) or if you want to clone with SSH instead of HTTPS (`git@github.com:user/project.git`). +- `REPO` (default: `ohmyzsh/ohmyzsh`): this takes the form of `owner/repository`. If you set this variable, + the installer will look for a repository at `https://github.com/{owner}/{repository}`. + +- `REMOTE` (default: `https://github.com/${REPO}.git`): this is the full URL of the git repository clone. You + can use this setting if you want to install from a fork that is not on GitHub (GitLab, Bitbucket...) or if + you want to clone with SSH instead of HTTPS (`git@github.com:user/project.git`). _NOTE: it's incompatible with setting the `REPO` variable. This setting will take precedence._ - `BRANCH` (default: `master`): you can use this setting if you want to change the default branch to be - checked out when cloning the repository. This might be useful for testing a Pull Request, or if you - want to use a branch other than `master`. + checked out when cloning the repository. This might be useful for testing a Pull Request, or if you want to + use a branch other than `master`. For example: @@ -229,19 +297,19 @@ REPO=apjanke/oh-my-zsh BRANCH=edge sh install.sh #### Manual Installation -##### 1. Clone the repository +##### 1. Clone The Repository ```sh git clone https://github.com/ohmyzsh/ohmyzsh.git ~/.oh-my-zsh ``` -##### 2. _Optionally_, backup your existing `~/.zshrc` file +##### 2. _Optionally_, Backup Your Existing `~/.zshrc` File ```sh cp ~/.zshrc ~/.zshrc.orig ``` -##### 3. Create a new zsh configuration file +##### 3. Create A New Zsh Configuration File You can create a new zsh config file by copying the template that we have included for you. @@ -249,7 +317,7 @@ You can create a new zsh config file by copying the template that we have includ cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc ``` -##### 4. Change your default shell +##### 4. Change Your Default Shell ```sh chsh -s $(which zsh) @@ -257,7 +325,7 @@ chsh -s $(which zsh) You must log out from your user session and log back in to see this change. -##### 5. Initialize your new zsh configuration +##### 5. Initialize Your New Zsh Configuration Once you open up a new terminal window, it should load zsh with Oh My Zsh's configuration. @@ -265,20 +333,111 @@ Once you open up a new terminal window, it should load zsh with Oh My Zsh's conf If you have any hiccups installing, here are a few common fixes. -- You _might_ need to modify your `PATH` in `~/.zshrc` if you're not able to find some commands after switching to `oh-my-zsh`. -- If you installed manually or changed the install location, check the `ZSH` environment variable in `~/.zshrc`. +- You _might_ need to modify your `PATH` in `~/.zshrc` if you're not able to find some commands after + switching to `oh-my-zsh`. +- If you installed manually or changed the install location, check the `ZSH` environment variable in + `~/.zshrc`. -### Custom Plugins and Themes +### Custom Plugins And Themes -If you want to override any of the default behaviors, just add a new file (ending in `.zsh`) in the `custom/` directory. +If you want to override any of the default behaviors, just add a new file (ending in `.zsh`) in the `custom/` +directory. -If you have many functions that go well together, you can put them as a `XYZ.plugin.zsh` file in the `custom/plugins/` directory and then enable this plugin. +If you have many functions that go well together, you can put them as a `XYZ.plugin.zsh` file in the +`custom/plugins/` directory and then enable this plugin. -If you would like to override the functionality of a plugin distributed with Oh My Zsh, create a plugin of the same name in the `custom/plugins/` directory and it will be loaded instead of the one in `plugins/`. +If you would like to override the functionality of a plugin distributed with Oh My Zsh, create a plugin of the +same name in the `custom/plugins/` directory and it will be loaded instead of the one in `plugins/`. + +### Enable GNU ls In macOS And FreeBSD Systems + + + +The default behaviour in Oh My Zsh is to use BSD `ls` in macOS and FreeBSD systems. If GNU `ls` is installed +(as `gls` command), you can choose to use it instead. To do it, you can use zstyle-based config before +sourcing `oh-my-zsh.sh`: + +```zsh +zstyle ':omz:lib:theme-and-appearance' gnu-ls yes +``` + +_Note: this is not compatible with `DISABLE_LS_COLORS=true`_ + +### Skip Aliases + + + +If you want to skip default Oh My Zsh aliases (those defined in `lib/*` files) or plugin aliases, you can use +the settings below in your `~/.zshrc` file, **before Oh My Zsh is loaded**. Note that there are many different +ways to skip aliases, depending on your needs. + +```sh +# Skip all aliases, in lib files and enabled plugins +zstyle ':omz:*' aliases no + +# Skip all aliases in lib files +zstyle ':omz:lib:*' aliases no +# Skip only aliases defined in the directories.zsh lib file +zstyle ':omz:lib:directories' aliases no + +# Skip all plugin aliases +zstyle ':omz:plugins:*' aliases no +# Skip only the aliases from the git plugin +zstyle ':omz:plugins:git' aliases no +``` + +You can combine these in other ways taking into account that more specific scopes take precedence: + +```sh +# Skip all plugin aliases, except for the git plugin +zstyle ':omz:plugins:*' aliases no +zstyle ':omz:plugins:git' aliases yes +``` + +A previous version of this feature was using the setting below, which has been removed: + +```sh +zstyle ':omz:directories' aliases no +``` + +Instead, you can now use the following: + +```sh +zstyle ':omz:lib:directories' aliases no +``` + +#### Notice + +> This feature is currently in a testing phase and it may be subject to change in the future. It is also not +> currently compatible with plugin managers such as zpm or zinit, which don't source the init script +> (`oh-my-zsh.sh`) where this feature is implemented in. + +> It is also not currently aware of "aliases" that are defined as functions. Example of such are `gccd`, +> `ggf`, or `ggl` functions from the git plugin. + +### Async git prompt + +Async prompt functions are an experimental feature (included on April 3, 2024) that allows Oh My Zsh to render +prompt information asynchronously. This can improve prompt rendering performance, but it might not work well +with some setups. We hope that's not an issue, but if you're seeing problems with this new feature, you can +turn it off by setting the following in your .zshrc file, before Oh My Zsh is sourced: + +```sh +zstyle ':omz:alpha:lib:git' async-prompt no +``` + +If your problem is that the git prompt just stopped appearing, you can try to force it by setting the following +configuration before `oh-my-zsh.sh` is sourced. If it still does not work, please open an issue with your +case. + +```sh +zstyle ':omz:alpha:lib:git' async-prompt force +``` ## Getting Updates -By default, you will be prompted to check for updates every 2 weeks. You can choose other update modes by adding a line to your `~/.zshrc` file, **before Oh My Zsh is loaded**: +By default, you will be prompted to check for updates every 2 weeks. You can choose other update modes by +adding a line to your `~/.zshrc` file, **before Oh My Zsh is loaded**: 1. Automatic update without confirmation prompt: @@ -307,54 +466,90 @@ zstyle ':omz:update' frequency 7 zstyle ':omz:update' frequency 0 ``` +### Updates Verbosity + +You can also limit the update verbosity with the following settings: + +```sh +zstyle ':omz:update' verbose default # default update prompt + +zstyle ':omz:update' verbose minimal # only few lines + +zstyle ':omz:update' verbose silent # only errors +``` + ### Manual Updates -If you'd like to update at any point in time (maybe someone just released a new plugin and you don't want to wait a week?) you just need to run: +If you'd like to update at any point in time (maybe someone just released a new plugin and you don't want to +wait a week?) you just need to run: ```sh omz update ``` +> [!NOTE] +> If you want to automate this process in a script, you should call directly the `upgrade` script, like this: +> +> ```sh +> $ZSH/tools/upgrade.sh +> ``` +> +> See more options in the [FAQ: How do I update Oh My Zsh?](https://github.com/ohmyzsh/ohmyzsh/wiki/FAQ#how-do-i-update-oh-my-zsh). +> +> **USE OF `omz update --unattended` HAS BEEN REMOVED, AS IT HAS SIDE EFFECTS**. + Magic! 🎉 ## Uninstalling Oh My Zsh Oh My Zsh isn't for everyone. We'll miss you, but we want to make this an easy breakup. -If you want to uninstall `oh-my-zsh`, just run `uninstall_oh_my_zsh` from the command-line. It will remove itself and revert your previous `bash` or `zsh` configuration. +If you want to uninstall `oh-my-zsh`, just run `uninstall_oh_my_zsh` from the command-line. It will remove +itself and revert your previous `bash` or `zsh` configuration. -## How do I contribute to Oh My Zsh? +## How Do I Contribute To Oh My Zsh? Before you participate in our delightful community, please read the [code of conduct](CODE_OF_CONDUCT.md). -I'm far from being a [Zsh](https://www.zsh.org/) expert and suspect there are many ways to improve – if you have ideas on how to make the configuration easier to maintain (and faster), don't hesitate to fork and send pull requests! +I'm far from being a [Zsh](https://www.zsh.org/) expert and suspect there are many ways to improve – if you +have ideas on how to make the configuration easier to maintain (and faster), don't hesitate to fork and send +pull requests! -We also need people to test out pull requests. So take a look through [the open issues](https://github.com/ohmyzsh/ohmyzsh/issues) and help where you can. +We also need people to test out pull requests. So take a look through +[the open issues](https://github.com/ohmyzsh/ohmyzsh/issues) and help where you can. See [Contributing](CONTRIBUTING.md) for more details. -### Do NOT send us themes +### Do Not Send Us Themes -We have (more than) enough themes for the time being. Please add your theme to the [external themes](https://github.com/ohmyzsh/ohmyzsh/wiki/External-themes) wiki page. +We have (more than) enough themes for the time being. Please add your theme to the +[external themes](https://github.com/ohmyzsh/ohmyzsh/wiki/External-themes) wiki page. ## Contributors -Oh My Zsh has a vibrant community of happy users and delightful contributors. Without all the time and help from our contributors, it wouldn't be so awesome. +Oh My Zsh has a vibrant community of happy users and delightful contributors. Without all the time and help +from our contributors, it wouldn't be so awesome. Thank you so much! + + + + ## Follow Us We're on social media: -- [@ohmyzsh](https://twitter.com/ohmyzsh) on Twitter. You should follow it. +- [@ohmyzsh](https://x.com/ohmyzsh) on X (formerly Twitter). You should follow it. - [Facebook](https://www.facebook.com/Oh-My-Zsh-296616263819290/) poke us. - [Instagram](https://www.instagram.com/_ohmyzsh/) tag us in your post showing Oh My Zsh! - [Discord](https://discord.gg/ohmyzsh) to chat with us! ## Merchandise -We have [stickers, shirts, and coffee mugs available](https://shop.planetargon.com/collections/oh-my-zsh?utm_source=github) for you to show off your love of Oh My Zsh. Again, you will become the talk of the town! +We have +[stickers, shirts, and coffee mugs available](https://commitgoods.com/collections/oh-my-zsh?utm_source=github) +for you to show off your love of Oh My Zsh. Again, you will become the talk of the town! ## License @@ -364,4 +559,6 @@ Oh My Zsh is released under the [MIT license](LICENSE.txt). ![Planet Argon](https://pa-github-assets.s3.amazonaws.com/PARGON_logo_digital_COL-small.jpg) -Oh My Zsh was started by the team at [Planet Argon](https://www.planetargon.com/?utm_source=github), a [Ruby on Rails development agency](https://www.planetargon.com/skills/ruby-on-rails-development?utm_source=github). Check out our [other open source projects](https://www.planetargon.com/open-source?utm_source=github). +Oh My Zsh was started by the team at [Planet Argon](https://www.planetargon.com/?utm_source=github), a +[Ruby on Rails development agency](https://www.planetargon.com/services/ruby-on-rails-development?utm_source=github). +Check out our [other open source projects](https://www.planetargon.com/open-source?utm_source=github). diff --git a/zsh/SECURITY.md b/zsh/SECURITY.md index 7e5c8ee..f823584 100644 --- a/zsh/SECURITY.md +++ b/zsh/SECURITY.md @@ -17,8 +17,7 @@ In the near future we will introduce versioning, so expect this section to chang **Do not submit an issue or pull request**: this might reveal the vulnerability. -Instead, you should email the maintainers directly at: [**security@ohmyz.sh**](mailto:security@ohmyz.sh). +Instead, you should use the form to [privately report a vulnerability to us via GitHub](https://github.com/ohmyzsh/ohmyzsh/security/advisories/new) +or email the maintainers directly at: [**security@ohmyz.sh**](mailto:security@ohmyz.sh). We will deal with the vulnerability privately and submit a patch as soon as possible. - -You can also submit your vulnerability report to [huntr.dev](https://huntr.dev/bounties/disclose/?utm_campaign=ohmyzsh%2Fohmyzsh&utm_medium=social&utm_source=github&target=https%3A%2F%2Fgithub.com%2Fohmyzsh%2Fohmyzsh) and see if you can get a bounty reward. diff --git a/zsh/custom/example.zsh b/zsh/custom/example.zsh index c505a96..c194f49 100644 --- a/zsh/custom/example.zsh +++ b/zsh/custom/example.zsh @@ -1,10 +1,12 @@ -# You can put files here to add functionality separated per file, which -# will be ignored by git. -# Files on the custom/ directory will be automatically loaded by the init -# script, in alphabetical order. - -# For example: add yourself some shortcuts to projects you often work on. +# Put files in this folder to add your own custom functionality. +# See: https://github.com/ohmyzsh/ohmyzsh/wiki/Customization +# +# Files in the custom/ directory will be: +# - loaded automatically by the init script, in alphabetical order +# - loaded last, after all built-ins in the lib/ directory, to override them +# - ignored by git by default +# +# Example: add custom/shortcuts.zsh for shortcuts to your local projects # # brainstormr=~/Projects/development/planetargon/brainstormr # cd $brainstormr -# diff --git a/zsh/custom/plugins/example/example.plugin.zsh b/zsh/custom/plugins/example/example.plugin.zsh index 406f274..83611fe 100644 --- a/zsh/custom/plugins/example/example.plugin.zsh +++ b/zsh/custom/plugins/example/example.plugin.zsh @@ -1,2 +1,3 @@ # Add your own custom plugins in the custom/plugins directory. Plugins placed # here will override ones with the same name in the main plugins directory. +# See: https://github.com/ohmyzsh/ohmyzsh/wiki/Customization#overriding-and-adding-plugins diff --git a/zsh/custom/plugins/yandex-cloud/yandex-cloud.plugin.zsh b/zsh/custom/plugins/yandex-cloud/yandex-cloud.plugin.zsh deleted file mode 100644 index 7027bac..0000000 --- a/zsh/custom/plugins/yandex-cloud/yandex-cloud.plugin.zsh +++ /dev/null @@ -1,5 +0,0 @@ -# The next line updates PATH for Yandex Cloud CLI. -if [ -f '$HOME/yandex-cloud/path.bash.inc' ]; then source '$HOME/yandex-cloud/path.bash.inc'; fi - -# The next line enables shell command completion for yc. -if [ -f '$HOME/yandex-cloud/completion.zsh.inc' ]; then source '$HOME/yandex-cloud/completion.zsh.inc'; fi diff --git a/zsh/custom/themes/example.zsh-theme b/zsh/custom/themes/example.zsh-theme index ef8f1c6..5551207 100644 --- a/zsh/custom/themes/example.zsh-theme +++ b/zsh/custom/themes/example.zsh-theme @@ -1,4 +1,6 @@ # Put your custom themes in this folder. +# See: https://github.com/ohmyzsh/ohmyzsh/wiki/Customization#overriding-and-adding-themes +# # Example: PROMPT="%{$fg[red]%}%n%{$reset_color%}@%{$fg[blue]%}%m %{$fg[yellow]%}%~ %{$reset_color%}%% " diff --git a/zsh/lib/async_prompt.zsh b/zsh/lib/async_prompt.zsh new file mode 100644 index 0000000..151e24b --- /dev/null +++ b/zsh/lib/async_prompt.zsh @@ -0,0 +1,145 @@ +# The async code is taken from +# https://github.com/zsh-users/zsh-autosuggestions/blob/master/src/async.zsh +# https://github.com/woefe/git-prompt.zsh/blob/master/git-prompt.zsh + +zmodload zsh/system +autoload -Uz is-at-least + +# For now, async prompt function handlers are set up like so: +# First, define the async function handler and register the handler +# with _omz_register_handler: +# +# function _git_prompt_status_async { +# # Do some expensive operation that outputs to stdout +# } +# _omz_register_handler _git_prompt_status_async +# +# Then add a stub prompt function in `$PROMPT` or similar prompt variables, +# which will show the output of "$_OMZ_ASYNC_OUTPUT[handler_name]": +# +# function git_prompt_status { +# echo -n $_OMZ_ASYNC_OUTPUT[_git_prompt_status_async] +# } +# +# RPROMPT='$(git_prompt_status)' +# +# This API is subject to change and optimization. Rely on it at your own risk. + +function _omz_register_handler { + setopt localoptions noksharrays unset + typeset -ga _omz_async_functions + # we want to do nothing if there's no $1 function or we already set it up + if [[ -z "$1" ]] || (( ! ${+functions[$1]} )) \ + || (( ${_omz_async_functions[(Ie)$1]} )); then + return + fi + _omz_async_functions+=("$1") + # let's add the hook to async_request if it's not there yet + if (( ! ${precmd_functions[(Ie)_omz_async_request]} )) \ + && (( ${+functions[_omz_async_request]})); then + autoload -Uz add-zsh-hook + add-zsh-hook precmd _omz_async_request + fi +} + +# Set up async handlers and callbacks +function _omz_async_request { + setopt localoptions noksharrays unset + local -i ret=$? + typeset -gA _OMZ_ASYNC_FDS _OMZ_ASYNC_PIDS _OMZ_ASYNC_OUTPUT + + # executor runs a subshell for all async requests based on key + local handler + for handler in ${_omz_async_functions}; do + (( ${+functions[$handler]} )) || continue + + local fd=${_OMZ_ASYNC_FDS[$handler]:--1} + local pid=${_OMZ_ASYNC_PIDS[$handler]:--1} + + # If we've got a pending request, cancel it + if (( fd != -1 && pid != -1 )) && { true <&$fd } 2>/dev/null; then + # Close the file descriptor and remove the handler + exec {fd}<&- + zle -F $fd + + # Zsh will make a new process group for the child process only if job + # control is enabled (MONITOR option) + if [[ -o MONITOR ]]; then + # Send the signal to the process group to kill any processes that may + # have been forked by the async function handler + kill -TERM -$pid 2>/dev/null + else + # Kill just the child process since it wasn't placed in a new process + # group. If the async function handler forked any child processes they may + # be orphaned and left behind. + kill -TERM $pid 2>/dev/null + fi + fi + + # Define global variables to store the file descriptor, PID and output + _OMZ_ASYNC_FDS[$handler]=-1 + _OMZ_ASYNC_PIDS[$handler]=-1 + + # Fork a process to fetch the git status and open a pipe to read from it + exec {fd}< <( + # Tell parent process our PID + builtin echo ${sysparams[pid]} + # Set exit code for the handler if used + () { return $ret } + # Run the async function handler + $handler + ) + + # Save FD for handler + _OMZ_ASYNC_FDS[$handler]=$fd + + # There's a weird bug here where ^C stops working unless we force a fork + # See https://github.com/zsh-users/zsh-autosuggestions/issues/364 + # and https://github.com/zsh-users/zsh-autosuggestions/pull/612 + is-at-least 5.8 || command true + + # Save the PID from the handler child process + read -u $fd "_OMZ_ASYNC_PIDS[$handler]" + + # When the fd is readable, call the response handler + zle -F "$fd" _omz_async_callback + done +} + +# Called when new data is ready to be read from the pipe +function _omz_async_callback() { + emulate -L zsh + + local fd=$1 # First arg will be fd ready for reading + local err=$2 # Second arg will be passed in case of error + + if [[ -z "$err" || "$err" == "hup" ]]; then + # Get handler name from fd + local handler="${(k)_OMZ_ASYNC_FDS[(r)$fd]}" + + # Store old output which is supposed to be already printed + local old_output="${_OMZ_ASYNC_OUTPUT[$handler]}" + + # Read output from fd + IFS= read -r -u $fd -d '' "_OMZ_ASYNC_OUTPUT[$handler]" + + # Repaint prompt if output has changed + if [[ "$old_output" != "${_OMZ_ASYNC_OUTPUT[$handler]}" ]]; then + zle .reset-prompt + zle -R + fi + + # Close the fd + exec {fd}<&- + fi + + # Always remove the handler + zle -F "$fd" + + # Unset global FD variable to prevent closing user created FDs in the precmd hook + _OMZ_ASYNC_FDS[$handler]=-1 + _OMZ_ASYNC_PIDS[$handler]=-1 +} + +autoload -Uz add-zsh-hook +add-zsh-hook precmd _omz_async_request diff --git a/zsh/lib/bzr.zsh b/zsh/lib/bzr.zsh index 005a165..78273d5 100644 --- a/zsh/lib/bzr.zsh +++ b/zsh/lib/bzr.zsh @@ -1,10 +1,14 @@ ## Bazaar integration -## Just works with the GIT integration just add $(bzr_prompt_info) to the PROMPT +## Just works with the GIT integration. Add $(bzr_prompt_info) to the PROMPT function bzr_prompt_info() { - BZR_CB=`bzr nick 2> /dev/null | grep -v "ERROR" | cut -d ":" -f2 | awk -F / '{print "bzr::"$1}'` - if [ -n "$BZR_CB" ]; then - BZR_DIRTY="" - [[ -n `bzr status` ]] && BZR_DIRTY=" %{$fg[red]%} * %{$fg[green]%}" - echo "$ZSH_THEME_SCM_PROMPT_PREFIX$BZR_CB$BZR_DIRTY$ZSH_THEME_GIT_PROMPT_SUFFIX" - fi -} \ No newline at end of file + local bzr_branch + bzr_branch=$(bzr nick 2>/dev/null) || return + + if [[ -n "$bzr_branch" ]]; then + local bzr_dirty="" + if [[ -n $(bzr status 2>/dev/null) ]]; then + bzr_dirty=" %{$fg[red]%}*%{$reset_color%}" + fi + printf "%s%s%s%s" "$ZSH_THEME_SCM_PROMPT_PREFIX" "bzr::${bzr_branch##*:}" "$bzr_dirty" "$ZSH_THEME_GIT_PROMPT_SUFFIX" + fi +} diff --git a/zsh/lib/cli.zsh b/zsh/lib/cli.zsh index fed00d2..55938ba 100644 --- a/zsh/lib/cli.zsh +++ b/zsh/lib/cli.zsh @@ -1,6 +1,7 @@ #!/usr/bin/env zsh function omz { + setopt localoptions noksharrays [[ $# -gt 0 ]] || { _omz::help return 1 @@ -11,7 +12,7 @@ function omz { # Subcommand functions start with _ so that they don't # appear as completion entries when looking for `omz` - (( $+functions[_omz::$command] )) || { + (( ${+functions[_omz::$command]} )) || { _omz::help return 1 } @@ -27,6 +28,7 @@ function _omz { 'plugin:Manage plugins' 'pr:Manage Oh My Zsh Pull Requests' 'reload:Reload the current zsh session' + 'shop:Open the Oh My Zsh shop' 'theme:Manage themes' 'update:Update Oh My Zsh' 'version:Show the version' @@ -71,6 +73,10 @@ function _omz { local -aU plugins plugins=("$ZSH"/plugins/*/{_*,*.plugin.zsh}(-.N:h:t) "$ZSH_CUSTOM"/plugins/*/{_*,*.plugin.zsh}(-.N:h:t)) _describe 'plugin' plugins ;; + plugin::list) + local -a opts + opts=('--enabled:List enabled plugins only') + _describe -o 'options' opts ;; theme::(set|use)) local -aU themes themes=("$ZSH"/themes/*.zsh-theme(-.N:t:r) "$ZSH_CUSTOM"/**/*.zsh-theme(-.N:r:gs:"$ZSH_CUSTOM"/themes/:::gs:"$ZSH_CUSTOM"/:::)) @@ -168,6 +174,7 @@ Available commands: plugin Manage plugins pr Manage Oh My Zsh Pull Requests reload Reload the current zsh session + shop Open the Oh My Zsh shop theme Manage themes update Update Oh My Zsh version Show the version @@ -192,7 +199,7 @@ EOF return 1 fi - "$ZSH/tools/changelog.sh" "$version" "${2:-}" "$format" + ZSH="$ZSH" command zsh -f "$ZSH/tools/changelog.sh" "$version" "${2:-}" "$format" } function _omz::plugin { @@ -205,7 +212,7 @@ Available commands: disable Disable plugin(s) enable Enable plugin(s) info Get information of a plugin - list List all available Oh My Zsh plugins + list [--enabled] List Oh My Zsh plugins load Load plugin(s) EOF @@ -241,10 +248,18 @@ function _omz::plugin::disable { # Remove plugins substitution awk script local awk_subst_plugins="\ - gsub(/[ \t]+(${(j:|:)dis_plugins})/, \"\") # with spaces before - gsub(/(${(j:|:)dis_plugins})[ \t]+/, \"\") # with spaces after - gsub(/\((${(j:|:)dis_plugins})\)/, \"\") # without spaces (only plugin) + gsub(/[ \t]+(${(j:|:)dis_plugins})[ \t]+/, \" \") # with spaces before or after + gsub(/[ \t]+(${(j:|:)dis_plugins})$/, \"\") # with spaces before and EOL + gsub(/^(${(j:|:)dis_plugins})[ \t]+/, \"\") # with BOL and spaces after + + gsub(/\((${(j:|:)dis_plugins})[ \t]+/, \"(\") # with parenthesis before and spaces after + gsub(/[ \t]+(${(j:|:)dis_plugins})\)/, \")\") # with spaces before or parenthesis after + gsub(/\((${(j:|:)dis_plugins})\)/, \"()\") # with only parentheses + + gsub(/^(${(j:|:)dis_plugins})\)/, \")\") # with BOL and closing parenthesis + gsub(/\((${(j:|:)dis_plugins})$/, \"(\") # with opening parenthesis and EOL " + # Disable plugins awk script local awk_script=" # if plugins=() is in oneline form, substitute disabled plugins and go to next line @@ -336,20 +351,40 @@ function _omz::plugin::enable { next } -# if plugins=() is in multiline form, enable multi flag +# if plugins=() is in multiline form, enable multi flag and indent by default with 2 spaces /^[ \t]*plugins=\(/ { multi=1 + indent=\" \" + print \$0 + next } # if multi flag is enabled and we find a valid closing parenthesis, -# add new plugins and disable multi flag +# add new plugins with proper indent and disable multi flag multi == 1 && /^[^#]*\)/ { multi=0 - sub(/\)/, \" $add_plugins&\") + split(\"$add_plugins\",p,\" \") + for (i in p) { + print indent p[i] + } print \$0 next } +# if multi flag is enabled and we didnt find a closing parenthesis, +# get the indentation level to match when adding plugins +multi == 1 && /^[^#]*/ { + indent=\"\" + for (i = 1; i <= length(\$0); i++) { + char=substr(\$0, i, 1) + if (char == \" \" || char == \"\t\") { + indent = indent char + } else { + break + } + } +} + { print \$0 } " @@ -389,8 +424,23 @@ function _omz::plugin::info { local readme for readme in "$ZSH_CUSTOM/plugins/$1/README.md" "$ZSH/plugins/$1/README.md"; do if [[ -f "$readme" ]]; then - (( ${+commands[less]} )) && less "$readme" || cat "$readme" - return 0 + # If being piped, just cat the README + if [[ ! -t 1 ]]; then + cat "$readme" + return $? + fi + + # Enrich the README display depending on the tools we have + # - glow: https://github.com/charmbracelet/glow + # - bat: https://github.com/sharkdp/bat + # - less: typical pager command + case 1 in + ${+commands[glow]}) glow -p "$readme" ;; + ${+commands[bat]}) bat -l md --style plain "$readme" ;; + ${+commands[less]}) less "$readme" ;; + *) cat "$readme" ;; + esac + return $? fi done @@ -405,8 +455,21 @@ function _omz::plugin::info { function _omz::plugin::list { local -a custom_plugins builtin_plugins - custom_plugins=("$ZSH_CUSTOM"/plugins/*(-/N:t)) - builtin_plugins=("$ZSH"/plugins/*(-/N:t)) + + # If --enabled is provided, only list what's enabled + if [[ "$1" == "--enabled" ]]; then + local plugin + for plugin in "${plugins[@]}"; do + if [[ -d "${ZSH_CUSTOM}/plugins/${plugin}" ]]; then + custom_plugins+=("${plugin}") + elif [[ -d "${ZSH}/plugins/${plugin}" ]]; then + builtin_plugins+=("${plugin}") + fi + done + else + custom_plugins=("$ZSH_CUSTOM"/plugins/*(-/N:t)) + builtin_plugins=("$ZSH"/plugins/*(-/N:t)) + fi # If the command is being piped, print all found line by line if [[ ! -t 1 ]]; then @@ -448,7 +511,7 @@ function _omz::plugin::load { if [[ ! -f "$base/_$plugin" && ! -f "$base/$plugin.plugin.zsh" ]]; then _omz::log warn "'$plugin' is not a valid plugin" continue - # It it is a valid plugin, add its directory to $fpath unless it is already there + # It is a valid plugin, add its directory to $fpath unless it is already there elif (( ! ${fpath[(Ie)$base]} )); then fpath=("$base" $fpath) fi @@ -560,10 +623,48 @@ function _omz::pr::test { done (( $found )) || { - _omz::log error "could not found the ohmyzsh git remote. Aborting..." + _omz::log error "could not find the ohmyzsh git remote. Aborting..." return 1 } + # Check if Pull Request has the "testers needed" label + _omz::log info "checking if PR #$1 has the 'testers needed' label..." + local pr_json label label_id="MDU6TGFiZWw4NzY1NTkwNA==" + pr_json=$( + curl -fsSL \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/repos/ohmyzsh/ohmyzsh/pulls/$1" + ) + + if [[ $? -gt 0 || -z "$pr_json" ]]; then + _omz::log error "error when trying to fetch PR #$1 from GitHub." + return 1 + fi + + # Check if the label is present with jq or grep + if (( $+commands[jq] )); then + label="$(command jq ".labels.[] | select(.node_id == \"$label_id\")" <<< "$pr_json")" + else + label="$(command grep "\"$label_id\"" <<< "$pr_json" 2>/dev/null)" + fi + + # If a maintainer hasn't labeled the PR to test, explain the security risk + if [[ -z "$label" ]]; then + _omz::log warn "PR #$1 does not have the 'testers needed' label. This means that the PR" + _omz::log warn "has not been reviewed by a maintainer and may contain malicious code." + + # Ask for explicit confirmation: user needs to type "yes" to continue + _omz::log prompt "Do you want to continue testing it? [yes/N] " + builtin read -r + if [[ "${REPLY:l}" != yes ]]; then + _omz::log error "PR test canceled. Please ask a maintainer to review and label the PR." + return 1 + else + _omz::log warn "Continuing to check out and test PR #$1. Be careful!" + fi + fi + # Fetch pull request head _omz::log info "fetching PR #$1 to ohmyzsh/pull-$1..." command git fetch -f "$remote" refs/pull/$1/head:ohmyzsh/pull-$1 || { @@ -622,6 +723,15 @@ function _omz::pr::test { ) } +function _omz::shop { + local shop_url="https://commitgoods.com/collections/oh-my-zsh" + + _omz::log info "Opening Oh My Zsh shop in your browser..." + _omz::log info "$shop_url" + + open_command "$shop_url" +} + function _omz::reload { # Delete current completion cache command rm -f $_comp_dumpfile $ZSH_COMPDUMP @@ -773,14 +883,28 @@ function _omz::theme::use { } function _omz::update { - local last_commit=$(builtin cd -q "$ZSH"; git rev-parse HEAD) + # Check if git command is available + (( $+commands[git] )) || { + _omz::log error "git is not installed. Aborting..." + return 1 + } + + # Check if --unattended was passed + [[ "$1" != --unattended ]] || { + _omz::log error "the \`\e[2m--unattended\e[0m\` flag is no longer supported, use the \`\e[2mupgrade.sh\e[0m\` script instead." + _omz::log error "for more information see https://github.com/ohmyzsh/ohmyzsh/wiki/FAQ#how-do-i-update-oh-my-zsh" + return 1 + } + + local last_commit=$(builtin cd -q "$ZSH"; git rev-parse HEAD 2>/dev/null) + [[ $? -eq 0 ]] || { + _omz::log error "\`$ZSH\` is not a git directory. Aborting..." + return 1 + } # Run update script - if [[ "$1" != --unattended ]]; then - ZSH="$ZSH" command zsh -f "$ZSH/tools/upgrade.sh" --interactive || return $? - else - ZSH="$ZSH" command zsh -f "$ZSH/tools/upgrade.sh" || return $? - fi + zstyle -s ':omz:update' verbose verbose_mode || verbose_mode=default + ZSH="$ZSH" command zsh -f "$ZSH/tools/upgrade.sh" -i -v $verbose_mode || return $? # Update last updated file zmodload zsh/datetime @@ -789,7 +913,7 @@ function _omz::update { command rm -rf "$ZSH/log/update.lock" # Restart the zsh session if there were changes - if [[ "$1" != --unattended && "$(builtin cd -q "$ZSH"; git rev-parse HEAD)" != "$last_commit" ]]; then + if [[ "$(builtin cd -q "$ZSH"; git rev-parse HEAD)" != "$last_commit" ]]; then # Old zsh versions don't have ZSH_ARGZERO local zsh="${ZSH_ARGZERO:-${functrace[-1]%:*}}" # Check whether to run a login shell diff --git a/zsh/lib/clipboard.zsh b/zsh/lib/clipboard.zsh index ad83fc4..27e8152 100644 --- a/zsh/lib/clipboard.zsh +++ b/zsh/lib/clipboard.zsh @@ -57,9 +57,12 @@ function detect-clipboard() { elif [[ "${OSTYPE}" == (cygwin|msys)* ]]; then function clipcopy() { cat "${1:-/dev/stdin}" > /dev/clipboard; } function clippaste() { cat /dev/clipboard; } + elif (( $+commands[clip.exe] )) && (( $+commands[powershell.exe] )); then + function clipcopy() { cat "${1:-/dev/stdin}" | clip.exe; } + function clippaste() { powershell.exe -noprofile -command Get-Clipboard; } elif [ -n "${WAYLAND_DISPLAY:-}" ] && (( ${+commands[wl-copy]} )) && (( ${+commands[wl-paste]} )); then function clipcopy() { cat "${1:-/dev/stdin}" | wl-copy &>/dev/null &|; } - function clippaste() { wl-paste; } + function clippaste() { wl-paste --no-newline; } elif [ -n "${DISPLAY:-}" ] && (( ${+commands[xsel]} )); then function clipcopy() { cat "${1:-/dev/stdin}" | xsel --clipboard --input; } function clippaste() { xsel --clipboard --output; } @@ -79,11 +82,8 @@ function detect-clipboard() { function clipcopy() { cat "${1:-/dev/stdin}" | termux-clipboard-set; } function clippaste() { termux-clipboard-get; } elif [ -n "${TMUX:-}" ] && (( ${+commands[tmux]} )); then - function clipcopy() { tmux load-buffer "${1:--}"; } + function clipcopy() { tmux load-buffer -w "${1:--}"; } function clippaste() { tmux save-buffer -; } - elif [[ $(uname -r) = *icrosoft* ]]; then - function clipcopy() { cat "${1:-/dev/stdin}" | clip.exe; } - function clippaste() { powershell.exe -noprofile -command Get-Clipboard; } else function _retry_clipboard_detection_or_fail() { local clipcmd="${1}"; shift @@ -100,8 +100,8 @@ function detect-clipboard() { fi } -# Detect at startup. A non-zero exit here indicates that the dummy clipboards were set, -# which is not really an error. If the user calls them, they will attempt to redetect -# (for example, perhaps the user has now installed xclip) and then either print an error -# or proceed successfully. -detect-clipboard || true +function clipcopy clippaste { + unfunction clipcopy clippaste + detect-clipboard || true # let one retry + "$0" "$@" +} diff --git a/zsh/lib/compfix.zsh b/zsh/lib/compfix.zsh index b09b283..2fe9d9e 100644 --- a/zsh/lib/compfix.zsh +++ b/zsh/lib/compfix.zsh @@ -13,7 +13,7 @@ function handle_completion_insecurities() { # /usr/share/zsh/5.0.6 # # Since the ignorable first line is printed to stderr and thus not captured, - # stderr is squelched to prevent this output from leaking to the user. + # stderr is squelched to prevent this output from leaking to the user. local -aU insecure_dirs insecure_dirs=( ${(f@):-"$(compaudit 2>/dev/null)"} ) diff --git a/zsh/lib/completion.zsh b/zsh/lib/completion.zsh index 2c56954..3823c25 100644 --- a/zsh/lib/completion.zsh +++ b/zsh/lib/completion.zsh @@ -18,9 +18,9 @@ if [[ "$CASE_SENSITIVE" = true ]]; then zstyle ':completion:*' matcher-list 'r:|=*' 'l:|=* r:|=*' else if [[ "$HYPHEN_INSENSITIVE" = true ]]; then - zstyle ':completion:*' matcher-list 'm:{a-zA-Z-_}={A-Za-z_-}' 'r:|=*' 'l:|=* r:|=*' + zstyle ':completion:*' matcher-list 'm:{[:lower:][:upper:]-_}={[:upper:][:lower:]_-}' 'r:|=*' 'l:|=* r:|=*' else - zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' 'r:|=*' 'l:|=* r:|=*' + zstyle ':completion:*' matcher-list 'm:{[:lower:][:upper:]}={[:upper:][:lower:]}' 'r:|=*' 'l:|=* r:|=*' fi fi unset CASE_SENSITIVE HYPHEN_INSENSITIVE @@ -40,7 +40,7 @@ fi # disable named-directories autocompletion zstyle ':completion:*:cd:*' tag-order local-directories directory-stack path-directories -# Use caching so that commands like apt and dpkg complete are useable +# Use caching so that commands like apt and dpkg complete are usable zstyle ':completion:*' use-cache yes zstyle ':completion:*' cache-path $ZSH_CACHE_DIR @@ -49,7 +49,7 @@ zstyle ':completion:*:*:*:users' ignored-patterns \ adm amanda apache at avahi avahi-autoipd beaglidx bin cacti canna \ clamav daemon dbus distcache dnsmasq dovecot fax ftp games gdm \ gkrellmd gopher hacluster haldaemon halt hsqldb ident junkbust kdm \ - ldap lp mail mailman mailnull man messagebus mldonkey mysql nagios \ + ldap lp mail mailman mailnull man messagebus mldonkey mysql nagios \ named netdump news nfsnobody nobody nscd ntp nut nx obsrun openvpn \ operator pcap polkitd postfix postgres privoxy pulse pvm quagga radvd \ rpc rpcuser rpm rtkit scard shutdown squid sshd statd svn sync tftp \ diff --git a/zsh/lib/correction.zsh b/zsh/lib/correction.zsh index 4259d34..ba9664f 100644 --- a/zsh/lib/correction.zsh +++ b/zsh/lib/correction.zsh @@ -1,13 +1,8 @@ if [[ "$ENABLE_CORRECTION" == "true" ]]; then alias cp='nocorrect cp' - alias ebuild='nocorrect ebuild' - alias gist='nocorrect gist' - alias heroku='nocorrect heroku' - alias hpodder='nocorrect hpodder' alias man='nocorrect man' alias mkdir='nocorrect mkdir' alias mv='nocorrect mv' - alias mysql='nocorrect mysql' alias sudo='nocorrect sudo' alias su='nocorrect su' diff --git a/zsh/lib/diagnostics.zsh b/zsh/lib/diagnostics.zsh index eaeba7d..d67e6fa 100644 --- a/zsh/lib/diagnostics.zsh +++ b/zsh/lib/diagnostics.zsh @@ -30,7 +30,7 @@ # # This is written in a defensive style so it still works (and can detect) cases when # basic functionality like echo and which have been redefined. In particular, almost -# everything is invoked with "builtin" or "command", to work in the face of user +# everything is invoked with "builtin" or "command", to work in the face of user # redefinitions. # # OPTIONS @@ -59,7 +59,7 @@ function omz_diagnostic_dump() { emulate -L zsh builtin echo "Generating diagnostic dump; please be patient..." - + local thisfcn=omz_diagnostic_dump local -A opts local opt_verbose opt_noverbose opt_outfile @@ -90,7 +90,7 @@ function omz_diagnostic_dump() { builtin echo builtin echo Diagnostic dump file created at: "$outfile" builtin echo - builtin echo To share this with OMZ developers, post it as a gist on GitHub + builtin echo To share this with OMZ developers, post it as a gist on GitHub builtin echo at "https://gist.github.com" and share the link to the gist. builtin echo builtin echo "WARNING: This dump file contains all your zsh and omz configuration files," @@ -105,8 +105,8 @@ function _omz_diag_dump_one_big_text() { builtin echo oh-my-zsh diagnostic dump builtin echo builtin echo $outfile - builtin echo - + builtin echo + # Basic system and zsh information command date command uname -a @@ -151,7 +151,7 @@ function _omz_diag_dump_one_big_text() { # Core command definitions _omz_diag_dump_check_core_commands || return 1 - builtin echo + builtin echo # ZSH Process state builtin echo Process state: @@ -167,7 +167,7 @@ function _omz_diag_dump_one_big_text() { #TODO: Should this include `env` instead of or in addition to `export`? builtin echo Exported: builtin echo $(builtin export | command sed 's/=.*//') - builtin echo + builtin echo builtin echo Locale: command locale builtin echo @@ -181,7 +181,7 @@ function _omz_diag_dump_one_big_text() { builtin echo builtin echo 'compaudit output:' compaudit - builtin echo + builtin echo builtin echo '$fpath directories:' command ls -lad $fpath builtin echo @@ -224,7 +224,7 @@ function _omz_diag_dump_one_big_text() { local cfgfile cfgfiles # Some files for bash that zsh does not use are intentionally included # to help with diagnosing behavior differences between bash and zsh - cfgfiles=( /etc/zshenv /etc/zprofile /etc/zshrc /etc/zlogin /etc/zlogout + cfgfiles=( /etc/zshenv /etc/zprofile /etc/zshrc /etc/zlogin /etc/zlogout $zdotdir/.zshenv $zdotdir/.zprofile $zdotdir/.zshrc $zdotdir/.zlogin $zdotdir/.zlogout ~/.zsh.pre-oh-my-zsh /etc/bashrc /etc/profile ~/.bashrc ~/.profile ~/.bash_profile ~/.bash_logout ) @@ -258,8 +258,8 @@ function _omz_diag_dump_check_core_commands() { # (For back-compatibility, if any of these are newish, they should be removed, # or at least made conditional on the version of the current running zsh.) # "history" is also excluded because OMZ is known to redefine that - reserved_words=( do done esac then elif else fi for case if while function - repeat time until select coproc nocorrect foreach end '!' '[[' '{' '}' + reserved_words=( do done esac then elif else fi for case if while function + repeat time until select coproc nocorrect foreach end '!' '[[' '{' '}' ) builtins=( alias autoload bg bindkey break builtin bye cd chdir command comparguments compcall compctl compdescribe compfiles compgroups compquote comptags @@ -331,7 +331,7 @@ function _omz_diag_dump_os_specific_version() { case "$OSTYPE" in darwin*) osname=$(command sw_vers -productName) - osver=$(command sw_vers -productVersion) + osver=$(command sw_vers -productVersion) builtin echo "OS Version: $osname $osver build $(sw_vers -buildVersion)" ;; cygwin) diff --git a/zsh/lib/directories.zsh b/zsh/lib/directories.zsh index c62f564..8927a56 100644 --- a/zsh/lib/directories.zsh +++ b/zsh/lib/directories.zsh @@ -1,8 +1,10 @@ # Changing/making/removing directory +setopt auto_cd setopt auto_pushd setopt pushd_ignore_dups setopt pushdminus + alias -g ...='../..' alias -g ....='../../..' alias -g .....='../../../..' diff --git a/zsh/lib/functions.zsh b/zsh/lib/functions.zsh index dfcc4d9..330b0e3 100644 --- a/zsh/lib/functions.zsh +++ b/zsh/lib/functions.zsh @@ -5,7 +5,7 @@ function zsh_stats() { } function uninstall_oh_my_zsh() { - env ZSH="$ZSH" sh "$ZSH/tools/uninstall.sh" + command env ZSH="$ZSH" sh "$ZSH/tools/uninstall.sh" } function upgrade_oh_my_zsh() { @@ -23,6 +23,9 @@ function open_command() { linux*) [[ "$(uname -r)" != *icrosoft* ]] && open_cmd='nohup xdg-open' || { open_cmd='cmd.exe /c start ""' [[ -e "$1" ]] && { 1="$(wslpath -w "${1:a}")" || return 1 } + [[ "$1" = (http|https)://* ]] && { + 1="$(echo "$1" | sed -E 's/([&|()<>^])/^\1/g')" || return 1 + } } ;; msys*) open_cmd='start ""' ;; *) echo "Platform $OSTYPE not supported" @@ -30,6 +33,13 @@ function open_command() { ;; esac + # If a URL is passed, $BROWSER might be set to a local browser within SSH. + # See https://github.com/ohmyzsh/ohmyzsh/issues/11098 + if [[ -n "$BROWSER" && "$1" = (http|https)://* ]]; then + "$BROWSER" "$@" + return + fi + ${=open_cmd} "$@" &>/dev/null } @@ -50,14 +60,26 @@ function takeurl() { cd "$thedir" } +function takezip() { + local data thedir + data="$(mktemp)" + curl -L "$1" > "$data" + unzip "$data" -d "./" + thedir="$(unzip -l "$data" | awk 'NR==4 {print $4}' | sed 's/\/.*//')" + rm "$data" + cd "$thedir" +} + function takegit() { git clone "$1" cd "$(basename ${1%%.git})" } function take() { - if [[ $1 =~ ^(https?|ftp).*\.tar\.(gz|bz2|xz)$ ]]; then + if [[ $1 =~ ^(https?|ftp).*\.(tar\.(gz|bz2|xz)|tgz)$ ]]; then takeurl "$1" + elif [[ $1 =~ ^(https?|ftp).*\.(zip)$ ]]; then + takezip "$1" elif [[ $1 =~ ^([A-Za-z0-9]\+@|https?|git|ssh|ftps?|rsync).*\.git/?$ ]]; then takegit "$1" else @@ -153,6 +175,8 @@ zmodload zsh/langinfo # -P causes spaces to be encoded as '%20' instead of '+' function omz_urlencode() { emulate -L zsh + setopt norematchpcre + local -a opts zparseopts -D -E -a opts r m P @@ -175,6 +199,8 @@ function omz_urlencode() { fi # Use LC_CTYPE=C to process text byte-by-byte + # Note that this doesn't work in Termux, as it only has UTF-8 locale. + # Characters will be processed as UTF-8, which is fine for URLs. local i byte ord LC_ALL=C export LC_ALL local reserved=';/?:@&=+$,' @@ -199,6 +225,9 @@ function omz_urlencode() { else if [[ "$byte" == " " && -n $spaces_as_plus ]]; then url_str+="+" + elif [[ "$PREFIX" = *com.termux* ]]; then + # Termux does not have non-UTF8 locales, so just send the UTF-8 character directly + url_str+="$byte" else ord=$(( [##16] #byte )) url_str+="%$ord" diff --git a/zsh/lib/git.zsh b/zsh/lib/git.zsh index be9fa7e..8d38f32 100644 --- a/zsh/lib/git.zsh +++ b/zsh/lib/git.zsh @@ -1,3 +1,5 @@ +autoload -Uz is-at-least + # The git prompt's git commands are read-only and should not interfere with # other processes. This environment variable is equivalent to running with `git # --no-optional-locks`, but falls back gracefully for older versions of git. @@ -9,16 +11,21 @@ function __git_prompt_git() { GIT_OPTIONAL_LOCKS=0 command git "$@" } -function git_prompt_info() { +function _omz_git_prompt_info() { # If we are on a folder not tracked by git, get out. # Otherwise, check for hide-info at global and local repository level if ! __git_prompt_git rev-parse --git-dir &> /dev/null \ - || [[ "$(__git_prompt_git config --get oh-my-zsh.hide-info 2>/dev/null)" == 1 ]]; then + || [[ "$(__git_prompt_git config --get oh-my-zsh.hide-info 2>/dev/null)" == 1 ]]; then return 0 fi + # Get either: + # - the current branch name + # - the tag name if we are on a tag + # - the short SHA of the current commit local ref ref=$(__git_prompt_git symbolic-ref --short HEAD 2> /dev/null) \ + || ref=$(__git_prompt_git describe --tags --exact-match HEAD 2> /dev/null) \ || ref=$(__git_prompt_git rev-parse --short HEAD 2> /dev/null) \ || return 0 @@ -32,6 +39,172 @@ function git_prompt_info() { echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref:gs/%/%%}${upstream:gs/%/%%}$(parse_git_dirty)${ZSH_THEME_GIT_PROMPT_SUFFIX}" } +function _omz_git_prompt_status() { + [[ "$(__git_prompt_git config --get oh-my-zsh.hide-status 2>/dev/null)" = 1 ]] && return + + # Maps a git status prefix to an internal constant + # This cannot use the prompt constants, as they may be empty + local -A prefix_constant_map + prefix_constant_map=( + '\?\? ' 'UNTRACKED' + 'A ' 'ADDED' + 'M ' 'MODIFIED' + 'MM ' 'MODIFIED' + ' M ' 'MODIFIED' + 'AM ' 'MODIFIED' + ' T ' 'MODIFIED' + 'R ' 'RENAMED' + ' D ' 'DELETED' + 'D ' 'DELETED' + 'UU ' 'UNMERGED' + 'ahead' 'AHEAD' + 'behind' 'BEHIND' + 'diverged' 'DIVERGED' + 'stashed' 'STASHED' + ) + + # Maps the internal constant to the prompt theme + local -A constant_prompt_map + constant_prompt_map=( + 'UNTRACKED' "$ZSH_THEME_GIT_PROMPT_UNTRACKED" + 'ADDED' "$ZSH_THEME_GIT_PROMPT_ADDED" + 'MODIFIED' "$ZSH_THEME_GIT_PROMPT_MODIFIED" + 'RENAMED' "$ZSH_THEME_GIT_PROMPT_RENAMED" + 'DELETED' "$ZSH_THEME_GIT_PROMPT_DELETED" + 'UNMERGED' "$ZSH_THEME_GIT_PROMPT_UNMERGED" + 'AHEAD' "$ZSH_THEME_GIT_PROMPT_AHEAD" + 'BEHIND' "$ZSH_THEME_GIT_PROMPT_BEHIND" + 'DIVERGED' "$ZSH_THEME_GIT_PROMPT_DIVERGED" + 'STASHED' "$ZSH_THEME_GIT_PROMPT_STASHED" + ) + + # The order that the prompt displays should be added to the prompt + local status_constants + status_constants=( + UNTRACKED ADDED MODIFIED RENAMED DELETED + STASHED UNMERGED AHEAD BEHIND DIVERGED + ) + + local status_text + status_text="$(__git_prompt_git status --porcelain -b 2> /dev/null)" + + # Don't continue on a catastrophic failure + if [[ $? -eq 128 ]]; then + return 1 + fi + + # A lookup table of each git status encountered + local -A statuses_seen + + if __git_prompt_git rev-parse --verify refs/stash &>/dev/null; then + statuses_seen[STASHED]=1 + fi + + local status_lines + status_lines=("${(@f)${status_text}}") + + # If the tracking line exists, get and parse it + if [[ "$status_lines[1]" =~ "^## [^ ]+ \[(.*)\]" ]]; then + local branch_statuses + branch_statuses=("${(@s/,/)match}") + for branch_status in $branch_statuses; do + if [[ ! $branch_status =~ "(behind|diverged|ahead) ([0-9]+)?" ]]; then + continue + fi + local last_parsed_status=$prefix_constant_map[$match[1]] + statuses_seen[$last_parsed_status]=$match[2] + done + fi + + # For each status prefix, do a regex comparison + for status_prefix in "${(@k)prefix_constant_map}"; do + local status_constant="${prefix_constant_map[$status_prefix]}" + local status_regex=$'(^|\n)'"$status_prefix" + + if [[ "$status_text" =~ $status_regex ]]; then + statuses_seen[$status_constant]=1 + fi + done + + # Display the seen statuses in the order specified + local status_prompt + for status_constant in $status_constants; do + if (( ${+statuses_seen[$status_constant]} )); then + local next_display=$constant_prompt_map[$status_constant] + status_prompt="$next_display$status_prompt" + fi + done + + echo $status_prompt +} + +# Use async version if setting is enabled, or unset but zsh version is at least 5.0.6. +# This avoids async prompt issues caused by previous zsh versions: +# - https://github.com/ohmyzsh/ohmyzsh/issues/12331 +# - https://github.com/ohmyzsh/ohmyzsh/issues/12360 +# TODO(2024-06-12): @mcornella remove workaround when CentOS 7 reaches EOL +local _style +if zstyle -t ':omz:alpha:lib:git' async-prompt \ + || { is-at-least 5.0.6 && zstyle -T ':omz:alpha:lib:git' async-prompt }; then + function git_prompt_info() { + if [[ -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]}" ]]; then + echo -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]}" + fi + } + + function git_prompt_status() { + if [[ -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]}" ]]; then + echo -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]}" + fi + } + + # Conditionally register the async handler, only if it's needed in $PROMPT + # or any of the other prompt variables + function _defer_async_git_register() { + # Check if git_prompt_info is used in a prompt variable + case "${PS1}:${PS2}:${PS3}:${PS4}:${RPROMPT}:${RPS1}:${RPS2}:${RPS3}:${RPS4}" in + *(\$\(git_prompt_info\)|\`git_prompt_info\`)*) + _omz_register_handler _omz_git_prompt_info + ;; + esac + + case "${PS1}:${PS2}:${PS3}:${PS4}:${RPROMPT}:${RPS1}:${RPS2}:${RPS3}:${RPS4}" in + *(\$\(git_prompt_status\)|\`git_prompt_status\`)*) + _omz_register_handler _omz_git_prompt_status + ;; + esac + + add-zsh-hook -d precmd _defer_async_git_register + unset -f _defer_async_git_register + } + + # Register the async handler first. This needs to be done before + # the async request prompt is run + precmd_functions=(_defer_async_git_register $precmd_functions) +elif zstyle -s ':omz:alpha:lib:git' async-prompt _style && [[ $_style == "force" ]]; then + function git_prompt_info() { + if [[ -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]}" ]]; then + echo -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_info]}" + fi + } + + function git_prompt_status() { + if [[ -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]}" ]]; then + echo -n "${_OMZ_ASYNC_OUTPUT[_omz_git_prompt_status]}" + fi + } + + _omz_register_handler _omz_git_prompt_info + _omz_register_handler _omz_git_prompt_status +else + function git_prompt_info() { + _omz_git_prompt_info + } + function git_prompt_status() { + _omz_git_prompt_status + } +fi + # Checks if working tree is dirty function parse_git_dirty() { local STATUS @@ -104,6 +277,18 @@ function git_current_branch() { echo ${ref#refs/heads/} } +# Outputs the name of the previously checked out branch +# Usage example: git pull origin $(git_previous_branch) +# rev-parse --symbolic-full-name @{-1} only prints if it is a branch +function git_previous_branch() { + local ref + ref=$(__git_prompt_git rev-parse --quiet --symbolic-full-name @{-1} 2> /dev/null) + local ret=$? + if [[ $ret != 0 ]] || [[ -z $ref ]]; then + return # no git repo or non-branch previous ref + fi + echo ${ref#refs/heads/} +} # Gets the number of commits ahead from remote function git_commits_ahead() { @@ -160,105 +345,6 @@ function git_prompt_long_sha() { SHA=$(__git_prompt_git rev-parse HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER" } -function git_prompt_status() { - [[ "$(__git_prompt_git config --get oh-my-zsh.hide-status 2>/dev/null)" = 1 ]] && return - - # Maps a git status prefix to an internal constant - # This cannot use the prompt constants, as they may be empty - local -A prefix_constant_map - prefix_constant_map=( - '\?\? ' 'UNTRACKED' - 'A ' 'ADDED' - 'M ' 'ADDED' - 'MM ' 'MODIFIED' - ' M ' 'MODIFIED' - 'AM ' 'MODIFIED' - ' T ' 'MODIFIED' - 'R ' 'RENAMED' - ' D ' 'DELETED' - 'D ' 'DELETED' - 'UU ' 'UNMERGED' - 'ahead' 'AHEAD' - 'behind' 'BEHIND' - 'diverged' 'DIVERGED' - 'stashed' 'STASHED' - ) - - # Maps the internal constant to the prompt theme - local -A constant_prompt_map - constant_prompt_map=( - 'UNTRACKED' "$ZSH_THEME_GIT_PROMPT_UNTRACKED" - 'ADDED' "$ZSH_THEME_GIT_PROMPT_ADDED" - 'MODIFIED' "$ZSH_THEME_GIT_PROMPT_MODIFIED" - 'RENAMED' "$ZSH_THEME_GIT_PROMPT_RENAMED" - 'DELETED' "$ZSH_THEME_GIT_PROMPT_DELETED" - 'UNMERGED' "$ZSH_THEME_GIT_PROMPT_UNMERGED" - 'AHEAD' "$ZSH_THEME_GIT_PROMPT_AHEAD" - 'BEHIND' "$ZSH_THEME_GIT_PROMPT_BEHIND" - 'DIVERGED' "$ZSH_THEME_GIT_PROMPT_DIVERGED" - 'STASHED' "$ZSH_THEME_GIT_PROMPT_STASHED" - ) - - # The order that the prompt displays should be added to the prompt - local status_constants - status_constants=( - UNTRACKED ADDED MODIFIED RENAMED DELETED - STASHED UNMERGED AHEAD BEHIND DIVERGED - ) - - local status_text - status_text="$(__git_prompt_git status --porcelain -b 2> /dev/null)" - - # Don't continue on a catastrophic failure - if [[ $? -eq 128 ]]; then - return 1 - fi - - # A lookup table of each git status encountered - local -A statuses_seen - - if __git_prompt_git rev-parse --verify refs/stash &>/dev/null; then - statuses_seen[STASHED]=1 - fi - - local status_lines - status_lines=("${(@f)${status_text}}") - - # If the tracking line exists, get and parse it - if [[ "$status_lines[1]" =~ "^## [^ ]+ \[(.*)\]" ]]; then - local branch_statuses - branch_statuses=("${(@s/,/)match}") - for branch_status in $branch_statuses; do - if [[ ! $branch_status =~ "(behind|diverged|ahead) ([0-9]+)?" ]]; then - continue - fi - local last_parsed_status=$prefix_constant_map[$match[1]] - statuses_seen[$last_parsed_status]=$match[2] - done - fi - - # For each status prefix, do a regex comparison - for status_prefix in ${(k)prefix_constant_map}; do - local status_constant="${prefix_constant_map[$status_prefix]}" - local status_regex=$'(^|\n)'"$status_prefix" - - if [[ "$status_text" =~ $status_regex ]]; then - statuses_seen[$status_constant]=1 - fi - done - - # Display the seen statuses in the order specified - local status_prompt - for status_constant in $status_constants; do - if (( ${+statuses_seen[$status_constant]} )); then - local next_display=$constant_prompt_map[$status_constant] - status_prompt="$next_display$status_prompt" - fi - done - - echo $status_prompt -} - # Outputs the name of the current user # Usage example: $(git_current_user_name) function git_current_user_name() { diff --git a/zsh/lib/grep.zsh b/zsh/lib/grep.zsh index 54e0f69..1a70de7 100644 --- a/zsh/lib/grep.zsh +++ b/zsh/lib/grep.zsh @@ -10,7 +10,7 @@ else } # Ignore these folders (if the necessary grep flags are available) - EXC_FOLDERS="{.bzr,CVS,.git,.hg,.svn,.idea,.tox}" + EXC_FOLDERS="{.bzr,CVS,.git,.hg,.svn,.idea,.tox,.venv,venv}" # Check for --exclude-dir, otherwise check for --exclude. If --exclude # isn't available, --color won't be either (they were released at the same @@ -24,8 +24,8 @@ else if [[ -n "$GREP_OPTIONS" ]]; then # export grep, egrep and fgrep settings alias grep="grep $GREP_OPTIONS" - alias egrep="grep -E $GREP_OPTIONS" - alias fgrep="grep -F $GREP_OPTIONS" + alias egrep="grep -E" + alias fgrep="grep -F" # write to cache file if cache directory is writable if [[ -w "$ZSH_CACHE_DIR" ]]; then diff --git a/zsh/lib/history.zsh b/zsh/lib/history.zsh index 7940769..781a0e9 100644 --- a/zsh/lib/history.zsh +++ b/zsh/lib/history.zsh @@ -1,19 +1,27 @@ ## History wrapper function omz_history { - local clear list - zparseopts -E c=clear l=list + # parse arguments and remove from $@ + local clear list stamp REPLY + zparseopts -E -D c=clear l=list f=stamp E=stamp i=stamp t:=stamp if [[ -n "$clear" ]]; then # if -c provided, clobber the history file - echo -n >| "$HISTFILE" + + # confirm action before deleting history + print -nu2 "This action will irreversibly delete your command history. Are you sure? [y/N] " + builtin read -E + [[ "$REPLY" = [yY] ]] || return 0 + + print -nu2 >| "$HISTFILE" fc -p "$HISTFILE" - echo >&2 History file deleted. - elif [[ -n "$list" ]]; then - # if -l provided, run as if calling `fc' directly - builtin fc "$@" + + print -u2 History file deleted. + elif [[ $# -eq 0 ]]; then + # if no arguments provided, show full history starting from 1 + builtin fc "${stamp[@]}" -l 1 else - # unless a number is provided, show all history events (starting from 1) - [[ ${@[-1]-} = *[0-9]* ]] && builtin fc -l "$@" || builtin fc -l "$@" 1 + # otherwise, run `fc -l` with a custom format + builtin fc "${stamp[@]}" -l "$@" fi } diff --git a/zsh/lib/key-bindings.zsh b/zsh/lib/key-bindings.zsh index aaa7304..0d2cecb 100644 --- a/zsh/lib/key-bindings.zsh +++ b/zsh/lib/key-bindings.zsh @@ -32,19 +32,26 @@ if [[ -n "${terminfo[knp]}" ]]; then fi # Start typing + [Up-Arrow] - fuzzy find history forward -if [[ -n "${terminfo[kcuu1]}" ]]; then - autoload -U up-line-or-beginning-search - zle -N up-line-or-beginning-search +autoload -U up-line-or-beginning-search +zle -N up-line-or-beginning-search +bindkey -M emacs "^[[A" up-line-or-beginning-search +bindkey -M viins "^[[A" up-line-or-beginning-search +bindkey -M vicmd "^[[A" up-line-or-beginning-search +if [[ -n "${terminfo[kcuu1]}" ]]; then bindkey -M emacs "${terminfo[kcuu1]}" up-line-or-beginning-search bindkey -M viins "${terminfo[kcuu1]}" up-line-or-beginning-search bindkey -M vicmd "${terminfo[kcuu1]}" up-line-or-beginning-search fi -# Start typing + [Down-Arrow] - fuzzy find history backward -if [[ -n "${terminfo[kcud1]}" ]]; then - autoload -U down-line-or-beginning-search - zle -N down-line-or-beginning-search +# Start typing + [Down-Arrow] - fuzzy find history backward +autoload -U down-line-or-beginning-search +zle -N down-line-or-beginning-search + +bindkey -M emacs "^[[B" down-line-or-beginning-search +bindkey -M viins "^[[B" down-line-or-beginning-search +bindkey -M vicmd "^[[B" down-line-or-beginning-search +if [[ -n "${terminfo[kcud1]}" ]]; then bindkey -M emacs "${terminfo[kcud1]}" down-line-or-beginning-search bindkey -M viins "${terminfo[kcud1]}" down-line-or-beginning-search bindkey -M vicmd "${terminfo[kcud1]}" down-line-or-beginning-search @@ -105,12 +112,12 @@ bindkey -M vicmd '^[[1;5D' backward-word bindkey '\ew' kill-region # [Esc-w] - Kill from the cursor to the mark -bindkey -s '\el' 'ls\n' # [Esc-l] - run command: ls +bindkey -s '\el' '^q ls\n' # [Esc-l] - run command: ls bindkey '^r' history-incremental-search-backward # [Ctrl-r] - Search backward incrementally for a specified string. The string may begin with ^ to anchor the search to the beginning of the line. bindkey ' ' magic-space # [Space] - don't do history expansion -# Edit the current command line in $EDITOR +# Edit the current command line in $VISUAL (or $EDITOR / `vi` if not set) autoload -U edit-command-line zle -N edit-command-line bindkey '\C-x\C-e' edit-command-line diff --git a/zsh/lib/misc.zsh b/zsh/lib/misc.zsh index 1f63708..054485f 100644 --- a/zsh/lib/misc.zsh +++ b/zsh/lib/misc.zsh @@ -15,11 +15,17 @@ if [[ $DISABLE_MAGIC_FUNCTIONS != true ]]; then done fi -## jobs -setopt long_list_jobs +setopt multios # enable redirect to multiple streams: echo >file1 >file2 +setopt long_list_jobs # show long list format job notifications +setopt interactivecomments # recognize comments -env_default 'PAGER' 'less' -env_default 'LESS' '-R' +# define pager depending on what is available (less or more) +if (( ${+commands[less]} )); then + env_default 'PAGER' 'less' + env_default 'LESS' '-R' +elif (( ${+commands[more]} )); then + env_default 'PAGER' 'more' +fi ## super user alias alias _='sudo ' @@ -30,6 +36,3 @@ if (( $+commands[ack-grep] )); then elif (( $+commands[ack] )); then alias afind='ack -il' fi - -# recognize comments -setopt interactivecomments diff --git a/zsh/lib/prompt_info_functions.zsh b/zsh/lib/prompt_info_functions.zsh index e553584..722ae58 100644 --- a/zsh/lib/prompt_info_functions.zsh +++ b/zsh/lib/prompt_info_functions.zsh @@ -18,7 +18,9 @@ function chruby_prompt_info \ vi_mode_prompt_info \ virtualenv_prompt_info \ jenv_prompt_info \ + azure_prompt_info \ tf_prompt_info \ + conda_prompt_info \ { return 1 } @@ -39,5 +41,5 @@ ZSH_THEME_RVM_PROMPT_OPTIONS="i v g" # use this to enable users to see their ruby version, no matter which # version management system they use function ruby_prompt_info() { - echo $(rvm_prompt_info || rbenv_prompt_info || chruby_prompt_info) + echo "$(rvm_prompt_info || rbenv_prompt_info || chruby_prompt_info)" } diff --git a/zsh/lib/spectrum.zsh b/zsh/lib/spectrum.zsh index 97f5c36..31e3779 100644 --- a/zsh/lib/spectrum.zsh +++ b/zsh/lib/spectrum.zsh @@ -7,6 +7,7 @@ typeset -AHg FX FG BG FX=( reset "%{%}" bold "%{%}" no-bold "%{%}" + dim "%{%}" no-dim "%{%}" italic "%{%}" no-italic "%{%}" underline "%{%}" no-underline "%{%}" blink "%{%}" no-blink "%{%}" diff --git a/zsh/lib/termsupport.zsh b/zsh/lib/termsupport.zsh index 80ca7ef..852a543 100644 --- a/zsh/lib/termsupport.zsh +++ b/zsh/lib/termsupport.zsh @@ -17,7 +17,7 @@ function title { : ${2=$1} case "$TERM" in - cygwin|xterm*|putty*|rxvt*|konsole*|ansi|mlterm*|alacritty|st*|foot) + cygwin|xterm*|putty*|rxvt*|konsole*|ansi|mlterm*|alacritty*|st*|foot*|contour*|wezterm*) print -Pn "\e]2;${2:q}\a" # set window name print -Pn "\e]1;${1:q}\a" # set tab name ;; @@ -47,13 +47,13 @@ fi # Runs before showing the prompt function omz_termsupport_precmd { - [[ "${DISABLE_AUTO_TITLE:-}" != true ]] || return + [[ "${DISABLE_AUTO_TITLE:-}" != true ]] || return 0 title "$ZSH_THEME_TERM_TAB_TITLE_IDLE" "$ZSH_THEME_TERM_TITLE_IDLE" } # Runs before executing the command function omz_termsupport_preexec { - [[ "${DISABLE_AUTO_TITLE:-}" != true ]] || return + [[ "${DISABLE_AUTO_TITLE:-}" != true ]] || return 0 emulate -L zsh setopt extended_glob @@ -109,28 +109,56 @@ if [[ -z "$INSIDE_EMACS" || "$INSIDE_EMACS" = vterm ]]; then add-zsh-hook preexec omz_termsupport_preexec fi -# Keep Apple Terminal.app's current working directory updated -# Based on this answer: https://superuser.com/a/315029 -# With extra fixes to handle multibyte chars and non-UTF-8 locales +# Keep terminal emulator's current working directory correct, +# even if the current working directory path contains symbolic links +# +# References: +# - Apple's Terminal.app: https://superuser.com/a/315029 +# - iTerm2: https://iterm2.com/documentation-escape-codes.html (iTerm2 Extension / CurrentDir+RemoteHost) +# - Konsole: https://bugs.kde.org/show_bug.cgi?id=327720#c1 +# - libvte (gnome-terminal, mate-terminal, …): https://bugzilla.gnome.org/show_bug.cgi?id=675987#c14 +# Apparently it had a bug before ~2012 were it would display the unknown OSC 7 code +# +# As of May 2021 mlterm, PuTTY, rxvt, screen, termux & xterm simply ignore the unknown OSC. -if [[ "$TERM_PROGRAM" == "Apple_Terminal" ]] && [[ -z "$INSIDE_EMACS" ]]; then - # Emits the control sequence to notify Terminal.app of the cwd - # Identifies the directory using a file: URI scheme, including - # the host name to disambiguate local vs. remote paths. - function update_terminalapp_cwd() { - emulate -L zsh - - # Percent-encode the host and path names. - local URL_HOST URL_PATH - URL_HOST="$(omz_urlencode -P $HOST)" || return 1 - URL_PATH="$(omz_urlencode -P $PWD)" || return 1 - - # Undocumented Terminal.app-specific control sequence - printf '\e]7;%s\a' "file://$URL_HOST$URL_PATH" - } - - # Use a precmd hook instead of a chpwd hook to avoid contaminating output - add-zsh-hook precmd update_terminalapp_cwd - # Run once to get initial cwd set - update_terminalapp_cwd +# Don't define the function if we're inside Emacs or in an SSH session (#11696) +if [[ -n "$INSIDE_EMACS" || -n "$SSH_CLIENT" || -n "$SSH_TTY" ]]; then + return fi + +# Don't define the function if we're in an unsupported terminal +case "$TERM" in + # all of these either process OSC 7 correctly or ignore entirely + xterm*|putty*|rxvt*|konsole*|mlterm*|alacritty*|screen*|tmux*) ;; + contour*|foot*) ;; + *) + # Terminal.app and iTerm2 process OSC 7 correctly + case "$TERM_PROGRAM" in + Apple_Terminal|iTerm.app) ;; + *) return ;; + esac ;; +esac + +# Emits the control sequence to notify many terminal emulators +# of the cwd +# +# Identifies the directory using a file: URI scheme, including +# the host name to disambiguate local vs. remote paths. +function omz_termsupport_cwd { + setopt localoptions unset + # Percent-encode the host and path names. + local URL_HOST URL_PATH + URL_HOST="$(omz_urlencode -P $HOST)" || return 1 + URL_PATH="$(omz_urlencode -P $PWD)" || return 1 + + # Konsole errors if the HOST is provided + [[ -z "$KONSOLE_PROFILE_NAME" && -z "$KONSOLE_DBUS_SESSION" ]] || URL_HOST="" + + # common control sequence (OSC 7) to set current host and path + printf "\e]7;file://%s%s\e\\" "${URL_HOST}" "${URL_PATH}" +} + +# Use a precmd hook instead of a chpwd hook to avoid contaminating output +# i.e. when a script or function changes directory without `cd -q`, chpwd +# will be called the output may be swallowed by the script or function. +add-zsh-hook precmd omz_termsupport_cwd diff --git a/zsh/lib/tests/cli.test.zsh b/zsh/lib/tests/cli.test.zsh new file mode 100644 index 0000000..9ee5cd2 --- /dev/null +++ b/zsh/lib/tests/cli.test.zsh @@ -0,0 +1,169 @@ +#!/usr/bin/zsh -df + +run_awk() { + local -a dis_plugins=(${=1}) + local input_text="$2" + + (( ! DEBUG )) || set -xv + + local awk_subst_plugins="\ + gsub(/[ \t]+(${(j:|:)dis_plugins})[ \t]+/, \" \") # with spaces before or after + gsub(/[ \t]+(${(j:|:)dis_plugins})$/, \"\") # with spaces before and EOL + gsub(/^(${(j:|:)dis_plugins})[ \t]+/, \"\") # with BOL and spaces after + + gsub(/\((${(j:|:)dis_plugins})[ \t]+/, \"(\") # with parenthesis before and spaces after + gsub(/[ \t]+(${(j:|:)dis_plugins})\)/, \")\") # with spaces before or parenthesis after + gsub(/\((${(j:|:)dis_plugins})\)/, \"()\") # with only parentheses + + gsub(/^(${(j:|:)dis_plugins})\)/, \")\") # with BOL and closing parenthesis + gsub(/\((${(j:|:)dis_plugins})$/, \"(\") # with opening parenthesis and EOL + " + # Disable plugins awk script + local awk_script=" + # if plugins=() is in oneline form, substitute disabled plugins and go to next line + /^[ \t]*plugins=\([^#]+\).*\$/ { + $awk_subst_plugins + print \$0 + next + } + + # if plugins=() is in multiline form, enable multi flag and disable plugins if they're there + /^[ \t]*plugins=\(/ { + multi=1 + $awk_subst_plugins + print \$0 + next + } + + # if multi flag is enabled and we find a valid closing parenthesis, remove plugins and disable multi flag + multi == 1 && /^[^#]*\)/ { + multi=0 + $awk_subst_plugins + print \$0 + next + } + + multi == 1 && length(\$0) > 0 { + $awk_subst_plugins + if (length(\$0) > 0) print \$0 + next + } + + { print \$0 } + " + + command awk "$awk_script" <<< "$input_text" + + (( ! DEBUG )) || set +xv +} + +# runs awk against stdin, checks if the resulting file is not empty and then checks if the file has valid zsh syntax +run_awk_and_test() { + local description="$1" + local plugins_to_disable="$2" + local input_text="$3" + local expected_output="$4" + + local tmpfile==(:) + + { + print -u2 "Test: $description" + DEBUG=0 run_awk "$plugins_to_disable" "$input_text" >| $tmpfile + + if [[ ! -s "$tmpfile" ]]; then + print -u2 "\e[31mError\e[0m: output file empty" + return 1 + fi + + if ! zsh -n $tmpfile; then + print -u2 "\e[31mError\e[0m: zsh syntax error" + diff -u $tmpfile <(echo "$expected_output") + return 1 + fi + + if ! diff -u --color=always $tmpfile <(echo "$expected_output"); then + if (( DEBUG )); then + print -u2 "" + DEBUG=1 run_awk "$plugins_to_disable" "$input_text" + print -u2 "" + fi + print -u2 "\e[31mError\e[0m: output file does not match expected output" + return 1 + fi + + print -u2 "\e[32mSuccess\e[0m" + } always { + print -u2 "" + command rm -f "$tmpfile" + } +} + +# These tests are for the `omz plugin disable` command +run_awk_and_test \ + "it should delete a single plugin in oneline format" \ + "git" \ + "plugins=(git)" \ + "plugins=()" + +run_awk_and_test \ + "it should delete a single plugin in multiline format" \ + "github" \ +"plugins=( + github +)" \ +"plugins=( +)" + +run_awk_and_test \ + "it should delete multiple plugins in oneline format" \ + "github git z" \ + "plugins=(github git z)" \ + "plugins=()" + +run_awk_and_test \ + "it should delete multiple plugins in multiline format" \ + "github git z" \ +"plugins=( + github + git + z +)" \ +"plugins=( +)" + +run_awk_and_test \ + "it should delete a single plugin among multiple in oneline format" \ + "git" \ + "plugins=(github git z)" \ + "plugins=(github z)" + +run_awk_and_test \ + "it should delete a single plugin among multiple in multiline format" \ + "git" \ +"plugins=( + github + git + z +)" \ +"plugins=( + github + z +)" + +run_awk_and_test \ + "it should delete multiple plugins in mixed format" \ + "git z" \ +"plugins=(github +git z)" \ +"plugins=(github +)" + +run_awk_and_test \ + "it should delete multiple plugins in mixed format 2" \ + "github z" \ +"plugins=(github + git +z)" \ +"plugins=( + git +)" diff --git a/zsh/lib/theme-and-appearance.zsh b/zsh/lib/theme-and-appearance.zsh index 00947f7..5cfa2e6 100644 --- a/zsh/lib/theme-and-appearance.zsh +++ b/zsh/lib/theme-and-appearance.zsh @@ -1,59 +1,81 @@ -# ls colors +# Sets color variable such as $fg, $bg, $color and $reset_color autoload -U colors && colors -# Enable ls colors +# Expand variables and commands in PROMPT variables +setopt prompt_subst + +# Prompt function theming defaults +ZSH_THEME_GIT_PROMPT_PREFIX="git:(" # Beginning of the git prompt, before the branch name +ZSH_THEME_GIT_PROMPT_SUFFIX=")" # End of the git prompt +ZSH_THEME_GIT_PROMPT_DIRTY="*" # Text to display if the branch is dirty +ZSH_THEME_GIT_PROMPT_CLEAN="" # Text to display if the branch is clean +ZSH_THEME_RUBY_PROMPT_PREFIX="(" +ZSH_THEME_RUBY_PROMPT_SUFFIX=")" + + +# Use diff --color if available +if command diff --color /dev/null{,} &>/dev/null; then + function diff { + command diff --color "$@" + } +fi + +# Don't set ls coloring if disabled +[[ "$DISABLE_LS_COLORS" != true ]] || return 0 + +# Default coloring for BSD-based ls export LSCOLORS="Gxfxcxdxbxegedabagacad" -# TODO organise this chaotic logic - -if [[ "$DISABLE_LS_COLORS" != "true" ]]; then - # Find the option for using colors in ls, depending on the version - if [[ "$OSTYPE" == netbsd* ]]; then - # On NetBSD, test if "gls" (GNU ls) is installed (this one supports colors); - # otherwise, leave ls as is, because NetBSD's ls doesn't support -G - gls --color -d . &>/dev/null && alias ls='gls --color=tty' - elif [[ "$OSTYPE" == openbsd* ]]; then - # On OpenBSD, "gls" (ls from GNU coreutils) and "colorls" (ls from base, - # with color and multibyte support) are available from ports. "colorls" - # will be installed on purpose and can't be pulled in by installing - # coreutils, so prefer it to "gls". - gls --color -d . &>/dev/null && alias ls='gls --color=tty' - colorls -G -d . &>/dev/null && alias ls='colorls -G' - elif [[ "$OSTYPE" == (darwin|freebsd)* ]]; then - # this is a good alias, it works by default just using $LSCOLORS - ls -G . &>/dev/null && alias ls='ls -G' - - # only use coreutils ls if there is a dircolors customization present ($LS_COLORS or .dircolors file) - # otherwise, gls will use the default color scheme which is ugly af - [[ -n "$LS_COLORS" || -f "$HOME/.dircolors" ]] && gls --color -d . &>/dev/null && alias ls='gls --color=tty' +# Default coloring for GNU-based ls +if [[ -z "$LS_COLORS" ]]; then + # Define LS_COLORS via dircolors if available. Otherwise, set a default + # equivalent to LSCOLORS (generated via https://geoff.greer.fm/lscolors) + if (( $+commands[dircolors] )); then + [[ -f "$HOME/.dircolors" ]] \ + && source <(dircolors -b "$HOME/.dircolors") \ + || source <(dircolors -b) else - # For GNU ls, we use the default ls color theme. They can later be overwritten by themes. - if [[ -z "$LS_COLORS" ]]; then - (( $+commands[dircolors] )) && eval "$(dircolors -b)" - fi - - ls --color -d . &>/dev/null && alias ls='ls --color=tty' || { ls -G . &>/dev/null && alias ls='ls -G' } - - # Take advantage of $LS_COLORS for completion as well. - zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}" + export LS_COLORS="di=1;36:ln=35:so=32:pi=33:ex=31:bd=34;46:cd=34;43:su=30;41:sg=30;46:tw=30;42:ow=30;43" fi fi -# enable diff color if possible. -if command diff --color /dev/null /dev/null &>/dev/null; then - alias diff='diff --color' -fi +function test-ls-args { + # Usage: test-ls-args cmd args... + # e.g. test-ls-args gls --color + command "$@" /dev/null &>/dev/null +} -setopt auto_cd -setopt multios -setopt prompt_subst +# Find the option for using colors in ls, depending on the version +case "$OSTYPE" in + netbsd*) + # On NetBSD, test if `gls` (GNU ls) is installed (this one supports colors); + # otherwise, leave ls as is, because NetBSD's ls doesn't support -G + test-ls-args gls --color && alias ls='gls --color=tty' + ;; + openbsd*) + # On OpenBSD, `gls` (ls from GNU coreutils) and `colorls` (ls from base, + # with color and multibyte support) are available from ports. + # `colorls` will be installed on purpose and can't be pulled in by installing + # coreutils (which might be installed for ), so prefer it to `gls`. + test-ls-args gls --color && alias ls='gls --color=tty' + test-ls-args colorls -G && alias ls='colorls -G' + ;; + (darwin|freebsd)*) + # This alias works by default just using $LSCOLORS + test-ls-args ls -G && alias ls='ls -G' + # Only use GNU ls if installed and there are user defaults for $LS_COLORS, + # as the default coloring scheme is not very pretty + zstyle -t ':omz:lib:theme-and-appearance' gnu-ls \ + && test-ls-args gls --color \ + && alias ls='gls --color=tty' + ;; + *) + if test-ls-args ls --color; then + alias ls='ls --color=tty' + elif test-ls-args ls -G; then + alias ls='ls -G' + fi + ;; +esac -[[ -n "$WINDOW" ]] && SCREEN_NO="%B$WINDOW%b " || SCREEN_NO="" - -# git theming default: Variables for theming the git info prompt -ZSH_THEME_GIT_PROMPT_PREFIX="git:(" # Prefix at the very beginning of the prompt, before the branch name -ZSH_THEME_GIT_PROMPT_SUFFIX=")" # At the very end of the prompt -ZSH_THEME_GIT_PROMPT_DIRTY="*" # Text to display if the branch is dirty -ZSH_THEME_GIT_PROMPT_CLEAN="" # Text to display if the branch is clean -ZSH_THEME_RUBY_PROMPT_PREFIX="(" -ZSH_THEME_RUBY_PROMPT_SUFFIX=")" +unfunction test-ls-args diff --git a/zsh/lib/vcs_info.zsh b/zsh/lib/vcs_info.zsh index e60938c..be6d32e 100644 --- a/zsh/lib/vcs_info.zsh +++ b/zsh/lib/vcs_info.zsh @@ -38,7 +38,7 @@ # due to malicious input as a consequence of CVE-2021-45444, which affects # zsh versions from 5.0.3 to 5.8. # -autoload -Uz +X regexp-replace VCS_INFO_formats 2>/dev/null || return +autoload -Uz +X regexp-replace VCS_INFO_formats 2>/dev/null || return 0 # We use $tmp here because it's already a local variable in VCS_INFO_formats typeset PATCH='for tmp (base base-name branch misc revision subdir) hook_com[$tmp]="${hook_com[$tmp]//\%/%%}"' diff --git a/zsh/oh-my-zsh.sh b/zsh/oh-my-zsh.sh index 29d39ca..3e547d3 100644 --- a/zsh/oh-my-zsh.sh +++ b/zsh/oh-my-zsh.sh @@ -1,14 +1,14 @@ +# ANSI formatting function (\033[m) +# 0: reset, 1: bold, 4: underline, 22: no bold, 24: no underline, 31: red, 33: yellow +omz_f() { + [ $# -gt 0 ] || return + IFS=";" printf "\033[%sm" $* +} +# If stdout is not a terminal ignore all formatting +[ -t 1 ] || omz_f() { :; } + # Protect against non-zsh execution of Oh My Zsh (use POSIX syntax here) [ -n "$ZSH_VERSION" ] || { - # ANSI formatting function (\033[m) - # 0: reset, 1: bold, 4: underline, 22: no bold, 24: no underline, 31: red, 33: yellow - omz_f() { - [ $# -gt 0 ] || return - IFS=";" printf "\033[%sm" $* - } - # If stdout is not a terminal ignore all formatting - [ -t 1 ] || omz_f() { :; } - omz_ptree() { # Get process tree of the current process pid=$$; pids="$pid" @@ -38,14 +38,25 @@ return 1 } +# Check if in emulation mode, if so early return +# https://github.com/ohmyzsh/ohmyzsh/issues/11686 +[[ "$(emulate)" = zsh ]] || { + printf "$(omz_f 1 31)Error:$(omz_f 22) Oh My Zsh can't be loaded in \`$(emulate)\` emulation mode.$(omz_f 0)\n" >&2 + return 1 +} + +unset -f omz_f + # If ZSH is not defined, use the current script's directory. -[[ -z "$ZSH" ]] && export ZSH="${${(%):-%x}:a:h}" +[[ -n "$ZSH" ]] || export ZSH="${${(%):-%x}:a:h}" + +# Set ZSH_CUSTOM to the path where your custom config files +# and plugins exists, or else we will use the default custom/ +[[ -n "$ZSH_CUSTOM" ]] || ZSH_CUSTOM="$ZSH/custom" # Set ZSH_CACHE_DIR to the path where cache files should be created # or else we will use the default cache/ -if [[ -z "$ZSH_CACHE_DIR" ]]; then - ZSH_CACHE_DIR="$ZSH/cache" -fi +[[ -n "$ZSH_CACHE_DIR" ]] || ZSH_CACHE_DIR="$ZSH/cache" # Make sure $ZSH_CACHE_DIR is writable, otherwise use a directory in $HOME if [[ ! -w "$ZSH_CACHE_DIR" ]]; then @@ -54,27 +65,19 @@ fi # Create cache and completions dir and add to $fpath mkdir -p "$ZSH_CACHE_DIR/completions" -(( ${fpath[(Ie)"$ZSH_CACHE_DIR/completions"]} )) || fpath=("$ZSH_CACHE_DIR/completions" $fpath) +(( ${fpath[(Ie)$ZSH_CACHE_DIR/completions]} )) || fpath=("$ZSH_CACHE_DIR/completions" $fpath) # Check for updates on initial load... -if [[ "$DISABLE_AUTO_UPDATE" != true ]]; then - source "$ZSH/tools/check_for_upgrade.sh" -fi +source "$ZSH/tools/check_for_upgrade.sh" # Initializes Oh My Zsh # add a function path -fpath=("$ZSH/functions" "$ZSH/completions" $fpath) +fpath=($ZSH/{functions,completions} $ZSH_CUSTOM/{functions,completions} $fpath) # Load all stock functions (from $fpath files) called below. autoload -U compaudit compinit zrecompile -# Set ZSH_CUSTOM to the path where your custom config files -# and plugins exists, or else we will use the default custom/ -if [[ -z "$ZSH_CUSTOM" ]]; then - ZSH_CUSTOM="$ZSH/custom" -fi - is_plugin() { local base_dir=$1 local name=$2 @@ -96,8 +99,8 @@ done # Figure out the SHORT hostname if [[ "$OSTYPE" = darwin* ]]; then - # macOS's $HOST changes with dhcp, etc. Use ComputerName if possible. - SHORT_HOST=$(scutil --get ComputerName 2>/dev/null) || SHORT_HOST="${HOST/.*/}" + # macOS's $HOST changes with dhcp, etc. Use LocalHostName if possible. + SHORT_HOST=$(scutil --get LocalHostName 2>/dev/null) || SHORT_HOST="${HOST/.*/}" else SHORT_HOST="${HOST/.*/}" fi @@ -143,24 +146,62 @@ fi unset zcompdump_revision zcompdump_fpath zcompdump_refresh # zcompile the completion dump file if the .zwc is older or missing. -zrecompile -q -p "$ZSH_COMPDUMP" && command rm -f "$ZSH_COMPDUMP.zwc.old" +if command mkdir "${ZSH_COMPDUMP}.lock" 2>/dev/null; then + zrecompile -q -p "$ZSH_COMPDUMP" + command rm -rf "$ZSH_COMPDUMP.zwc.old" "${ZSH_COMPDUMP}.lock" +fi -# Load all of the config files in ~/oh-my-zsh that end in .zsh +_omz_source() { + local context filepath="$1" + + # Construct zstyle context based on path + case "$filepath" in + lib/*) context="lib:${filepath:t:r}" ;; # :t = lib_name.zsh, :r = lib_name + plugins/*) context="plugins:${filepath:h:t}" ;; # :h = plugins/plugin_name, :t = plugin_name + esac + + local disable_aliases=0 + zstyle -T ":omz:${context}" aliases || disable_aliases=1 + + # Back up alias names prior to sourcing + local -A aliases_pre galiases_pre + if (( disable_aliases )); then + aliases_pre=("${(@kv)aliases}") + galiases_pre=("${(@kv)galiases}") + fi + + # Source file from $ZSH_CUSTOM if it exists, otherwise from $ZSH + if [[ -f "$ZSH_CUSTOM/$filepath" ]]; then + source "$ZSH_CUSTOM/$filepath" + elif [[ -f "$ZSH/$filepath" ]]; then + source "$ZSH/$filepath" + fi + + # Unset all aliases that don't appear in the backed up list of aliases + if (( disable_aliases )); then + if (( #aliases_pre )); then + aliases=("${(@kv)aliases_pre}") + else + (( #aliases )) && unalias "${(@k)aliases}" + fi + if (( #galiases_pre )); then + galiases=("${(@kv)galiases_pre}") + else + (( #galiases )) && unalias "${(@k)galiases}" + fi + fi +} + +# Load all of the lib files in ~/.oh-my-zsh/lib that end in .zsh # TIP: Add files you don't want in git to .gitignore -for config_file ("$ZSH"/lib/*.zsh); do - custom_config_file="$ZSH_CUSTOM/lib/${config_file:t}" - [[ -f "$custom_config_file" ]] && config_file="$custom_config_file" - source "$config_file" +for lib_file ("$ZSH"/lib/*.zsh); do + _omz_source "lib/${lib_file:t}" done -unset custom_config_file +unset lib_file # Load all of the plugins that were defined in ~/.zshrc for plugin ($plugins); do - if [[ -f "$ZSH_CUSTOM/plugins/$plugin/$plugin.plugin.zsh" ]]; then - source "$ZSH_CUSTOM/plugins/$plugin/$plugin.plugin.zsh" - elif [[ -f "$ZSH/plugins/$plugin/$plugin.plugin.zsh" ]]; then - source "$ZSH/plugins/$plugin/$plugin.plugin.zsh" - fi + _omz_source "plugins/$plugin/$plugin.plugin.zsh" done unset plugin @@ -188,3 +229,6 @@ if [[ -n "$ZSH_THEME" ]]; then echo "[oh-my-zsh] theme '$ZSH_THEME' not found" fi fi + +# set completion colors to be the same as `ls`, after theme has been loaded +[[ -z "$LS_COLORS" ]] || zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}" diff --git a/zsh/plugins/1password/1password.plugin.zsh b/zsh/plugins/1password/1password.plugin.zsh index 941523c..e8f91f8 100644 --- a/zsh/plugins/1password/1password.plugin.zsh +++ b/zsh/plugins/1password/1password.plugin.zsh @@ -1,9 +1,15 @@ # Do nothing if op is not installed (( ${+commands[op]} )) || return -# Load op completion -eval "$(op completion zsh)" -compdef _op op +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `op`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_op" ]]; then + typeset -g -A _comps + autoload -Uz _op + _comps[op]=_op +fi + +op completion zsh >| "$ZSH_CACHE_DIR/completions/_op" &| # Load opswd function autoload -Uz opswd diff --git a/zsh/plugins/1password/README.md b/zsh/plugins/1password/README.md index f6854da..ace6da8 100644 --- a/zsh/plugins/1password/README.md +++ b/zsh/plugins/1password/README.md @@ -14,16 +14,18 @@ clipboard. ## `opswd` The `opswd` command is a wrapper around the `op` command. It takes a service -name as an argument and copies the password for that service to the clipboard. +name as an argument and copies the username, then the password for that service +to the clipboard, after confirmation on the user part. -If the service also contains a TOTP, it is copied to the clipboard after 10 seconds. -Finally, after 20 seconds, the clipboard is cleared. +If the service also contains a TOTP, it is copied to the clipboard after confirmation +on the user part. Finally, after 20 seconds, the clipboard is cleared. -The function has completion support, so you can use tab completion to select -which service you want to get. +For example, `opswd github.com` will put your GitHub username into your clipboard. Then, +it will ask for confirmation to continue, and copy the password to your clipboard. Finally, +if a TOTP is available, it will be copied to the clipboard after your confirmation. -For example, `opswd github.com` will put your GitHub password into your clipboard, and if -a TOTP is available, it will be copied to the clipboard after 10 seconds. +This function has completion support, so you can use tab completion to select which +service you want to get. > NOTE: you need to be signed in for `opswd` to work. If you are using biometric unlock, > 1Password CLI will automatically prompt you to sign in. See: diff --git a/zsh/plugins/1password/_opswd b/zsh/plugins/1password/_opswd index dbc094f..694df5c 100644 --- a/zsh/plugins/1password/_opswd +++ b/zsh/plugins/1password/_opswd @@ -6,14 +6,4 @@ function _opswd() { [[ -z "$services" ]] || compadd -a -- services } -# TODO: 2022-03-26: Remove support for op CLI 1 -autoload -Uz is-at-least -is-at-least 2.0.0 $(op --version) || { - function _opswd() { - local -a services - services=("${(@f)$(op list items --categories Login 2>/dev/null | op get item - --fields title 2>/dev/null)}") - [[ -z "$services" ]] || compadd -a -- services - } -} - _opswd "$@" diff --git a/zsh/plugins/1password/opswd b/zsh/plugins/1password/opswd index 5767280..9e09ae7 100644 --- a/zsh/plugins/1password/opswd +++ b/zsh/plugins/1password/opswd @@ -14,65 +14,36 @@ function opswd() { # If not logged in, print error and return op user list > /dev/null || return + local username + # Copy the username to the clipboard + if ! username=$(op item get "$service" --fields username 2>/dev/null); then + echo "error: could not obtain username for $service" + return 1 + fi + + echo -n "$username" | clipcopy + echo "✔ username for service $service copied to the clipboard. Press Enter to continue" + read + local password # Copy the password to the clipboard - if ! password=$(op item get "$service" --fields password 2>/dev/null); then + if ! password=$(op item get "$service" --reveal --fields password 2>/dev/null); then echo "error: could not obtain password for $service" return 1 fi echo -n "$password" | clipcopy - echo "✔ password for $service copied to clipboard" + echo "✔ password for $service copied to clipboard. Press Enter to continue" + read - # If there's a one time password, copy it to the clipboard after 10 seconds + # If there's a one time password, copy it to the clipboard local totp if totp=$(op item get --otp "$service" 2>/dev/null) && [[ -n "$totp" ]]; then - sleep 10 && echo -n "$totp" | clipcopy + echo -n "$totp" | clipcopy echo "✔ TOTP for $service copied to clipboard" fi (sleep 20 && clipcopy /dev/null) &! } -# TODO: 2022-03-26: Remove support for op CLI 1 -autoload -Uz is-at-least -is-at-least 2.0.0 $(op --version) || { - print -ru2 ${(%):-"%F{yellow}opswd: usage with op version $(op --version) is deprecated. Upgrade to CLI 2 and reload zsh. -For instructions, see https://developer.1password.com/docs/cli/upgrade.%f"} - - # opswd puts the password of the named service into the clipboard. If there's a - # one time password, it will be copied into the clipboard after 10 seconds. The - # clipboard is cleared after another 20 seconds. - function opswd() { - if [[ $# -lt 1 ]]; then - echo "Usage: opswd " - return 1 - fi - - local service=$1 - - # If not logged in, print error and return - op list users > /dev/null || return - - local password - # Copy the password to the clipboard - if ! password=$(op get item "$service" --fields password 2>/dev/null); then - echo "error: could not obtain password for $service" - return 1 - fi - - echo -n "$password" | clipcopy - echo "✔ password for $service copied to clipboard" - - # If there's a one time password, copy it to the clipboard after 5 seconds - local totp - if totp=$(op get totp "$service" 2>/dev/null) && [[ -n "$totp" ]]; then - sleep 10 && echo -n "$totp" | clipcopy - echo "✔ TOTP for $service copied to clipboard" - fi - - (sleep 20 && clipcopy /dev/null) &! - } -} - opswd "$@" diff --git a/zsh/plugins/adb/README.md b/zsh/plugins/adb/README.md deleted file mode 100644 index 83dcc72..0000000 --- a/zsh/plugins/adb/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# adb autocomplete plugin - -* Adds autocomplete options for all adb commands. -* Add autocomplete for `adb -s` - -## Requirements - -In order to make this work, you will need to have the Android adb tools set up in your path. diff --git a/zsh/plugins/adb/_adb b/zsh/plugins/adb/_adb deleted file mode 100644 index 78c4577..0000000 --- a/zsh/plugins/adb/_adb +++ /dev/null @@ -1,67 +0,0 @@ -#compdef adb -#autoload - -# in order to make this work, you will need to have the android adb tools - -# adb zsh completion, based on homebrew completion - -local -a _1st_arguments -_1st_arguments=( -'bugreport:return all information from the device that should be included in a bug report.' -'connect:connect to a device via TCP/IP Port 5555 is default.' -'devices:list all connected devices' -'disconnect:disconnect from a TCP/IP device. Port 5555 is default.' -'emu:run emulator console command' -'forward:forward socket connections' -'get-devpath:print the device path' -'get-serialno:print the serial number of the device' -'get-state:print the current state of the device: offline | bootloader | device' -'help:show the help message' -'install:push this package file to the device and install it' -'jdwp:list PIDs of processes hosting a JDWP transport' -'keygen:generate adb public/private key' -'kill-server:kill the server if it is running' -'logcat:view device log' -'pull:copy file/dir from device' -'push:copy file/dir to device' -'reboot:reboots the device, optionally into the bootloader or recovery program' -'reboot-bootloader:reboots the device into the bootloader' -'remount:remounts the partitions on the device read-write' -'root:restarts the adbd daemon with root permissions' -'sideload:push a ZIP to device and install it' -'shell:run remote shell interactively' -'sync:copy host->device only if changed (-l means list but dont copy)' -'start-server:ensure that there is a server running' -'tcpip:restart host adb in tcpip mode' -'uninstall:remove this app package from the device' -'usb:restart the adbd daemon listing on USB' -'version:show version num' -'wait-for-device:block until device is online' -) - -local expl -local -a pkgs installed_pkgs - -_arguments \ - '-s[devices]:specify device:->specify_device' \ - '*:: :->subcmds' && return 0 - -case "$state" in - specify_device) - _values -C 'devices' ${$(adb devices -l|awk 'NR>1&& $1 \ - {sub(/ +/," ",$0); \ - gsub(":","\\:",$1); \ - for(i=1;i<=NF;i++) { - if($i ~ /model:/) { split($i,m,":") } \ - else if($i ~ /product:/) { split($i,p,":") } } \ - printf "%s[%s(%s)] ",$1, p[2], m[2]}'):-""} - return - ;; -esac - -if (( CURRENT == 1 )); then - _describe -t commands "adb subcommand" _1st_arguments - return -fi - -_files diff --git a/zsh/plugins/ag/README.md b/zsh/plugins/ag/README.md deleted file mode 100644 index 1983aaa..0000000 --- a/zsh/plugins/ag/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# The Silver Searcher - -This plugin provides completion support for [`ag`](https://github.com/ggreer/the_silver_searcher). - -To use it, add ag to the plugins array in your zshrc file. - -```zsh -plugins=(... ag) -``` - -## INSTALLATION NOTES - -Besides oh-my-zsh, `ag` needs to be installed by following these steps: https://github.com/ggreer/the_silver_searcher#installing. diff --git a/zsh/plugins/ag/_ag b/zsh/plugins/ag/_ag deleted file mode 100644 index 25b0c27..0000000 --- a/zsh/plugins/ag/_ag +++ /dev/null @@ -1,66 +0,0 @@ -#compdef ag -#autoload - -typeset -A opt_args - -# Took the liberty of not listing every option… specially aliases and -D -_ag () { - local -a _1st_arguments - _1st_arguments=( - '--ackmate:Print results in AckMate-parseable format' - {'-A','--after'}':[LINES] Print lines after match (Default: 2)' - {'-B','--before'}':[LINES] Print lines before match (Default: 2)' - '--break:Print newlines between matches in different files' - '--nobreak:Do not print newlines between matches in different files' - {'-c','--count'}':Only print the number of matches in each file' - '--color:Print color codes in results (Default: On)' - '--nocolor:Do not print color codes in results' - '--color-line-number:Color codes for line numbers (Default: 1;33)' - '--color-match:Color codes for result match numbers (Default: 30;43)' - '--color-path:Color codes for path names (Default: 1;32)' - '--column:Print column numbers in results' - {'-H','--heading'}':Print file names (On unless searching a single file)' - '--noheading:Do not print file names (On unless searching a single file)' - '--line-numbers:Print line numbers even for streams' - {'-C','--context'}':[LINES] Print lines before and after matches (Default: 2)' - '-g:[PATTERN] Print filenames matching PATTERN' - {'-l','--files-with-matches'}':Only print filenames that contain matches' - {'-L','--files-without-matches'}':Only print filenames that do not contain matches' - '--no-numbers:Do not print line numbers' - {'-o','--only-matching'}':Prints only the matching part of the lines' - '--print-long-lines:Print matches on very long lines (Default: 2k characters)' - '--passthrough:When searching a stream, print all lines even if they do not match' - '--silent:Suppress all log messages, including errors' - '--stats:Print stats (files scanned, time taken, etc.)' - '--vimgrep:Print results like vim :vimgrep /pattern/g would' - {'-0','--null'}':Separate filenames with null (for "xargs -0")' - - {'-a','--all-types'}':Search all files (does not include hidden files / .gitignore)' - '--depth:[NUM] Search up to NUM directories deep (Default: 25)' - {'-f','--follow'}':Follow symlinks' - {'-G','--file-search-regex'}':[PATTERN] Limit search to filenames matching PATTERN' - '--hidden:Search hidden files (obeys .*ignore files)' - {'-i','--ignore-case'}':Match case insensitively' - '--ignore:[PATTERN] Ignore files/directories matching PATTERN' - {'-m','--max-count'}':[NUM] Skip the rest of a file after NUM matches (Default: 10k)' - {'-p','--path-to-agignore'}':[PATH] Use .agignore file at PATH' - {'-Q','--literal'}':Do not parse PATTERN as a regular expression' - {'-s','--case-sensitive'}':Match case' - {'-S','--smart-case'}':Insensitive match unless PATTERN has uppercase (Default: On)' - '--search-binary:Search binary files for matches' - {'-t','--all-text'}':Search all text files (Hidden files not included)' - {'-u','--unrestricted'}':Search all files (ignore .agignore and _all_)' - {'-U','--skip-vcs-ignores'}':Ignore VCS files (stil obey .agignore)' - {'-v','--invert-match'}':Invert match' - {'-w','--word-regexp'}':Only match whole words' - {'-z','--search-zip'}':Search contents of compressed (e.g., gzip) files' - - '--list-file-types:list of supported file types' - ) - - if [[ $words[-1] =~ "^-" ]]; then - _describe -t commands "ag options" _1st_arguments && ret=0 - else - _files && ret=0 - fi -} diff --git a/zsh/plugins/alias-finder/.zunit.yml b/zsh/plugins/alias-finder/.zunit.yml new file mode 100644 index 0000000..ae65f8e --- /dev/null +++ b/zsh/plugins/alias-finder/.zunit.yml @@ -0,0 +1,9 @@ +tap: false +directories: + tests: tests + output: tests/_output + support: tests/_support +time_limit: 0 +fail_fast: false +allow_risky: false +verbose: true diff --git a/zsh/plugins/alias-finder/README.md b/zsh/plugins/alias-finder/README.md index 409f4b6..b24f8d4 100644 --- a/zsh/plugins/alias-finder/README.md +++ b/zsh/plugins/alias-finder/README.md @@ -2,45 +2,69 @@ This plugin searches the defined aliases and outputs any that match the command inputted. This makes learning new aliases easier. +## Setup + To use it, add `alias-finder` to the `plugins` array of your zshrc file: ``` plugins=(... alias-finder) ``` +To enable it for every single command, set zstyle in your `~/.zshrc`. + +If the user has installed `rg`([ripgrep](https://github.com/BurntSushi/ripgrep)), it will be used because it's faster. Otherwise, it will use the `grep` command. + +```zsh +# ~/.zshrc + +zstyle ':omz:plugins:alias-finder' autoload yes # disabled by default +zstyle ':omz:plugins:alias-finder' longer yes # disabled by default +zstyle ':omz:plugins:alias-finder' exact yes # disabled by default +zstyle ':omz:plugins:alias-finder' cheaper yes # disabled by default +``` + +As you can see, options are also available with zstyle. + ## Usage -To see if there is an alias defined for the command, pass it as an argument to `alias-finder`. This can also run automatically before each command you input - add `ZSH_ALIAS_FINDER_AUTOMATIC=true` to your zshrc if you want this. -## Options +When you execute a command alias finder will look at your defined aliases and suggest shorter aliases you could have used, for example: -- Use `--longer` or `-l` to allow the aliases to be longer than the input (match aliases if they contain the input). -- Use `--exact` or `-e` to avoid matching aliases that are shorter than the input. +Running the un-aliased `git status` command: +```sh +╭─tim@fox ~/repo/gitopolis ‹main› +╰─$ git status -## Examples +gst='git status' # <=== shorter suggestion from alias-finder + +On branch main +Your branch is up-to-date with 'origin/main'. +nothing to commit, working tree clean ``` -$ alias-finder "git pull" -gl='git pull' -g=git + +Running a shorter `git st` alias from `.gitconfig` that it suggested : +```sh +╭─tim@fox ~/repo/gitopolis ‹main› +╰─$ git st +gs='git st' # <=== shorter suggestion from alias-finder +## main...origin/main ``` + +Running the shortest `gs` shell alias that it found: +```sh +╭─tim@fox ~/repo/gitopolis ‹main› +╰─$ gs + # <=== no suggestions alias-finder because this is the shortest +## main...origin/main ``` -$ alias-finder "web_search google oh my zsh" -google='web_search google' -``` -``` -$ alias-finder "git commit -v" -gc="git commit -v" -g=git -``` -``` -$ alias-finder -e "git commit -v" -gc='git commit -v' -``` -``` -$ alias-finder -l "git commit -v" -gc='git commit -v' -'gc!'='git commit -v --amend' -gca='git commit -v -a' -'gca!'='git commit -v -a --amend' -'gcan!'='git commit -v -a --no-edit --amend' -'gcans!'='git commit -v -a -s --no-edit --amend' -'gcn!'='git commit -v --no-edit --amend' -``` + +![image](https://github.com/ohmyzsh/ohmyzsh/assets/19378/39642750-fb10-4f1a-b7f9-f36789eeb01b) + + +### Options + +> In order to clarify, let's say `alias a=abc` has source 'abc' and destination 'a'. + +- Use `--longer` or `-l` to include aliases where the source is longer than the input (in other words, the source could contain the whole input). +- Use `--exact` or `-e` to avoid aliases where the source is shorter than the input (in other words, the source must be the same with the input). +- Use `--cheaper` or `-c` to avoid aliases where the destination is longer than the input (in other words, the destination must be the shorter than the input). + + diff --git a/zsh/plugins/alias-finder/alias-finder.plugin.zsh b/zsh/plugins/alias-finder/alias-finder.plugin.zsh index caee9b5..6f24c70 100644 --- a/zsh/plugins/alias-finder/alias-finder.plugin.zsh +++ b/zsh/plugins/alias-finder/alias-finder.plugin.zsh @@ -1,44 +1,67 @@ alias-finder() { - local cmd="" exact="" longer="" wordStart="" wordEnd="" multiWordEnd="" - for i in $@; do - case $i in + local cmd=" " exact="" longer="" cheaper="" wordEnd="'{0,1}$" finder="" filter="" + + # build command and options + for c in "$@"; do + case $c in + # TODO: Remove backward compatibility (other than zstyle form) + # set options if exist -e|--exact) exact=true;; -l|--longer) longer=true;; - *) - if [[ -z $cmd ]]; then - cmd=$i - else - cmd="$cmd $i" - fi - ;; + -c|--cheaper) cheaper=true;; + # concatenate cmd + *) cmd="$cmd$c " ;; esac done - cmd=$(sed 's/[].\|$(){}?+*^[]/\\&/g' <<< $cmd) # adds escaping for grep - if (( $(wc -l <<< $cmd) == 1 )); then - while [[ $cmd != "" ]]; do - if [[ $longer = true ]]; then - wordStart="'{0,1}" - else - wordEnd="$" - multiWordEnd="'$" - fi - if [[ $cmd == *" "* ]]; then - local finder="'$cmd$multiWordEnd" - else - local finder=$wordStart$cmd$wordEnd - fi - alias | grep -E "=$finder" - if [[ $exact = true || $longer = true ]]; then - break - else - cmd=$(sed -E 's/ {0,1}[^ ]*$//' <<< $cmd) # removes last word - fi - done + + zstyle -t ':omz:plugins:alias-finder' longer && longer=true + zstyle -t ':omz:plugins:alias-finder' exact && exact=true + zstyle -t ':omz:plugins:alias-finder' cheaper && cheaper=true + + # format cmd for grep + ## - replace newlines with spaces + ## - trim both ends + ## - replace multiple spaces with one space + ## - add escaping character to special characters + cmd=$(echo -n "$cmd" | tr '\n' ' ' | xargs | tr -s '[:space:]' | sed 's/[].\|$(){}?+*^[]/\\&/g') + + if [[ $longer == true ]]; then + wordEnd="" # remove wordEnd to find longer aliases fi + + # find with alias and grep, removing last word each time until no more words + while [[ $cmd != "" ]]; do + finder="'{0,1}$cmd$wordEnd" + + # make filter to find only shorter results than current cmd + if [[ $cheaper == true ]]; then + cmdLen=$(echo -n "$cmd" | wc -c) + if [[ $cmdLen -le 1 ]]; then + return + fi + + filter="^'?.{1,$((cmdLen - 1))}'?=" # some aliases is surrounded by single quotes + fi + + if (( $+commands[rg] )); then + alias | rg "$filter" | rg "=$finder" + else + alias | grep -E "$filter" | grep -E "=$finder" + fi + + if [[ $exact == true ]]; then + break # because exact case is only one + elif [[ $longer == true ]]; then + break # because above grep command already found every longer aliases during first cycle + fi + + cmd=$(sed -E 's/ {0,}[^ ]*$//' <<< "$cmd") # remove last word + done } preexec_alias-finder() { - if [[ $ZSH_ALIAS_FINDER_AUTOMATIC = true ]]; then + # TODO: Remove backward compatibility (other than zstyle form) + zstyle -t ':omz:plugins:alias-finder' autoload && alias-finder $1 || if [[ $ZSH_ALIAS_FINDER_AUTOMATIC = true ]]; then alias-finder $1 fi } diff --git a/zsh/plugins/alias-finder/tests/_output/.gitkeep b/zsh/plugins/alias-finder/tests/_output/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/zsh/plugins/alias-finder/tests/_support/.gitkeep b/zsh/plugins/alias-finder/tests/_support/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/zsh/plugins/alias-finder/tests/_support/bootstrap b/zsh/plugins/alias-finder/tests/_support/bootstrap new file mode 100644 index 0000000..0107661 --- /dev/null +++ b/zsh/plugins/alias-finder/tests/_support/bootstrap @@ -0,0 +1,2 @@ +#!/usr/bin/env zsh +# Write your bootstrap code here diff --git a/zsh/plugins/alias-finder/tests/test_run.sh b/zsh/plugins/alias-finder/tests/test_run.sh new file mode 100644 index 0000000..6b7abeb --- /dev/null +++ b/zsh/plugins/alias-finder/tests/test_run.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env zunit + +@setup { + load ../alias-finder.plugin.zsh + + set_git_aliases() { + unalias -a # all + alias g="git" + alias gc="git commit" + alias gcv="git commit -v" + alias gcvs="git commit -v -S" + } +} + +@test 'find aliases that contain input' { + set_git_aliases + + run alias-finder "git" + + assert "${#lines[@]}" equals 1 + assert "${lines[1]}" same_as "g=git" +} + +@test 'find aliases that contain input with whitespaces at ends' { + set_git_aliases + + run alias-finder " git " + + assert "${#lines[@]}" equals 1 + assert "${lines[1]}" same_as "g=git" +} + +@test 'find aliases that contain multiple words' { + set_git_aliases + + run alias-finder "git commit -v" + + assert "${#lines[@]}" equals 3 + assert "${lines[1]}" same_as "gcv='git commit -v'" + assert "${lines[2]}" same_as "gc='git commit'" + assert "${lines[3]}" same_as "g=git" +} + +@test 'find alias that is the same with input when --exact option is set' { + set_git_aliases + + run alias-finder -e "git" + + assert "${#lines[@]}" equals 1 + assert "${lines[1]}" same_as "g=git" +} + +@test 'find alias that is the same with multiple words input when --exact option is set' { + set_git_aliases + + run alias-finder -e "git commit -v" + + assert "${#lines[@]}" equals 1 + assert "${lines[1]}" same_as "gcv='git commit -v'" +} + +@test 'find alias that is the same with or longer than input when --longer option is set' { + set_git_aliases + + run alias-finder -l "git" + + assert "${#lines[@]}" equals 4 + assert "${lines[1]}" same_as "g=git" + assert "${lines[2]}" same_as "gc='git commit'" + assert "${lines[3]}" same_as "gcv='git commit -v'" + assert "${lines[4]}" same_as "gcvs='git commit -v -S'" +} + +@test 'find alias that is the same with or longer than multiple words input when --longer option is set' { + set_git_aliases + + run alias-finder -l "git commit -v" + + assert "${#lines[@]}" equals 2 + assert "${lines[1]}" same_as "gcv='git commit -v'" + assert "${lines[2]}" same_as "gcvs='git commit -v -S'" +} + +@test 'find aliases including expensive (longer) than input' { + set_git_aliases + alias expensiveCommands="git commit" + + run alias-finder "git commit -v" + + assert "${#lines[@]}" equals 4 + assert "${lines[1]}" same_as "gcv='git commit -v'" + assert "${lines[2]}" same_as "expensiveCommands='git commit'" + assert "${lines[3]}" same_as "gc='git commit'" + assert "${lines[4]}" same_as "g=git" +} + +@test 'find aliases excluding expensive (longer) than input when --cheap option is set' { + set_git_aliases + alias expensiveCommands="git commit" + + run alias-finder -c "git commit -v" + + assert "${#lines[@]}" equals 3 + assert "${lines[1]}" same_as "gcv='git commit -v'" + assert "${lines[2]}" same_as "gc='git commit'" + assert "${lines[3]}" same_as "g=git" +} diff --git a/zsh/plugins/aliases/README.md b/zsh/plugins/aliases/README.md index 66fd845..5a7e7df 100644 --- a/zsh/plugins/aliases/README.md +++ b/zsh/plugins/aliases/README.md @@ -1,7 +1,5 @@ # Aliases cheatsheet -**Maintainer:** [@hqingyi](https://github.com/hqingyi) - With lots of 3rd-party amazing aliases installed, this plugin helps list the shortcuts that are currently available based on the plugins you have enabled. @@ -13,16 +11,18 @@ plugins=(aliases) Requirements: Python needs to be installed. +**Maintainer:** [@hqingyi](https://github.com/hqingyi) + ## Usage -- `acs`: show all aliases by group. +- `als`: show all aliases by group -- `acs -h/--help`: print help mesage. +- `als -h/--help`: print help message -- `acs `: filter aliases by `` and highlight. +- `als `: filter and highlight aliases by `` -- `acs -g /--group `. Multiple uses of the flag show all groups, +- `als -g /--group `: show only aliases for group ``. Multiple uses of the flag show all groups -- `acs --groups-only`: show only group names +- `als --groups`: show only group names - ![screenshot](https://cloud.githubusercontent.com/assets/3602957/11581913/cb54fb8a-9a82-11e5-846b-5a67f67ad9ad.png) + ![screenshot](https://github.com/ohmyzsh/ohmyzsh/assets/66907184/5bfa00ea-5fc3-4e97-8b22-2f74f6b948c7) diff --git a/zsh/plugins/aliases/aliases.plugin.zsh b/zsh/plugins/aliases/aliases.plugin.zsh index 9864de9..7f1ba83 100644 --- a/zsh/plugins/aliases/aliases.plugin.zsh +++ b/zsh/plugins/aliases/aliases.plugin.zsh @@ -4,7 +4,7 @@ 0="${${(M)0:#/*}:-$PWD/$0}" eval ' - function acs(){ + function als(){ (( $+commands[python3] )) || { echo "[error] No python executable detected" return diff --git a/zsh/plugins/aliases/cheatsheet.py b/zsh/plugins/aliases/cheatsheet.py index 3362a6a..61bf5f9 100644 --- a/zsh/plugins/aliases/cheatsheet.py +++ b/zsh/plugins/aliases/cheatsheet.py @@ -15,6 +15,7 @@ def parse(line): def cheatsheet(lines): exps = [ parse(line) for line in lines ] + exps.sort(key=lambda exp:exp[2]) cheatsheet = {'_default': []} for key, group in itertools.groupby(exps, lambda exp:exp[2]): group_list = [ item for item in group ] @@ -56,8 +57,8 @@ def pretty_print(cheatsheet, wfilter, group_list=None, groups_only=False): pretty_print_group(key, [ alias for alias in aliases if alias[0].find(wfilter)>-1 or alias[1].find(wfilter)>-1], wfilter) if __name__ == '__main__': - parser = argparse.ArgumentParser(description="Pretty print aliases.") - parser.add_argument('filter', nargs="*", help="search aliases matching string") + parser = argparse.ArgumentParser(description="Pretty print aliases.", prog="als") + parser.add_argument('filter', nargs="*", metavar="", help="search aliases matching keywords") parser.add_argument('-g', '--group', dest="group_list", action='append', help="only print aliases in given groups") parser.add_argument('--groups', dest='groups_only', action='store_true', help="only print alias groups") args = parser.parse_args() diff --git a/zsh/plugins/ansible/README.md b/zsh/plugins/ansible/README.md index e0e6a19..6a06962 100644 --- a/zsh/plugins/ansible/README.md +++ b/zsh/plugins/ansible/README.md @@ -1,7 +1,5 @@ # ansible plugin -## Introduction - The `ansible plugin` adds several aliases for useful [ansible](https://docs.ansible.com/ansible/latest/index.html) commands and [aliases](#aliases). To use it, add `ansible` to the plugins array of your zshrc file: @@ -21,7 +19,6 @@ plugins=(... ansible) | `acon` | command `ansible-console` | | `ainv` | command `ansible-inventory` | | `aplaybook` | command `ansible-playbook` | -| `ainv` | command `ansible-inventory` | | `adoc` | command `ansible-doc` | | `agal` | command `ansible-galaxy` | | `apull` | command `ansible-pull` | @@ -29,6 +26,6 @@ plugins=(... ansible) ## Maintainer -### [Deepankumar](https://github.com/deepan10) +### [Deepankumar](https://github.com/deepan10) [https://github.com/deepan10/oh-my-zsh/tree/features/ansible-plugin](https://github.com/deepan10/oh-my-zsh/tree/features/ansible-plugin) diff --git a/zsh/plugins/archlinux/README.md b/zsh/plugins/archlinux/README.md index fd772c6..5e015db 100644 --- a/zsh/plugins/archlinux/README.md +++ b/zsh/plugins/archlinux/README.md @@ -181,3 +181,4 @@ whether the package manager is installed, checked in the following order: - Ybalrid (Arthur Brainville) - ybalrid@ybalrid.info - Jeff M. Hubbard - jeffmhubbard@gmail.com - K. Harishankar(harishnkr) - hari2menon1234@gmail.com +- WH-2099 - wh2099@outlook.com \ No newline at end of file diff --git a/zsh/plugins/archlinux/archlinux.plugin.zsh b/zsh/plugins/archlinux/archlinux.plugin.zsh index 4f13647..7abd7c2 100644 --- a/zsh/plugins/archlinux/archlinux.plugin.zsh +++ b/zsh/plugins/archlinux/archlinux.plugin.zsh @@ -23,30 +23,27 @@ alias pacfiles='pacman -F' alias pacls='pacman -Ql' alias pacown='pacman -Qo' alias pacupd="sudo pacman -Sy" -alias upgrade='sudo pacman -Syu' function paclist() { - # Based on https://bbs.archlinux.org/viewtopic.php?id=93683 - pacman -Qqe | \ - xargs -I '{}' \ - expac "${bold_color}% 20n ${fg_no_bold[white]}%d${reset_color}" '{}' + pacman -Qqe | xargs -I{} -P0 --no-run-if-empty pacman -Qs --color=auto "^{}\$" } function pacdisowned() { - local tmp db fs - tmp=${TMPDIR-/tmp}/pacman-disowned-$UID-$$ - db=$tmp/db - fs=$tmp/fs + local tmp_dir db fs + tmp_dir=$(mktemp --directory) + db=$tmp_dir/db + fs=$tmp_dir/fs - mkdir "$tmp" - trap 'rm -rf "$tmp"' EXIT + trap "rm -rf $tmp_dir" EXIT pacman -Qlq | sort -u > "$db" - find /bin /etc /lib /sbin /usr ! -name lost+found \ + find /etc /usr ! -name lost+found \ \( -type d -printf '%p/\n' -o -print \) | sort > "$fs" comm -23 "$fs" "$db" + + rm -rf $tmp_dir } alias pacmanallkeys='sudo pacman-key --refresh-keys' @@ -109,7 +106,6 @@ if (( $+commands[aura] )); then alias auupd="sudo aura -Sy" alias auupg='sudo sh -c "aura -Syu && aura -Au"' alias ausu='sudo sh -c "aura -Syu --no-confirm && aura -Au --no-confirm"' - alias upgrade='sudo aura -Syu' # extra bonus specially for aura alias auown="aura -Qqo" @@ -136,7 +132,6 @@ if (( $+commands[pacaur] )); then alias painsd='pacaur -S --asdeps' alias pamir='pacaur -Syy' alias paupd="pacaur -Sy" - alias upgrade='pacaur -Syu' fi if (( $+commands[trizen] )); then @@ -158,7 +153,6 @@ if (( $+commands[trizen] )); then alias trinsd='trizen -S --asdeps' alias trmir='trizen -Syy' alias trupd="trizen -Sy" - alias upgrade='trizen -Syu' fi if (( $+commands[yay] )); then @@ -180,5 +174,31 @@ if (( $+commands[yay] )); then alias yainsd='yay -S --asdeps' alias yamir='yay -Syy' alias yaupd="yay -Sy" - alias upgrade='yay -Syu' fi + +# Check Arch Linux PGP Keyring before System Upgrade to prevent failure. +function upgrade() { + sudo pacman -Sy + echo ":: Checking Arch Linux PGP Keyring..." + local installedver="$(LANG= sudo pacman -Qi archlinux-keyring | grep -Po '(?<=Version : ).*')" + local currentver="$(LANG= sudo pacman -Si archlinux-keyring | grep -Po '(?<=Version : ).*')" + if [ $installedver != $currentver ]; then + echo " Arch Linux PGP Keyring is out of date." + echo " Updating before full system upgrade." + sudo pacman -S --needed --noconfirm archlinux-keyring + else + echo " Arch Linux PGP Keyring is up to date." + echo " Proceeding with full system upgrade." + fi + if (( $+commands[yay] )); then + yay -Su + elif (( $+commands[trizen] )); then + trizen -Su + elif (( $+commands[pacaur] )); then + pacaur -Su + elif (( $+commands[aura] )); then + sudo aura -Su + else + sudo pacman -Su + fi +} diff --git a/zsh/plugins/arduino-cli/README.md b/zsh/plugins/arduino-cli/README.md new file mode 100644 index 0000000..821d72b --- /dev/null +++ b/zsh/plugins/arduino-cli/README.md @@ -0,0 +1,9 @@ +# Arduino CLI plugin + +This plugin adds completion for the [arduino-cli](https://github.com/arduino/arduino-cli) tool. + +To use it, add `arduino-cli` to the plugins array in your zshrc file: + +```zsh +plugins=(... arduino-cli) +``` diff --git a/zsh/plugins/arduino-cli/arduino-cli.plugin.zsh b/zsh/plugins/arduino-cli/arduino-cli.plugin.zsh new file mode 100644 index 0000000..e4fdcf9 --- /dev/null +++ b/zsh/plugins/arduino-cli/arduino-cli.plugin.zsh @@ -0,0 +1,14 @@ +if (( ! $+commands[arduino-cli] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `arduino-cli`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_arduino-cli" ]]; then + typeset -g -A _comps + autoload -Uz _arduino-cli + _comps[arduino-cli]=_arduino-cli +fi + +# Generate and load arduino-cli completion +arduino-cli completion zsh >! "$ZSH_CACHE_DIR/completions/_arduino-cli" &| diff --git a/zsh/plugins/argocd/README.md b/zsh/plugins/argocd/README.md new file mode 100644 index 0000000..0f900ff --- /dev/null +++ b/zsh/plugins/argocd/README.md @@ -0,0 +1,20 @@ +# Argo CD plugin + +This plugin adds completion for the [Argo CD](https://argoproj.github.io/cd/) CLI. + +To use it, add `argocd` to the plugins array in your zshrc file: + +```zsh +plugins=(... argocd) +``` + +This plugin does not add any aliases. + +## Cache + +This plugin caches the completion script and is automatically updated asynchronously when the plugin is +loaded, which is usually when you start up a new terminal emulator. + +The cache is stored at: + +- `$ZSH_CACHE/completions/_argocd` completions script diff --git a/zsh/plugins/argocd/argocd.plugin.zsh b/zsh/plugins/argocd/argocd.plugin.zsh new file mode 100644 index 0000000..8de7b02 --- /dev/null +++ b/zsh/plugins/argocd/argocd.plugin.zsh @@ -0,0 +1,14 @@ +# Autocompletion for argocd. +if (( ! $+commands[argocd] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `argocd`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_argocd" ]]; then + typeset -g -A _comps + autoload -Uz _argocd + _comps[argocd]=_argocd +fi + +argocd completion zsh >| "$ZSH_CACHE_DIR/completions/_argocd" &| diff --git a/zsh/plugins/asdf/README.md b/zsh/plugins/asdf/README.md index e8aa976..69db693 100644 --- a/zsh/plugins/asdf/README.md +++ b/zsh/plugins/asdf/README.md @@ -1,27 +1,48 @@ -## asdf - -**Maintainer:** [@RobLoach](https://github.com/RobLoach) +# asdf Adds integration with [asdf](https://github.com/asdf-vm/asdf), the extendable version manager, with support for Ruby, Node.js, Elixir, Erlang and more. -### Installation +## Installation -1. Enable the plugin by adding it to your `plugins` definition in `~/.zshrc`. - - ``` - plugins=(asdf) - ``` - -2. [Install asdf](https://github.com/asdf-vm/asdf#setup) by running the following: - ``` - git clone https://github.com/asdf-vm/asdf.git ~/.asdf - ``` - -### Usage - -See the [asdf usage documentation](https://github.com/asdf-vm/asdf#usage) for information on how to use asdf: +1. [Install](https://asdf-vm.com/guide/getting-started.html#_1-install-asdf) asdf and ensure that's it's discoverable on `$PATH`; +2. Enable it by adding it to your `plugins` definition in `~/.zshrc`: +```sh +plugins=(asdf) ``` -asdf plugin-add nodejs git@github.com:asdf-vm/asdf-nodejs.git -asdf install nodejs 5.9.1 + +## Usage + +Refer to the [asdf plugin documentation](https://asdf-vm.com/guide/getting-started.html#_4-install-a-plugin) for information on how to add a plugin and install the many runtime versions for it. + +Example for installing the nodejs plugin and the many runtimes for it: + +```sh +# Add plugin to asdf +asdf plugin add nodejs + +# Install the latest available version +asdf install nodejs latest + +# Uninstall the latest version +asdf uninstall nodejs latest + +# Install a specific version +asdf install nodejs 16.5.0 + +# Set the latest version in .tool-versions of the `current directory` +asdf set nodejs latest + +# Set a specific version in the `parent directory` +asdf set -p nodejs 16.5.0 # -p is shorthand for --parent + +# Set a global version under `$HOME` +asdf set -u nodejs 16.5.0 # -u is shorthand for --home ``` + +For more commands, run `asdf help` or refer to the +[asdf CLI documentation](https://asdf-vm.com/manage/commands.html#all-commands). + +## Maintainer + +- [@RobLoach](https://github.com/RobLoach) diff --git a/zsh/plugins/asdf/asdf.plugin.zsh b/zsh/plugins/asdf/asdf.plugin.zsh index 3016282..9139498 100644 --- a/zsh/plugins/asdf/asdf.plugin.zsh +++ b/zsh/plugins/asdf/asdf.plugin.zsh @@ -1,27 +1,15 @@ -# Find where asdf should be installed -ASDF_DIR="${ASDF_DIR:-$HOME/.asdf}" -ASDF_COMPLETIONS="$ASDF_DIR/completions" +(( ! $+commands[asdf] )) && return -# If not found, check for archlinux/AUR package (/opt/asdf-vm/) -if [[ ! -f "$ASDF_DIR/asdf.sh" || ! -f "$ASDF_COMPLETIONS/asdf.bash" ]] && [[ -f "/opt/asdf-vm/asdf.sh" ]]; then - ASDF_DIR="/opt/asdf-vm" - ASDF_COMPLETIONS="$ASDF_DIR" -fi - -# If not found, check for Homebrew package -if [[ ! -f "$ASDF_DIR/asdf.sh" || ! -f "$ASDF_COMPLETIONS/asdf.bash" ]] && (( $+commands[brew] )); then - brew_prefix="$(brew --prefix asdf)" - ASDF_DIR="${brew_prefix}/libexec" - ASDF_COMPLETIONS="${brew_prefix}/etc/bash_completion.d" - unset brew_prefix -fi - -# Load command -if [[ -f "$ASDF_DIR/asdf.sh" ]]; then - . "$ASDF_DIR/asdf.sh" - - # Load completions - if [[ -f "$ASDF_COMPLETIONS/asdf.bash" ]]; then - . "$ASDF_COMPLETIONS/asdf.bash" - fi +export ASDF_DATA_DIR="${ASDF_DATA_DIR:-$HOME/.asdf}" + +# Add shims to the front of the path, removing if already present. +path=("$ASDF_DATA_DIR/shims" ${path:#$ASDF_DATA_DIR/shims}) + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `asdf`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_asdf" ]]; then + typeset -g -A _comps + autoload -Uz _asdf + _comps[asdf]=_asdf fi +asdf completion zsh >| "$ZSH_CACHE_DIR/completions/_asdf" &| diff --git a/zsh/plugins/autoenv/autoenv.plugin.zsh b/zsh/plugins/autoenv/autoenv.plugin.zsh index 229a8a8..2f84f0a 100644 --- a/zsh/plugins/autoenv/autoenv.plugin.zsh +++ b/zsh/plugins/autoenv/autoenv.plugin.zsh @@ -17,9 +17,13 @@ if ! type autoenv_init >/dev/null; then /usr/local/bin /usr/share/autoenv-git ~/Library/Python/bin + .venv/bin + venv/bin + env/bin + .env/bin ) for d ( $install_locations ); do - if [[ -e $d/activate.sh ]]; then + if [[ -e $d/activate || -e $d/activate.sh ]]; then autoenv_dir=$d break fi @@ -29,13 +33,13 @@ if ! type autoenv_init >/dev/null; then # Look for Homebrew path as a last resort if [[ -z "$autoenv_dir" ]] && (( $+commands[brew] )); then d=$(brew --prefix)/opt/autoenv - if [[ -e $d/activate.sh ]]; then + if [[ -e $d/activate || -e $d/activate.sh ]]; then autoenv_dir=$d fi fi # Complain if autoenv is not installed - if [[ -z $autoenv_dir ]]; then + if [[ -z $autoenv_dir ]]; then cat <&2 -------- AUTOENV --------- Could not locate autoenv installation. @@ -46,7 +50,11 @@ END return 1 fi # Load autoenv - source $autoenv_dir/activate.sh + if [[ -e $autoenv_dir/activate ]]; then + source $autoenv_dir/activate + else + source $autoenv_dir/activate.sh + fi fi } [[ $? != 0 ]] && return $? diff --git a/zsh/plugins/autojump/autojump.plugin.zsh b/zsh/plugins/autojump/autojump.plugin.zsh index 8593353..a0668a4 100644 --- a/zsh/plugins/autojump/autojump.plugin.zsh +++ b/zsh/plugins/autojump/autojump.plugin.zsh @@ -1,17 +1,22 @@ declare -a autojump_paths autojump_paths=( - $HOME/.autojump/etc/profile.d/autojump.zsh # manual installation - $HOME/.autojump/share/autojump/autojump.zsh # manual installation - $HOME/.nix-profile/etc/profile.d/autojump.sh # NixOS installation - /run/current-system/sw/share/autojump/autojump.zsh # NixOS installation - /usr/share/autojump/autojump.zsh # Debian and Ubuntu package - /etc/profile.d/autojump.zsh # manual installation - /etc/profile.d/autojump.sh # Gentoo installation - /usr/local/share/autojump/autojump.zsh # FreeBSD installation - /usr/pkg/share/autojump/autojump.zsh # NetBSD installation - /opt/local/etc/profile.d/autojump.sh # macOS with MacPorts - /usr/local/etc/profile.d/autojump.sh # macOS with Homebrew (default) - /opt/homebrew/etc/profile.d/autojump.sh # macOS with Homebrew (default on M1 macs) + $HOME/.autojump/etc/profile.d/autojump.zsh # manual installation + $HOME/.autojump/share/autojump/autojump.zsh # manual installation + $HOME/.nix-profile/etc/profile.d/autojump.sh # NixOS installation + /run/current-system/sw/share/autojump/autojump.zsh # NixOS installation + /etc/profiles/per-user/$USER/share/autojump/autojump.zsh # Home Manager, NixOS with user-scoped packages + /usr/share/autojump/autojump.zsh # Debian and Ubuntu package + $PREFIX/share/autojump/autojump.zsh # Termux package + /etc/profile.d/autojump.zsh # manual installation + /etc/profile.d/autojump.sh # Gentoo installation + /usr/local/share/autojump/autojump.zsh # FreeBSD installation + /usr/pkg/share/autojump/autojump.zsh # NetBSD installation + /opt/local/etc/profile.d/autojump.sh # macOS with MacPorts + /usr/local/etc/profile.d/autojump.sh # macOS with Homebrew (default) + /opt/homebrew/etc/profile.d/autojump.sh # macOS with Homebrew (default on M1 macs) + /opt/pkg/share/autojump/autojump.zsh # macOS with pkgsrc + /etc/profiles/per-user/$USER/etc/profile.d/autojump.sh # macOS Nix, Home Manager and flakes + /nix/var/nix/gcroots/current-system/sw/share/zsh/site-functions/autojump.zsh # macOS Nix, nix-darwin ) for file in $autojump_paths; do diff --git a/zsh/plugins/aws/README.md b/zsh/plugins/aws/README.md index d6f4f46..0d0773f 100644 --- a/zsh/plugins/aws/README.md +++ b/zsh/plugins/aws/README.md @@ -1,7 +1,8 @@ # aws -This plugin provides completion support for [awscli](https://docs.aws.amazon.com/cli/latest/reference/index.html) -and a few utilities to manage AWS profiles and display them in the prompt. +This plugin provides completion support for [awscli v2](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/index.html) +and a few utilities to manage AWS profiles/regions and display them in the prompt. +[awscli v1](https://docs.aws.amazon.com/cli/latest/userguide/cliv2-migration.html) is no longer supported. To use it, add `aws` to the plugins array in your zshrc file. @@ -12,9 +13,14 @@ plugins=(... aws) ## Plugin commands * `asp []`: sets `$AWS_PROFILE` and `$AWS_DEFAULT_PROFILE` (legacy) to ``. - It also sets `$AWS_EB_PROFILE` to `` for the Elastic Beanstalk CLI. + It also sets `$AWS_EB_PROFILE` to `` for the Elastic Beanstalk CLI. It sets `$AWS_PROFILE_REGION` for display in `aws_prompt_info`. Run `asp` without arguments to clear the profile. -* `asp [] login`: If AWS SSO has been configured in your aws profile, it will run the `aws sso login` command following profile selection. +* `asp [] login`: If AWS SSO has been configured in your aws profile, it will run the `aws sso login` command following profile selection. +* `asp [] login []`: In addition to `asp [] login`, if SSO session has been configured in your aws profile, it will run the `aws sso login --sso-session ` command following profile selection. +* `asp [] logout`: If AWS SSO has been configured in your aws profile, it will run the `aws sso logout` command following profile selection. + +* `asr []`: sets `$AWS_REGION` and `$AWS_DEFAULT_REGION` (legacy) to ``. + Run `asr` without arguments to clear the profile. * `acp [] []`: in addition to `asp` functionality, it actually changes the profile by assuming the role specified in the `` configuration. It supports @@ -25,25 +31,41 @@ plugins=(... aws) * `agp`: gets the current value of `$AWS_PROFILE`. +* `agr`: gets the current value of `$AWS_REGION`. + * `aws_change_access_key`: changes the AWS access key of a profile. * `aws_profiles`: lists the available profiles in the `$AWS_CONFIG_FILE` (default: `~/.aws/config`). Used to provide completion for the `asp` function. +* `aws_regions`: lists the available regions. + Used to provide completion for the `asr` function. + ## Plugin options * Set `SHOW_AWS_PROMPT=false` in your zshrc file if you want to prevent the plugin from modifying your RPROMPT. Some themes might overwrite the value of RPROMPT instead of appending to it, so they'll need to be fixed to - see the AWS profile prompt. + see the AWS profile/region prompt. + +* Set `AWS_PROFILE_STATE_ENABLED=true` in your zshrc file if you want the aws profile to persist between shell sessions. + This option might slow down your shell startup time. + By default the state file path is `/tmp/.aws_current_profile`. This means that the state won't survive a reboot or otherwise GC. + You can control the state file path using the `AWS_STATE_FILE` environment variable. ## Theme The plugin creates an `aws_prompt_info` function that you can use in your theme, which displays -the current `$AWS_PROFILE`. It uses two variables to control how that is shown: +the current `$AWS_PROFILE` and `$AWS_REGION`. It uses four variables to control how that is shown: -* ZSH_THEME_AWS_PREFIX: sets the prefix of the AWS_PROFILE. Defaults to ``. +* ZSH_THEME_AWS_PROFILE_SUFFIX: sets the suffix of the AWS_PROFILE. Defaults to `>`. + +* ZSH_THEME_AWS_REGION_PREFIX: sets the prefix of the AWS_REGION. Defaults to ``. + +* ZSH_THEME_AWS_DIVIDER: sets the divider between ZSH_THEME_AWS_PROFILE_SUFFIX and ZSH_THEME_AWS_REGION_PREFIX. Defaults to ` ` (single space). ## Configuration @@ -53,7 +75,7 @@ the current `$AWS_PROFILE`. It uses two variables to control how that is shown: Source profile credentials in `~/.aws/credentials`: -``` +```ini [source-profile-name] aws_access_key_id = ... aws_secret_access_key = ... @@ -61,7 +83,7 @@ aws_secret_access_key = ... Role configuration in `~/.aws/config`: -``` +```ini [profile source-profile-name] mfa_serial = arn:aws:iam::111111111111:mfa/myuser region = us-east-1 diff --git a/zsh/plugins/aws/aws.plugin.zsh b/zsh/plugins/aws/aws.plugin.zsh index 2167f55..0c43031 100644 --- a/zsh/plugins/aws/aws.plugin.zsh +++ b/zsh/plugins/aws/aws.plugin.zsh @@ -2,10 +2,30 @@ function agp() { echo $AWS_PROFILE } +function agr() { + echo $AWS_REGION +} + +# Update state file if enabled +function _aws_update_state() { + if [[ "$AWS_PROFILE_STATE_ENABLED" == true ]]; then + test -d $(dirname ${AWS_STATE_FILE}) || exit 1 + echo "${AWS_PROFILE} ${AWS_REGION}" > "${AWS_STATE_FILE}" + fi +} + +function _aws_clear_state() { + if [[ "$AWS_PROFILE_STATE_ENABLED" == true ]]; then + test -d $(dirname ${AWS_STATE_FILE}) || exit 1 + echo -n > "${AWS_STATE_FILE}" + fi +} + # AWS profile selection function asp() { if [[ -z "$1" ]]; then - unset AWS_DEFAULT_PROFILE AWS_PROFILE AWS_EB_PROFILE + unset AWS_DEFAULT_PROFILE AWS_PROFILE AWS_EB_PROFILE AWS_PROFILE_REGION + _aws_clear_state echo AWS profile cleared. return fi @@ -22,11 +42,42 @@ function asp() { export AWS_PROFILE=$1 export AWS_EB_PROFILE=$1 + export AWS_PROFILE_REGION=$(aws configure get region) + + _aws_update_state + if [[ "$2" == "login" ]]; then - aws sso login + if [[ -n "$3" ]]; then + aws sso login --sso-session $3 + else + aws sso login + fi + elif [[ "$2" == "logout" ]]; then + aws sso logout fi } +# AWS region selection +function asr() { + if [[ -z "$1" ]]; then + unset AWS_DEFAULT_REGION AWS_REGION + _aws_update_state + echo AWS region cleared. + return + fi + + local -a available_regions + available_regions=($(aws_regions)) + if [[ -z "${available_regions[(r)$1]}" ]]; then + echo "${fg[red]}Available regions: \n$(aws_regions)" + return 1 + fi + + export AWS_REGION=$1 + export AWS_DEFAULT_REGION=$1 + _aws_update_state +} + # AWS profile switch function acp() { if [[ -z "$1" ]]; then @@ -135,21 +186,69 @@ function aws_change_access_key() { return 1 fi - echo "Insert the credentials when asked." - asp "$1" || return 1 - AWS_PAGER="" aws iam create-access-key - AWS_PAGER="" aws configure --profile "$1" + local profile="$1" + # Get current access key + local original_aws_access_key_id="$(aws configure get aws_access_key_id --profile $profile)" - echo "You can now safely delete the old access key running \`aws iam delete-access-key --access-key-id ID\`" + asp "$profile" || return 1 + echo "Generating a new access key pair for you now." + if aws --no-cli-pager iam create-access-key; then + echo "Insert the newly generated credentials when asked." + aws --no-cli-pager configure --profile $profile + else + echo "Current access keys:" + aws --no-cli-pager iam list-access-keys + echo "Profile \"${profile}\" is currently using the $original_aws_access_key_id key. You can delete an old access key by running \`aws --profile $profile iam delete-access-key --access-key-id AccessKeyId\`" + return 1 + fi + + read -q "yn?Would you like to disable your previous access key (${original_aws_access_key_id}) now? " + case $yn in + [Yy]*) + echo -n "\nDisabling access key ${original_aws_access_key_id}..." + if aws --no-cli-pager iam update-access-key --access-key-id ${original_aws_access_key_id} --status Inactive; then + echo "done." + else + echo "\nFailed to disable ${original_aws_access_key_id} key." + fi + ;; + *) + echo "" + ;; + esac + echo "You can now safely delete the old access key by running \`aws --profile $profile iam delete-access-key --access-key-id ${original_aws_access_key_id}\`" echo "Your current keys are:" - AWS_PAGER="" aws iam list-access-keys + aws --no-cli-pager iam list-access-keys +} + +function aws_regions() { + local region + if [[ $AWS_DEFAULT_REGION ]];then + region="$AWS_DEFAULT_REGION" + elif [[ $AWS_REGION ]];then + region="$AWS_REGION" + else + region="us-west-1" + fi + + if [[ $AWS_DEFAULT_PROFILE || $AWS_PROFILE ]];then + aws ec2 describe-regions --region $region |grep RegionName | awk -F ':' '{gsub(/"/, "", $2);gsub(/,/, "", $2);gsub(/ /, "", $2); print $2}' + else + echo "You must specify a AWS profile." + fi } function aws_profiles() { + aws --no-cli-pager configure list-profiles 2> /dev/null && return [[ -r "${AWS_CONFIG_FILE:-$HOME/.aws/config}" ]] || return 1 grep --color=never -Eo '\[.*\]' "${AWS_CONFIG_FILE:-$HOME/.aws/config}" | sed -E 's/^[[:space:]]*\[(profile)?[[:space:]]*([^[:space:]]+)\][[:space:]]*$/\2/g' } +function _aws_regions() { + reply=($(aws_regions)) +} +compctl -K _aws_regions asr + function _aws_profiles() { reply=($(aws_profiles)) } @@ -157,14 +256,40 @@ compctl -K _aws_profiles asp acp aws_change_access_key # AWS prompt function aws_prompt_info() { - [[ -n "$AWS_PROFILE" ]] || return - echo "${ZSH_THEME_AWS_PREFIX=}" + local _aws_to_show + local region="${AWS_REGION:-${AWS_DEFAULT_REGION:-$AWS_PROFILE_REGION}}" + + if [[ -n "$AWS_PROFILE" ]];then + _aws_to_show+="${ZSH_THEME_AWS_PROFILE_PREFIX=""}" + fi + + if [[ -n "$region" ]]; then + [[ -n "$_aws_to_show" ]] && _aws_to_show+="${ZSH_THEME_AWS_DIVIDER=" "}" + _aws_to_show+="${ZSH_THEME_AWS_REGION_PREFIX=""}" + fi + + echo "$_aws_to_show" } if [[ "$SHOW_AWS_PROMPT" != false && "$RPROMPT" != *'$(aws_prompt_info)'* ]]; then RPROMPT='$(aws_prompt_info)'"$RPROMPT" fi +if [[ "$AWS_PROFILE_STATE_ENABLED" == true ]]; then + AWS_STATE_FILE="${AWS_STATE_FILE:-/tmp/.aws_current_profile}" + test -s "${AWS_STATE_FILE}" || return + + aws_state=($(cat $AWS_STATE_FILE)) + + export AWS_DEFAULT_PROFILE="${aws_state[1]}" + export AWS_PROFILE="$AWS_DEFAULT_PROFILE" + export AWS_EB_PROFILE="$AWS_DEFAULT_PROFILE" + + test -z "${aws_state[2]}" && AWS_REGION=$(aws configure get region) + + export AWS_REGION=${AWS_REGION:-$aws_state[2]} + export AWS_DEFAULT_REGION="$AWS_REGION" +fi # Load awscli completions @@ -210,3 +335,4 @@ else [[ -r $_aws_zsh_completer_path ]] && source $_aws_zsh_completer_path unset _aws_zsh_completer_path _brew_prefix fi + diff --git a/zsh/plugins/azure/README.md b/zsh/plugins/azure/README.md new file mode 100644 index 0000000..f399308 --- /dev/null +++ b/zsh/plugins/azure/README.md @@ -0,0 +1,49 @@ +# azure + +This plugin provides completion support for [azure cli](https://docs.microsoft.com/en-us/cli/azure/) +and a few utilities to manage azure subscriptions and display them in the prompt. + +To use it, add `azure` to the plugins array in your zshrc file. + +```zsh +plugins=(... azure) +``` + +## Plugin commands + + +* `az_subscriptions`: lists the available subscriptions in the `AZURE_CONFIG_DIR` (default: `~/.azure/`). + Used to provide completion for the `azss` function. + +* `azgs`: gets the current value of `$azure_subscription`. + +* `azss []`: sets the `$azure_subscription`. + + +NOTE : because azure keeps the state of active subscription in ${AZURE_CONFIG_DIR:-$HOME/.azure/azureProfile.json}, the prompt command requires `jq` to be enabled to parse the file. If jq is not in the path the prompt will show nothing + +## Theme + +The plugin creates an `azure_prompt_info` function that you can use in your theme, which displays +the current `$azure_subscription`. It uses two variables to control how that is shown: + +- ZSH_THEME_AZURE_PREFIX: sets the prefix of the azure_subscription. Defaults to ``. + + +``` +RPROMPT='$(azure_prompt_info)' +``` + +## Develop + +On ubuntu get a working environment with : + +` docker run -it -v $(pwd):/mnt -w /mnt ubuntu bash` + +``` +apt install -y curl jq zsh git vim +sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" +curl -sL https://aka.ms/InstallAzureCLIDeb | bash +``` \ No newline at end of file diff --git a/zsh/plugins/azure/azure.plugin.zsh b/zsh/plugins/azure/azure.plugin.zsh new file mode 100644 index 0000000..b33b0f8 --- /dev/null +++ b/zsh/plugins/azure/azure.plugin.zsh @@ -0,0 +1,60 @@ +# AZ Get Subscriptions +function azgs() { + az account show --output tsv --query 'name' 2>/dev/null +} + +# AZ Subscription Selection +alias azss="az account set --subscription" + + +function az_subscriptions() { + az account list --all --output tsv --query '[*].name' 2> /dev/null +} + +function _az_subscriptions() { + reply=($(az_subscriptions)) +} +compctl -K _az_subscriptions azss + +# Azure prompt +function azure_prompt_info() { + [[ ! -f "${AZURE_CONFIG_DIR:-$HOME/.azure}/azureProfile.json" ]] && return + # azgs is too expensive, if we have jq, we enable the prompt + (( $+commands[jq] )) || return 1 + azgs=$(jq -r '.subscriptions[] | select(.isDefault==true) .name' "${AZURE_CONFIG_DIR:-$HOME/.azure}/azureProfile.json") + echo "${ZSH_THEME_AZURE_PREFIX:=}" +} + + +# Load az completions +function _az-homebrew-installed() { + # check if Homebrew is installed + (( $+commands[brew] )) || return 1 + + # if so, we assume it's default way to install brew + if [[ ${commands[brew]:t2} == bin/brew ]]; then + _brew_prefix="${commands[brew]:h:h}" # remove trailing /bin/brew + else + # ok, it is not in the default prefix + # this call to brew is expensive (about 400 ms), so at least let's make it only once + _brew_prefix=$(brew --prefix) + fi +} + + +# get az.completion.sh location from $PATH +_az_zsh_completer_path="$commands[az_zsh_completer.sh]" + +# otherwise check common locations +if [[ -z $_az_zsh_completer_path ]]; then + # Homebrew + if _az-homebrew-installed; then + _az_zsh_completer_path=$_brew_prefix/etc/bash_completion.d/az + # Linux + else + _az_zsh_completer_path=/etc/bash_completion.d/azure-cli + fi +fi + +[[ -r $_az_zsh_completer_path ]] && autoload -U +X bashcompinit && bashcompinit && source $_az_zsh_completer_path +unset _az_zsh_completer_path _brew_prefix diff --git a/zsh/plugins/battery/README.md b/zsh/plugins/battery/README.md index 18e5bd8..07e4e0b 100644 --- a/zsh/plugins/battery/README.md +++ b/zsh/plugins/battery/README.md @@ -12,6 +12,19 @@ Then, add the `battery_pct_prompt` function to your custom theme. For example: RPROMPT='$(battery_pct_prompt) ...' ``` +Also, you set the `BATTERY_CHARGING` variable to your favor. +For example: + +```zsh +BATTERY_CHARGING="⚡️" +``` + +You can see the power of your charger using the following setting (MacOS only) + +```zsh +BATTERY_SHOW_WATTS=true +``` + ## Requirements - On Linux, you must have the `acpi` or `acpitool` commands installed on your operating system. diff --git a/zsh/plugins/battery/battery.plugin.zsh b/zsh/plugins/battery/battery.plugin.zsh index db5eeb9..c7618f6 100644 --- a/zsh/plugins/battery/battery.plugin.zsh +++ b/zsh/plugins/battery/battery.plugin.zsh @@ -13,8 +13,17 @@ # Author: Avneet Singh (kalsi-avneet) # # Modified to add support for Android # ########################################### +# Author: Not Pua (im-notpua) # +# Modified to add support for OpenBSD # +########################################### + +: ${BATTERY_SHOW_WATTS:=false} + if [[ "$OSTYPE" = darwin* ]]; then + function get_charger_power() { + echo "$(ioreg -rc AppleSmartBattery | grep -o '"Watts"=[0-9]\+' | head -1 | grep -o '[0-9]\+')W " + } function battery_is_charging() { ioreg -rc AppleSmartBattery | command grep -q '^.*"ExternalConnected"\ =\ Yes' } @@ -54,7 +63,10 @@ if [[ "$OSTYPE" = darwin* ]]; then fi echo "%{$fg[$color]%}[${battery_pct}%%]%{$reset_color%}" else - echo "∞" + if [[ "${BATTERY_SHOW_WATTS}" = "true" ]] ; then + watts=$(get_charger_power) + fi + echo "${watts}${BATTERY_CHARGING-⚡️}" fi } @@ -139,6 +151,46 @@ elif [[ "$OSTYPE" = linux-android ]] && (( ${+commands[termux-battery-status]} ) echo "%{$fg[$color]%}${battery_pct}%%%{$reset_color%}" fi } +elif [[ "$OSTYPE" = openbsd* ]]; then + function battery_is_charging() { + [[ $(apm -b) -eq 3 ]] + } + function battery_pct() { + apm -l + } + function battery_pct_remaining() { + if ! battery_is_charging; then + battery_pct + else + echo "External Power" + fi + } + function battery_time_remaining() { + local remaining_time + remaining_time=$(apm -m) + if [[ $remaining_time -ge 0 ]]; then + ((hour = $remaining_time / 60 )) + ((minute = $remaining_time % 60 )) + printf %02d:%02d $hour $minute + fi + } + function battery_pct_prompt() { + local battery_pct color + battery_pct=$(battery_pct_remaining) + if battery_is_charging; then + echo "∞" + else + if [[ $battery_pct -gt 50 ]]; then + color='green' + elif [[ $battery_pct -gt 20 ]]; then + color='yellow' + else + color='red' + fi + echo "%{$fg[$color]%}${battery_pct}%%%{$reset_color%}" + fi + } + elif [[ "$OSTYPE" = linux* ]]; then function battery_is_charging() { if (( $+commands[acpitool] )); then diff --git a/zsh/plugins/bazel/README.md b/zsh/plugins/bazel/README.md index fc375d2..b0c34a1 100644 --- a/zsh/plugins/bazel/README.md +++ b/zsh/plugins/bazel/README.md @@ -1,7 +1,7 @@ # Bazel plugin -This plugin adds completion for [bazel](https://bazel.build), an open-source build and -test tool that scalably supports multi-language and multi-platform projects. +This plugin adds completion and aliases for [bazel](https://bazel.build), an open-source build and test tool +that scalably supports multi-language and multi-platform projects. To use it, add `bazel` to the plugins array in your zshrc file: @@ -12,3 +12,18 @@ plugins=(... bazel) The plugin has a copy of [the completion script from the git repository][1]. [1]: https://github.com/bazelbuild/bazel/blob/master/scripts/zsh_completion/_bazel + +## Aliases + +| Alias | Command | Description | +| ----- | ------------- | ------------------------- | +| bzb | `bazel build` | The `bazel build` command | +| bzt | `bazel test` | The `bazel test` command | +| bzr | `bazel run` | The `bazel run` command | +| bzq | `bazel query` | The `bazel query` command | + +## Functions + +| Function | Description | +| -------- | -------------------------------- | +| sri-hash | Generate SRI hash used by bzlmod | diff --git a/zsh/plugins/bazel/_bazel b/zsh/plugins/bazel/_bazel index c34c572..ea1f4ca 100644 --- a/zsh/plugins/bazel/_bazel +++ b/zsh/plugins/bazel/_bazel @@ -1,4 +1,4 @@ -#compdef bazel +#compdef bazel bazelisk # Copyright 2015 The Bazel Authors. All rights reserved. # diff --git a/zsh/plugins/bazel/bazel.plugin.zsh b/zsh/plugins/bazel/bazel.plugin.zsh new file mode 100644 index 0000000..818d565 --- /dev/null +++ b/zsh/plugins/bazel/bazel.plugin.zsh @@ -0,0 +1,9 @@ +# Aliases for bazel +alias bzb='bazel build' +alias bzt='bazel test' +alias bzr='bazel run' +alias bzq='bazel query' + +sri-hash() { + openssl dgst -sha256 -binary $1 | openssl base64 -A | sed 's/^/sha256-/' +} diff --git a/zsh/plugins/bedtools/_bedtools b/zsh/plugins/bedtools/_bedtools index ef6c417..15e3dc2 100644 --- a/zsh/plugins/bedtools/_bedtools +++ b/zsh/plugins/bedtools/_bedtools @@ -47,7 +47,7 @@ case $state in "random[Generate random intervals in a genome.]" \ "reldist[Calculate the distribution of relative distances b/w two files.]" \ "sample[Sample random records from file using reservoir sampling.]" \ - "shuffle[Randomly redistrubute intervals in a genome.]" \ + "shuffle[Randomly redistribute intervals in a genome.]" \ "slop[Adjust the size of intervals.]" \ "sort[Order the intervals in a file.]" \ "subtract[Remove intervals based on overlaps b/w two files.]" \ diff --git a/zsh/plugins/bgnotify/README.md b/zsh/plugins/bgnotify/README.md index 1d8fac5..1389def 100644 --- a/zsh/plugins/bgnotify/README.md +++ b/zsh/plugins/bgnotify/README.md @@ -1,19 +1,19 @@ # bgnotify zsh plugin -cross-platform background notifications for long running commands! Supports OSX and Ubuntu linux. +cross-platform background notifications for long running commands! Supports OSX and Linux. Standalone homepage: [t413/zsh-background-notify](https://github.com/t413/zsh-background-notify) ----------------------------------- +--- -## How to use! +## How to use Just add bgnotify to your plugins list in your `.zshrc` - On OS X you'll need [terminal-notifier](https://github.com/alloy/terminal-notifier) * `brew install terminal-notifier` (or `gem install terminal-notifier`) -- On ubuntu you're already all set! -- On windows you can use [notifu](https://www.paralint.com/projects/notifu/) or the Cygwin Ports libnotify package +- On Linux, make sure you have `notify-send` or `kdialog` installed. If you're using Ubuntu you should already be all set! +- On Windows you can use [notifu](https://www.paralint.com/projects/notifu/) or the Cygwin Ports libnotify package ## Screenshots @@ -35,20 +35,30 @@ Just add bgnotify to your plugins list in your `.zshrc` One can configure a few things: +- `bgnotify_bell` enabled or disables the terminal bell (default true) - `bgnotify_threshold` sets the notification threshold time (default 6 seconds) -- `function bgnotify_formatted` lets you change the notification +- `function bgnotify_formatted` lets you change the notification. You can for instance customize the message and pass in an icon. +- `bgnotify_extraargs` appends extra args to notifier (e.g. `-e` for notify-send to create a transient notification) Use these by adding a function definition before the your call to source. Example: -~~~ sh +```sh +bgnotify_bell=false ## disable terminal bell bgnotify_threshold=4 ## set your own notification threshold function bgnotify_formatted { ## $1=exit_status, $2=command, $3=elapsed_time - [ $1 -eq 0 ] && title="Holy Smokes Batman!" || title="Holy Graf Zeppelin!" - bgnotify "$title -- after $3 s" "$2"; + + # Humanly readable elapsed time + local elapsed="$(( $3 % 60 ))s" + (( $3 < 60 )) || elapsed="$((( $3 % 3600) / 60 ))m $elapsed" + (( $3 < 3600 )) || elapsed="$(( $3 / 3600 ))h $elapsed" + + [ $1 -eq 0 ] && title="Holy Smokes Batman" || title="Holy Graf Zeppelin" + [ $1 -eq 0 ] && icon="$HOME/icons/success.png" || icon="$HOME/icons/fail.png" + bgnotify "$title - took ${elapsed}" "$2" "$icon" } plugins=(git bgnotify) ## add to plugins list source $ZSH/oh-my-zsh.sh ## existing source call -~~~ +``` diff --git a/zsh/plugins/bgnotify/bgnotify.plugin.zsh b/zsh/plugins/bgnotify/bgnotify.plugin.zsh index 479796d..4c1613e 100644 --- a/zsh/plugins/bgnotify/bgnotify.plugin.zsh +++ b/zsh/plugins/bgnotify/bgnotify.plugin.zsh @@ -1,93 +1,144 @@ #!/usr/bin/env zsh -## setup ## +## Setup -[[ -o interactive ]] || return #interactive only! -zmodload zsh/datetime || { print "can't load zsh/datetime"; return } # faster than date() -autoload -Uz add-zsh-hook || { print "can't add zsh hook!"; return } +[[ -o interactive ]] || return # don't load on non-interactive shells +[[ -z "$SSH_CLIENT" && -z "$SSH_TTY" ]] || return # don't load on a SSH connection -(( ${+bgnotify_threshold} )) || bgnotify_threshold=5 #default 10 seconds +zmodload zsh/datetime # faster than `date` -## definitions ## +## Zsh Hooks -if ! (type bgnotify_formatted | grep -q 'function'); then ## allow custom function override - function bgnotify_formatted { ## args: (exit_status, command, elapsed_seconds) - elapsed="$(( $3 % 60 ))s" - (( $3 >= 60 )) && elapsed="$((( $3 % 3600) / 60 ))m $elapsed" - (( $3 >= 3600 )) && elapsed="$(( $3 / 3600 ))h $elapsed" - [ $1 -eq 0 ] && bgnotify "#win (took $elapsed)" "$2" || bgnotify "#fail (took $elapsed)" "$2" - } -fi - -currentAppId () { - if (( $+commands[osascript] )); then - osascript -e 'tell application (path to frontmost application as text) to id' 2>/dev/null - fi -} - -currentWindowId () { - if hash osascript 2>/dev/null; then #osx - osascript -e 'tell application (path to frontmost application as text) to id of front window' 2&> /dev/null || echo "0" - elif (hash notify-send 2>/dev/null || hash kdialog 2>/dev/null); then #ubuntu! - xprop -root 2> /dev/null | awk '/NET_ACTIVE_WINDOW/{print $5;exit} END{exit !$5}' || echo "0" - else - echo $EPOCHSECONDS #fallback for windows - fi -} - -bgnotify () { ## args: (title, subtitle) - if hash terminal-notifier 2>/dev/null; then #osx - local term_id="$bgnotify_appid" - if [[ -z "$term_id" ]]; then - case "$TERM_PROGRAM" in - iTerm.app) term_id='com.googlecode.iterm2' ;; - Apple_Terminal) term_id='com.apple.terminal' ;; - esac - fi - - ## now call terminal-notifier, (hopefully with $term_id!) - if [[ -z "$term_id" ]]; then - terminal-notifier -message "$2" -title "$1" >/dev/null - else - terminal-notifier -message "$2" -title "$1" -activate "$term_id" -sender "$term_id" >/dev/null - fi - elif hash growlnotify 2>/dev/null; then #osx growl - growlnotify -m "$1" "$2" - elif hash notify-send 2>/dev/null; then #ubuntu gnome! - notify-send "$1" "$2" - elif hash kdialog 2>/dev/null; then #ubuntu kde! - kdialog --title "$1" --passivepopup "$2" 5 - elif hash notifu 2>/dev/null; then #cygwyn support! - notifu /m "$2" /p "$1" - fi -} - - -## Zsh hooks ## - -bgnotify_begin() { +function bgnotify_begin { bgnotify_timestamp=$EPOCHSECONDS bgnotify_lastcmd="${1:-$2}" - bgnotify_appid="$(currentAppId)" - bgnotify_windowid=$(currentWindowId) } -bgnotify_end() { - didexit=$? - elapsed=$(( EPOCHSECONDS - bgnotify_timestamp )) - past_threshold=$(( elapsed >= bgnotify_threshold )) - if (( bgnotify_timestamp > 0 )) && (( past_threshold )); then - if [[ $(currentAppId) != "$bgnotify_appid" || $(currentWindowId) != "$bgnotify_windowid" ]]; then - print -n "\a" - bgnotify_formatted "$didexit" "$bgnotify_lastcmd" "$elapsed" - fi +function bgnotify_end { + { + local exit_status=$? + local elapsed=$(( EPOCHSECONDS - bgnotify_timestamp )) + + # check time elapsed + [[ $bgnotify_timestamp -gt 0 ]] || return 0 + [[ $elapsed -ge $bgnotify_threshold ]] || return 0 + + # check if Terminal app is not active + [[ $(bgnotify_appid) != "$bgnotify_termid" ]] || return 0 + + bgnotify_formatted "$exit_status" "$bgnotify_lastcmd" "$elapsed" + } always { + bgnotify_timestamp=0 + } +} + +autoload -Uz add-zsh-hook +add-zsh-hook preexec bgnotify_begin +add-zsh-hook precmd bgnotify_end + + +## Functions + +# allow custom function override +(( ${+functions[bgnotify_formatted]} )) || \ +function bgnotify_formatted { + local exit_status=$1 + local cmd="$2" + + # humanly readable elapsed time + local elapsed="$(( $3 % 60 ))s" + (( $3 < 60 )) || elapsed="$((( $3 % 3600) / 60 ))m $elapsed" + (( $3 < 3600 )) || elapsed="$(( $3 / 3600 ))h $elapsed" + + [[ $bgnotify_bell = true ]] && printf '\a' # beep sound + if [[ $exit_status -eq 0 ]]; then + bgnotify "#win (took $elapsed)" "$cmd" + else + bgnotify "#fail (took $elapsed)" "$cmd" fi - bgnotify_timestamp=0 #reset it to 0! } -## only enable if a local (non-ssh) connection -if [ -z "$SSH_CLIENT" ] && [ -z "$SSH_TTY" ]; then - add-zsh-hook preexec bgnotify_begin - add-zsh-hook precmd bgnotify_end -fi +function bgnotify_appid { + if (( ${+commands[lsappinfo]} )); then + lsappinfo info -only bundleid "$(lsappinfo front)" | awk -F= '{print $2}' | tr -d '"' 2>/dev/null + elif (( ${+commands[osascript]} )); then + osascript -e "tell application id \"$(bgnotify_programid)\" to get the {id, frontmost, id of front window, visible of front window}" 2>/dev/null + elif [[ -n $WAYLAND_DISPLAY ]] && ([[ -n $SWAYSOCK ]] || [[ -n $I3SOCK ]]) && (( ${+commands[swaymsg]} )); then # wayland+sway + local app_id=$(bgnotify_find_sway_appid) + [[ -n "$app_id" ]] && echo "$app_id" || echo $EPOCHSECONDS + elif [[ -z $WAYLAND_DISPLAY ]] && [[ -n $DISPLAY ]] && (( ${+commands[xprop]} )); then + xprop -root _NET_ACTIVE_WINDOW 2>/dev/null | cut -d' ' -f5 + else + echo $EPOCHSECONDS + fi +} + + +function bgnotify_find_sway_appid { + # output is "app_id,container_id", for example "Alacritty,1694" + # see example swaymsg output: https://github.com/ohmyzsh/ohmyzsh/files/13463939/output.json + if (( ${+commands[jq]} )); then + swaymsg -t get_tree | jq '.. | select(.type?) | select(.focused==true) | {app_id, id} | join(",")' + else + swaymsg -t get_tree | awk ' + BEGIN { Id = ""; Appid = ""; FocusNesting = -1; Nesting = 0 } + { + # Enter a block + if ($0 ~ /.*{$/) Nesting++ + + # Exit a block. If Nesting is now less than FocusNesting, we have the data we are looking for + if ($0 ~ /^[[:blank:]]*}.*/) { Nesting--; if (FocusNesting > 0 && Nesting < FocusNesting) exit 0 } + + # Save the Id, it is potentially what we are looking for + if ($0 ~ /^[[:blank:]]*"id": [0-9]*,?$/) { sub(/^[[:blank:]]*"id": /, ""); sub(/,$/, ""); Id = $0 } + + # Save the Appid, it is potentially what we are looking for + if ($0 ~ /^[[:blank:]]*"app_id": ".*",?$/) { sub(/^[[:blank:]]*"app_id": "/, ""); sub(/",$/, ""); Appid = $0 } + + # Window is focused, this nesting block contains the Id and Appid we want! + if ($0 ~ /^[[:blank:]]*"focused": true,?$/) { FocusNesting = Nesting } + } + END { + if (Appid != "" && Id != "" && FocusNesting != -1) print Appid "," Id + else print "" + }' + fi +} + +function bgnotify_programid { + case "$TERM_PROGRAM" in + iTerm.app) echo 'com.googlecode.iterm2' ;; + Apple_Terminal) echo 'com.apple.terminal' ;; + ghostty) echo 'com.mitchellh.ghostty' ;; + esac +} + +function bgnotify { + local title="$1" + local message="$2" + local icon="$3" + if (( ${+commands[terminal-notifier]} )); then # macOS + local term_id=$(bgnotify_programid) + terminal-notifier -message "$message" -title "$title" ${=icon:+-appIcon "$icon"} ${=term_id:+-activate "$term_id"} ${=bgnotify_extraargs:-} &>/dev/null + elif (( ${+commands[growlnotify]} )); then # macOS growl + growlnotify -m "$title" "$message" ${=bgnotify_extraargs:-} + elif (( ${+commands[notify-send]} )); then + notify-send "$title" "$message" ${=icon:+--icon "$icon"} ${=bgnotify_extraargs:-} + elif (( ${+commands[kdialog]} )); then # KDE + kdialog --title "$title" --passivepopup "$message" 5 ${=bgnotify_extraargs:-} + elif (( ${+commands[notifu]} )); then # cygwin + notifu /m "$message" /p "$title" ${=icon:+/i "$icon"} ${=bgnotify_extraargs:-} + fi +} + +## Defaults + +# enable terminal bell on notify by default +bgnotify_bell=${bgnotify_bell:-true} + +# notify if command took longer than 5s by default +bgnotify_threshold=${bgnotify_threshold:-5} + +# bgnotify_appid is slow in macOS and the terminal ID won't change, so cache it at startup +bgnotify_termid="$(bgnotify_appid)" diff --git a/zsh/plugins/branch/README.md b/zsh/plugins/branch/README.md index a15dd22..2b6d12d 100644 --- a/zsh/plugins/branch/README.md +++ b/zsh/plugins/branch/README.md @@ -39,7 +39,7 @@ index 2fd5f2cd..9d89a464 100644 PROMPT="%(?:%{$fg_bold[green]%}➜ :%{$fg_bold[red]%}➜ )" -PROMPT+=' %{$fg[cyan]%}%c%{$reset_color%} $(git_prompt_info)' +PROMPT+=' %{$fg[cyan]%}%c%{$reset_color%} $(branch_prompt_info)' - + ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_bold[blue]%}git:(%{$fg[red]%}" ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%} " ``` diff --git a/zsh/plugins/branch/branch.plugin.zsh b/zsh/plugins/branch/branch.plugin.zsh index dd5871f..c24f909 100644 --- a/zsh/plugins/branch/branch.plugin.zsh +++ b/zsh/plugins/branch/branch.plugin.zsh @@ -8,7 +8,7 @@ function branch_prompt_info() { while [[ "$dir" != '/' ]]; do # Found .git directory if [[ -d "${dir}/.git" ]]; then - branch="${"$(<"${dir}/.git/HEAD")"##*/}" + branch="${"$(<"${dir}/.git/HEAD")"##ref: refs/heads/}" echo '±' "${branch:gs/%/%%}" return fi diff --git a/zsh/plugins/brew/README.md b/zsh/plugins/brew/README.md index 9ce2c5b..ab0b9cd 100644 --- a/zsh/plugins/brew/README.md +++ b/zsh/plugins/brew/README.md @@ -10,28 +10,59 @@ plugins=(... brew) ## Shellenv -If `brew` is not found in the PATH, this plugin will attempt to find it in common -locations, and execute `brew shellenv` to set the environment appropriately. -This plugin will also export `HOMEBREW_PREFIX="$(brew --prefix)"` if not previously -defined for convenience. +If `brew` is not found in the PATH, this plugin will attempt to find it in common locations, and execute +`brew shellenv` to set the environment appropriately. This plugin will also export +`HOMEBREW_PREFIX="$(brew --prefix)"` if not previously defined for convenience. + +In case you installed `brew` in a non-common location, you can still set `BREW_LOCATION` variable pointing to +the `brew` binary before sourcing `oh-my-zsh.sh` and it'll set up the environment. ## Aliases -| Alias | Command | Description | -| -------- | ------------------------------------- | ------------------------------------------------------------------- | -| `bcubc` | `brew upgrade --cask && brew cleanup` | Update outdated casks, then run cleanup. | -| `bcubo` | `brew update && brew outdated --cask` | Update Homebrew data, then list outdated casks. | -| `brewp` | `brew pin` | Pin a specified formula so that it's not upgraded. | -| `brews` | `brew list -1` | List installed formulae or the installed files for a given formula. | -| `brewsp` | `brew list --pinned` | List pinned formulae, or show the version of a given formula. | -| `bubc` | `brew upgrade && brew cleanup` | Upgrade outdated formulae and casks, then run cleanup. | -| `bubo` | `brew update && brew outdated` | Update Homebrew data, then list outdated formulae and casks. | -| `bubu` | `bubo && bubc` | Do the last two operations above. | -| `buf` | `brew upgrade --formula` | Upgrade only formulas (not casks). | +| Alias | Command | Description | +| -------- | --------------------------------------- | --------------------------------------------------------------------- | +| `ba` | `brew autoremove` | Uninstall unnecessary formulae. | +| `bcfg` | `brew config` | Show Homebrew and system configuration info useful for debugging. | +| `bci` | `brew info --cask` | Display information about the given cask. | +| `bcin` | `brew install --cask` | Install the given cask. | +| `bcl` | `brew list --cask` | List installed casks. | +| `bcn` | `brew cleanup` | Run cleanup. | +| `bco` | `brew outdated --cask` | Report all outdated casks. | +| `bcrin` | `brew reinstall --cask` | Reinstall the given cask. | +| `bcubc` | `brew upgrade --cask && brew cleanup` | Upgrade outdated casks, then run cleanup. | +| `bcubo` | `brew update && brew outdated --cask` | Update Homebrew data, then list outdated casks. | +| `bcup` | `brew upgrade --cask` | Upgrade all outdated casks. | +| `bdr` | `brew doctor` | Check your system for potential problems. | +| `bfu` | `brew upgrade --formula` | Upgrade only formulae (not casks). | +| `bi` | `brew install` | Install a formula. | +| `bih` | `brew install --HEAD` | Install a formula with --HEAD | +| `bl` | `brew list` | List all installed formulae. | +| `bo` | `brew outdated` | List installed formulae that have an updated version available. | +| `br` | `brew reinstall` | Reinstall a formula. | +| `brewp` | `brew pin` | Pin a specified formula so that it's not upgraded. | +| `brews` | `brew list -1` | List installed formulae or the installed files for a given formula. | +| `brewsp` | `brew list --pinned` | List pinned formulae, or show the version of a given formula. | +| `brh` | `brew reinstall --HEAD` | Reinstall a formula with --HEAD | +| `bs` | `brew search` | Perform a substring search of cask tokens and formula names for text. | +| `bsl` | `brew services list` | List all running services. | +| `bsoff` | `brew services stop` | Stop the service and unregister it from launching at login (or boot). | +| `bsoffa` | `bsoff --all` | Stop all started services. | +| `bson` | `brew services start` | Start the service and register it to launch at login (or boot). | +| `bsona` | `bson --all` | Start all stopped services. | +| `bsr` | `brew services run` | Run the service without registering to launch at login (or boot). | +| `bsra` | `bsr --all` | Run all stopped services. | +| `bu` | `brew update` | Update brew and all installed formulae. | +| `bubo` | `brew update && brew outdated` | Update Homebrew data, then list outdated formulae and casks. | +| `bubu` | `bubo && bup` | Do the last two operations above. | +| `bugbc` | `brew upgrade --greedy && brew cleanup` | Upgrade outdated formulae and casks (greedy), then run cleanup. | +| `bup` | `brew upgrade` | Upgrade outdated, unpinned brews. | +| `buz` | `brew uninstall --zap` | Remove all files associated with a cask. | ## Completion -With the release of Homebrew 1.0, they decided to bundle the zsh completion as part of the -brew installation, so we no longer ship it with the brew plugin; now it only has brew -aliases. If you find that brew completion no longer works, make sure you have your Homebrew -installation fully up to date. +This plugin configures paths with Homebrew's completion functions automatically, so you don't need to do it +manually. See: https://docs.brew.sh/Shell-Completion#configuring-completions-in-zsh. + +With the release of Homebrew 1.0, they decided to bundle the zsh completion as part of the brew installation, +so we no longer ship it with the brew plugin; now it only has brew aliases. If you find that brew completion +no longer works, make sure you have your Homebrew installation fully up to date. diff --git a/zsh/plugins/brew/brew.plugin.zsh b/zsh/plugins/brew/brew.plugin.zsh index 41420b5..7d5db20 100644 --- a/zsh/plugins/brew/brew.plugin.zsh +++ b/zsh/plugins/brew/brew.plugin.zsh @@ -1,5 +1,10 @@ if (( ! $+commands[brew] )); then - if [[ -x /opt/homebrew/bin/brew ]]; then + if [[ -n "$BREW_LOCATION" ]]; then + if [[ ! -x "$BREW_LOCATION" ]]; then + echo "[oh-my-zsh] $BREW_LOCATION is not executable" + return + fi + elif [[ -x /opt/homebrew/bin/brew ]]; then BREW_LOCATION="/opt/homebrew/bin/brew" elif [[ -x /usr/local/bin/brew ]]; then BREW_LOCATION="/usr/local/bin/brew" @@ -19,24 +24,56 @@ if (( ! $+commands[brew] )); then fi if [[ -z "$HOMEBREW_PREFIX" ]]; then - # Maintain compatability with potential custom user profiles, where we had + # Maintain compatibility with potential custom user profiles, where we had # previously relied on always sourcing shellenv. OMZ plugins should not rely # on this to be defined due to out of order processing. export HOMEBREW_PREFIX="$(brew --prefix)" fi +if [[ -d "$HOMEBREW_PREFIX/share/zsh/site-functions" ]]; then + fpath+=("$HOMEBREW_PREFIX/share/zsh/site-functions") +fi + +alias ba='brew autoremove' +alias bcfg='brew config' +alias bci='brew info --cask' +alias bcin='brew install --cask' +alias bcl='brew list --cask' +alias bcn='brew cleanup' +alias bco='brew outdated --cask' +alias bcrin='brew reinstall --cask' alias bcubc='brew upgrade --cask && brew cleanup' alias bcubo='brew update && brew outdated --cask' +alias bcup='brew upgrade --cask' +alias bdr='brew doctor' +alias bfu='brew upgrade --formula' +alias bi='brew install' +alias bih='brew install --HEAD' +alias bl='brew list' +alias bo='brew outdated' +alias br='brew reinstall' alias brewp='brew pin' alias brewsp='brew list --pinned' -alias bubc='brew upgrade && brew cleanup' +alias brh='brew reinstall --HEAD' +alias bs='brew search' +alias bsl='brew services list' +alias bsoff='brew services stop' +alias bsoffa='bsoff --all' +alias bson='brew services start' +alias bsona='bson --all' +alias bsr='brew services run' +alias bsra='bsr --all' +alias bu='brew update' alias bubo='brew update && brew outdated' -alias bubu='bubo && bubc' -alias buf='brew upgrade --formula' +alias bubu='bubo && bup' +alias bubug='bubo && bugbc' +alias bugbc='brew upgrade --greedy && brew cleanup' +alias bup='brew upgrade' +alias buz='brew uninstall --zap' function brews() { local formulae="$(brew leaves | xargs brew deps --installed --for-each)" - local casks="$(brew list --cask)" + local casks="$(brew list --cask 2>/dev/null)" local blue="$(tput setaf 4)" local bold="$(tput bold)" diff --git a/zsh/plugins/bridgetown/README.md b/zsh/plugins/bridgetown/README.md new file mode 100644 index 0000000..0a41814 --- /dev/null +++ b/zsh/plugins/bridgetown/README.md @@ -0,0 +1,26 @@ +# Bridgetown plugin + +This plugin adds some aliases and autocompletion for common [Bridgetown](https://bridgetownrb.com/) commands. + +To use it, add `bridgetown` to the plugins array in your zshrc file: + +```zsh +plugins=(... bridgetown) +``` + +## Aliases + +| Alias | Command | +|-------|----------------------------| +| br | `bridgetown` | +| bra | `bin/bridgetown apply` | +| brb | `bin/bridgetown build` | +| brc | `bin/bridgetown console` | +| brclean | `bin/bridgetown clean` | +| brd | `bin/bridgetown deploy` | +| brdoc | `bin/bridgetown doctor` | +| brh | `bin/bridgetown help` | +| brn | `bridgetown new` | +| brp | `bridgetown plugins` | +| brpl | `bridgetown plugins list` | +| brs | `bin/bridgetown start` | diff --git a/zsh/plugins/bridgetown/bridgetown.plugin.zsh b/zsh/plugins/bridgetown/bridgetown.plugin.zsh new file mode 100644 index 0000000..502e9df --- /dev/null +++ b/zsh/plugins/bridgetown/bridgetown.plugin.zsh @@ -0,0 +1,12 @@ +alias br='bridgetown' +alias bra='bin/bridgetown apply' +alias brb='bin/bridgetown build' +alias brc='bin/bridgetown console' +alias brclean='bin/bridgetown clean' +alias brd='bin/bridgetown deploy' +alias brdoc='bin/bridgetown doctor' +alias brh='bin/bridgetown help' +alias brn='bridgetown new' +alias brp='bridgetown plugins' +alias brpl='bridgetown plugins list' +alias brs='bin/bridgetown start' diff --git a/zsh/plugins/buf/README.md b/zsh/plugins/buf/README.md new file mode 100644 index 0000000..946cf38 --- /dev/null +++ b/zsh/plugins/buf/README.md @@ -0,0 +1,9 @@ +# Buf plugin + +This plugin adds completion for [Buf CLI](https://github.com/bufbuild/buf), a tool working with Protocol Buffers. + +To use it, add `buf` to the plugins array in your zshrc file: + +```zsh +plugins=(... buf) +``` \ No newline at end of file diff --git a/zsh/plugins/buf/buf.plugin.zsh b/zsh/plugins/buf/buf.plugin.zsh new file mode 100644 index 0000000..0b251ac --- /dev/null +++ b/zsh/plugins/buf/buf.plugin.zsh @@ -0,0 +1,14 @@ +# Autocompletion for the Buf CLI (buf). +if (( !$+commands[buf] )); then + return +fi +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `buf`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_buf" ]]; then + typeset -g -A _comps + autoload -Uz _buf + _comps[buf]=_buf +fi + +# Generate and load buf completion +buf completion zsh >! "$ZSH_CACHE_DIR/completions/_buf" &| \ No newline at end of file diff --git a/zsh/plugins/bun/README.md b/zsh/plugins/bun/README.md new file mode 100644 index 0000000..5a31237 --- /dev/null +++ b/zsh/plugins/bun/README.md @@ -0,0 +1,20 @@ +# Bun Plugin + +This plugin sets up completion for [Bun](https://bun.sh). + +To use it, add `bun` to the plugins array in your zshrc file: + +```zsh +plugins=(... bun) +``` + +This plugin does not add any aliases. + +## Cache + +This plugin caches the completion script and is automatically updated when the +plugin is loaded, which is usually when you start up a new terminal emulator. + +The cache is stored at: + +- `$ZSH_CACHE_DIR/completions/_bun_` completions script diff --git a/zsh/plugins/bun/bun.plugin.zsh b/zsh/plugins/bun/bun.plugin.zsh new file mode 100644 index 0000000..576dbbf --- /dev/null +++ b/zsh/plugins/bun/bun.plugin.zsh @@ -0,0 +1,14 @@ +# If Bun is not found, don't do the rest of the script +if (( ! $+commands[bun] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `bun`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_bun" ]]; then + typeset -g -A _comps + autoload -Uz _bun + _comps[bun]=_bun +fi + +SHELL=zsh bun completions >| "$ZSH_CACHE_DIR/completions/_bun" &| diff --git a/zsh/plugins/bundler/README.md b/zsh/plugins/bundler/README.md index 7b79cbc..ddf5472 100644 --- a/zsh/plugins/bundler/README.md +++ b/zsh/plugins/bundler/README.md @@ -11,18 +11,18 @@ plugins=(... bundler) ## Aliases -| Alias | Command | Description | -|--------|--------------------------------------|------------------------------------------------------------------------------------------| -| `ba` | `bundle add` | Add gem to the Gemfile and run bundle install | -| `bck` | `bundle check` | Verifies if dependencies are satisfied by installed gems | -| `bcn` | `bundle clean` | Cleans up unused gems in your bundler directory | -| `be` | `bundle exec` | Execute a command in the context of the bundle | -| `bi` | `bundle install --jobs=` | Install the dependencies specified in your Gemfile (using all cores in bundler >= 1.4.0) | -| `bl` | `bundle list` | List all the gems in the bundle | -| `bo` | `bundle open` | Opens the source directory for a gem in your bundle | -| `bout` | `bundle outdated` | List installed gems with newer versions available | -| `bp` | `bundle package` | Package your needed .gem files into your application | -| `bu` | `bundle update` | Update your gems to the latest available versions | +| Alias | Command | Description | +| ------ | ----------------- | -------------------------------------------------------- | +| `ba` | `bundle add` | Add gem to the Gemfile and run bundle install | +| `bck` | `bundle check` | Verifies if dependencies are satisfied by installed gems | +| `bcn` | `bundle clean` | Cleans up unused gems in your bundler directory | +| `be` | `bundle exec` | Execute a command in the context of the bundle | +| `bi` | `bundle install` | Install the dependencies specified in your Gemfile | +| `bl` | `bundle list` | List all the gems in the bundle | +| `bo` | `bundle open` | Opens the source directory for a gem in your bundle | +| `bout` | `bundle outdated` | List installed gems with newer versions available | +| `bp` | `bundle package` | Package your needed .gem files into your application | +| `bu` | `bundle update` | Update your gems to the latest available versions | ## Gem wrapper diff --git a/zsh/plugins/bundler/_bundler b/zsh/plugins/bundler/_bundler index 51678dd..6613cc6 100644 --- a/zsh/plugins/bundler/_bundler +++ b/zsh/plugins/bundler/_bundler @@ -1,4 +1,4 @@ -#compdef bundle +#compdef bundle bundler local curcontext="$curcontext" state line _gems _opts ret=1 diff --git a/zsh/plugins/bundler/bundler.plugin.zsh b/zsh/plugins/bundler/bundler.plugin.zsh index c1cbb13..53b36f0 100644 --- a/zsh/plugins/bundler/bundler.plugin.zsh +++ b/zsh/plugins/bundler/bundler.plugin.zsh @@ -4,45 +4,13 @@ alias ba="bundle add" alias bck="bundle check" alias bcn="bundle clean" alias be="bundle exec" -alias bi="bundle_install" +alias bi="bundle install" alias bl="bundle list" alias bo="bundle open" alias bout="bundle outdated" alias bp="bundle package" alias bu="bundle update" -## Functions - -bundle_install() { - # Bail out if bundler is not installed - if (( ! $+commands[bundle] )); then - echo "Bundler is not installed" - return 1 - fi - - # Bail out if not in a bundled project - if ! _within-bundled-project; then - echo "Can't 'bundle install' outside a bundled project" - return 1 - fi - - # Check the bundler version is at least 1.4.0 - autoload -Uz is-at-least - local bundler_version=$(bundle version | cut -d' ' -f3) - if ! is-at-least 1.4.0 "$bundler_version"; then - bundle install "$@" - return $? - fi - - # If bundler is at least 1.4.0, use all the CPU cores to bundle install - if [[ "$OSTYPE" = (darwin|freebsd)* ]]; then - local cores_num="$(sysctl -n hw.ncpu)" - else - local cores_num="$(nproc)" - fi - BUNDLE_JOBS="$cores_num" bundle install "$@" -} - ## Gem wrapper bundled_commands=( diff --git a/zsh/plugins/cakephp3/cakephp3.plugin.zsh b/zsh/plugins/cakephp3/cakephp3.plugin.zsh index dbfbeba..a1a289f 100644 --- a/zsh/plugins/cakephp3/cakephp3.plugin.zsh +++ b/zsh/plugins/cakephp3/cakephp3.plugin.zsh @@ -1,10 +1,10 @@ # CakePHP 3 basic command completion _cakephp3_get_command_list () { - bin/cake Completion commands + bin/cake completion commands } _cakephp3_get_sub_command_list () { - bin/cake Completion subcommands ${words[2]} + bin/cake completion subcommands ${words[2]} } _cakephp3_get_3rd_argument () { @@ -34,5 +34,5 @@ compdef _cakephp3 cake #Alias alias c3='bin/cake' -alias c3cache='bin/cake orm_cache clear' +alias c3cache='bin/cake schema_cache clear' alias c3migrate='bin/cake migrations migrate' diff --git a/zsh/plugins/cargo/README.md b/zsh/plugins/cargo/README.md deleted file mode 100644 index 93e69ae..0000000 --- a/zsh/plugins/cargo/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# cargo - -**Deprecated: use the [`rust`](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/rust) plugin instead.** diff --git a/zsh/plugins/cargo/cargo.plugin.zsh b/zsh/plugins/cargo/cargo.plugin.zsh deleted file mode 100644 index 692025e..0000000 --- a/zsh/plugins/cargo/cargo.plugin.zsh +++ /dev/null @@ -1,7 +0,0 @@ -print ${(%):-'%F{yellow}The `cargo` plugin is deprecated and has been moved to the `rust` plugin.'} -print ${(%):-'Please update your .zshrc to use the `%Brust%b` plugin instead.%f'} - -(( ${fpath[(Ie)$ZSH/plugins/rust]} )) || { - fpath=("$ZSH/plugins/rust" $fpath) - source "$ZSH/plugins/rust/rust.plugin.zsh" -} diff --git a/zsh/plugins/catimg/README.md b/zsh/plugins/catimg/README.md index 8f26880..4cfda0e 100644 --- a/zsh/plugins/catimg/README.md +++ b/zsh/plugins/catimg/README.md @@ -1,6 +1,7 @@ # catimg -Plugin for displaying images on the terminal using the the `catimg.sh` script provided by [posva](https://github.com/posva/catimg) +Plugin for displaying images on the terminal using the `catimg.sh` script provided by +[posva](https://github.com/posva/catimg) To use it, add `catimg` to the plugins array in your zshrc file: @@ -10,7 +11,7 @@ plugins=(... catimg) ## Requirements -- `convert` (ImageMagick) +- `magick convert` (ImageMagick) ## Functions diff --git a/zsh/plugins/catimg/catimg.plugin.zsh b/zsh/plugins/catimg/catimg.plugin.zsh index f4ff6f8..ad10d85 100644 --- a/zsh/plugins/catimg/catimg.plugin.zsh +++ b/zsh/plugins/catimg/catimg.plugin.zsh @@ -9,9 +9,11 @@ function catimg() { - if [[ -x `which convert` ]]; then - zsh $ZSH/plugins/catimg/catimg.sh $@ + if (( $+commands[magick] )); then + CONVERT_CMD="magick" zsh $ZSH/plugins/catimg/catimg.sh $@ + elif (( $+commands[convert] )); then + CONVERT_CMD="convert" zsh $ZSH/plugins/catimg/catimg.sh $@ else - echo "catimg need convert (ImageMagick) to work)" + echo "catimg need magick/convert (ImageMagick) to work)" fi } diff --git a/zsh/plugins/catimg/catimg.sh b/zsh/plugins/catimg/catimg.sh index f583924..7946ad1 100644 --- a/zsh/plugins/catimg/catimg.sh +++ b/zsh/plugins/catimg/catimg.sh @@ -7,6 +7,10 @@ # GitHub: https://github.com/posva/catimg # ################################################################################ +# this should come from outside, either `magick` or `convert` +# from imagemagick v7 and ahead `convert` is deprecated +: ${CONVERT_CMD:=convert} + function help() { echo "Usage catimg [-h] [-w width] [-c char] img" echo "By default char is \" \" and w is the terminal width" @@ -43,23 +47,23 @@ if [ ! "$WIDTH" ]; then else COLS=$(expr $WIDTH "/" $(echo -n "$CHAR" | wc -c)) fi -WIDTH=$(convert "$IMG" -print "%w\n" /dev/null) +WIDTH=$($CONVERT_CMD "$IMG" -print "%w\n" /dev/null) if [ "$WIDTH" -gt "$COLS" ]; then WIDTH=$COLS fi REMAP="" -if convert "$IMG" -resize $COLS\> +dither -remap $COLOR_FILE /dev/null ; then +if $CONVERT_CMD "$IMG" -resize $COLS\> +dither -remap $COLOR_FILE /dev/null ; then REMAP="-remap $COLOR_FILE" else echo "The version of convert is too old, don't expect good results :(" >&2 - #convert "$IMG" -colors 256 PNG8:tmp.png - #IMG="tmp.png" + # $CONVERT_CMD "$IMG" -colors 256 PNG8:tmp.png + # IMG="tmp.png" fi # Display the image I=0 -convert "$IMG" -resize $COLS\> +dither `echo $REMAP` txt:- 2>/dev/null | +$CONVERT_CMD "$IMG" -resize $COLS\> +dither `echo $REMAP` txt:- 2>/dev/null | sed -e 's/.*none.*/NO NO NO/g' -e '1d;s/^.*(\(.*\)[,)].*$/\1/g;y/,/ /' | while read R G B f; do if [ ! "$R" = "NO" ]; then diff --git a/zsh/plugins/chezmoi/README.md b/zsh/plugins/chezmoi/README.md new file mode 100644 index 0000000..32aee73 --- /dev/null +++ b/zsh/plugins/chezmoi/README.md @@ -0,0 +1,11 @@ +# chezmoi Plugin + +## Introduction + +This `chezmoi` plugin sets up completion for [chezmoi](https://chezmoi.io). + +To use it, add `chezmoi` to the plugins array of your zshrc file: + +```bash +plugins=(... chezmoi) +``` diff --git a/zsh/plugins/chezmoi/chezmoi.plugin.zsh b/zsh/plugins/chezmoi/chezmoi.plugin.zsh new file mode 100644 index 0000000..80e19fe --- /dev/null +++ b/zsh/plugins/chezmoi/chezmoi.plugin.zsh @@ -0,0 +1,14 @@ +# COMPLETION FUNCTION +if (( ! $+commands[chezmoi] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `chezmoi`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_chezmoi" ]]; then + typeset -g -A _comps + autoload -Uz _chezmoi + _comps[chezmoi]=_chezmoi +fi + +chezmoi completion zsh >| "$ZSH_CACHE_DIR/completions/_chezmoi" &| diff --git a/zsh/plugins/chruby/chruby.plugin.zsh b/zsh/plugins/chruby/chruby.plugin.zsh index d7a28d4..1bcc6c6 100644 --- a/zsh/plugins/chruby/chruby.plugin.zsh +++ b/zsh/plugins/chruby/chruby.plugin.zsh @@ -2,7 +2,7 @@ _source-from-omz-settings() { local _chruby_path _chruby_auto - + zstyle -s :omz:plugins:chruby path _chruby_path || return 1 zstyle -s :omz:plugins:chruby auto _chruby_auto || return 1 @@ -15,6 +15,13 @@ _source-from-omz-settings() { fi } +_source-from-default-location() { + [[ -r /usr/local/share/chruby/chruby.sh ]] || return 1 + + source /usr/local/share/chruby/chruby.sh + source /usr/local/share/chruby/auto.sh +} + _source-from-homebrew() { (( $+commands[brew] )) || return 1 @@ -22,8 +29,10 @@ _source-from-homebrew() { # check default brew prefix if [[ -h /usr/local/opt/chruby ]];then _brew_prefix="/usr/local/opt/chruby" + elif [[ -h /opt/homebrew/opt/chruby ]]; then + _brew_prefix="/opt/homebrew/opt/chruby" else - # ok , it is not default prefix + # ok , it is not default prefix # this call to brew is expensive ( about 400 ms ), so at least let's make it only once _brew_prefix=$(brew --prefix chruby) fi @@ -34,27 +43,14 @@ _source-from-homebrew() { source $_brew_prefix/share/chruby/auto.sh } -_load-chruby-dirs() { - local dir - for dir in "$HOME/.rubies" "$PREFIX/opt/rubies"; do - if [[ -d "$dir" ]]; then - RUBIES+=("$dir") - fi - done -} - # Load chruby -if _source-from-omz-settings; then - _load-chruby-dirs -elif [[ -r "/usr/local/share/chruby/chruby.sh" ]] ; then - source /usr/local/share/chruby/chruby.sh - source /usr/local/share/chruby/auto.sh - _load-chruby-dirs -elif _source-from-homebrew; then - _load-chruby-dirs -fi +_source-from-omz-settings || \ + _source-from-default-location || \ + _source-from-homebrew -unfunction _source-from-homebrew _source-from-omz-settings _load-chruby-dirs +unfunction _source-from-homebrew \ + _source-from-default-location \ + _source-from-omz-settings ## chruby utility functions and aliases diff --git a/zsh/plugins/chucknorris/README.md b/zsh/plugins/chucknorris/README.md index b51875d..655e7cf 100644 --- a/zsh/plugins/chucknorris/README.md +++ b/zsh/plugins/chucknorris/README.md @@ -1,6 +1,6 @@ # chucknorris -Chuck Norris fortunes plugin for Oh My Zsh. Perfectly suitable as MOTD. +Fortunes plugin for Chuck Norris for Oh My Zsh. Perfectly suitable as MOTD. To use it add `chucknorris` to the plugins array in you zshrc file. @@ -36,3 +36,10 @@ Last login: Fri Jan 30 23:12:26 on ttys001 - `cowsay` if using `chuck_cow` Available via homebrew, apt, ... + +> [!NOTE] +> In addition to installing `fortune`, it may be necessary to run: +> +> `strfile $ZSH/plugins/chucknorris/fortunes/chucknorris\n` +> +> (include the "\n" literally) to write the fortune data to the proper directory. diff --git a/zsh/plugins/cloudfoundry/README.md b/zsh/plugins/cloudfoundry/README.md index 89dd9d1..567a905 100644 --- a/zsh/plugins/cloudfoundry/README.md +++ b/zsh/plugins/cloudfoundry/README.md @@ -50,7 +50,7 @@ Alternatively, seek out the [online documentation][3]. And don't forget, there a ## Contributors -Contributed to `oh_my_zsh` by [benwilcock][2]. +Contributed to `oh_my_zsh` by [benwilcock][2]. [1]: https://docs.cloudfoundry.org/cf-cli/install-go-cli.html [2]: https://github.com/benwilcock diff --git a/zsh/plugins/coffee/README.md b/zsh/plugins/coffee/README.md index 2baade8..c2ab192 100644 --- a/zsh/plugins/coffee/README.md +++ b/zsh/plugins/coffee/README.md @@ -24,7 +24,7 @@ Also provides the following aliases: * **cfc:** Copies the compiled JS to your clipboard. Very useful when you want to run the code in a JS console. -* **cfp:** Compiles from your currently copied clipboard. Useful when you want +* **cfp:** Compiles from your currently copied clipboard. Useful when you want to compile large/multi-line snippets * **cfpc:** Paste coffeescript from clipboard, compile to JS, then copy the diff --git a/zsh/plugins/coffee/_coffee b/zsh/plugins/coffee/_coffee index e2814f7..a771f52 100644 --- a/zsh/plugins/coffee/_coffee +++ b/zsh/plugins/coffee/_coffee @@ -1,6 +1,6 @@ #compdef coffee # ------------------------------------------------------------------------------ -# Copyright (c) 2011 Github zsh-users - https://github.com/zsh-users +# Copyright (c) 2011 GitHub zsh-users - https://github.com/zsh-users # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/zsh/plugins/colored-man-pages/colored-man-pages.plugin.zsh b/zsh/plugins/colored-man-pages/colored-man-pages.plugin.zsh index 981992d..26a8b59 100644 --- a/zsh/plugins/colored-man-pages/colored-man-pages.plugin.zsh +++ b/zsh/plugins/colored-man-pages/colored-man-pages.plugin.zsh @@ -36,13 +36,14 @@ function colored() { # Prefer `less` whenever available, since we specifically configured # environment for it. environment+=( PAGER="${commands[less]:-$PAGER}" ) + environment+=( GROFF_NO_SGR=1 ) # See ./nroff script. if [[ "$OSTYPE" = solaris* ]]; then environment+=( PATH="${__colored_man_pages_dir}:$PATH" ) fi - command env $environment "$@" + command env "${environment[@]}" "$@" } # Colorize man and dman/debman (from debian-goodies) diff --git a/zsh/plugins/colorize/colorize.plugin.zsh b/zsh/plugins/colorize/colorize.plugin.zsh index a9da6cf..c49acd8 100644 --- a/zsh/plugins/colorize/colorize.plugin.zsh +++ b/zsh/plugins/colorize/colorize.plugin.zsh @@ -23,7 +23,7 @@ colorize_check_requirements() { if [[ ${available_tools[(Ie)$ZSH_COLORIZE_TOOL]} -eq 0 ]]; then echo "ZSH_COLORIZE_TOOL '$ZSH_COLORIZE_TOOL' not recognized. Available options are 'pygmentize' and 'chroma'." >&2 return 1 - elif (( $+commands["$ZSH_COLORIZE_TOOL"] )); then + elif ! (( $+commands[$ZSH_COLORIZE_TOOL] )); then echo "Package '$ZSH_COLORIZE_TOOL' is not installed!" >&2 return 1 fi @@ -42,12 +42,12 @@ colorize_cat() { ZSH_COLORIZE_STYLE="emacs" fi - # Use stdin if no arguments have been passed. - if [ $# -eq 0 ]; then + # Use stdin if stdin is not attached to a terminal. + if [ ! -t 0 ]; then if [[ "$ZSH_COLORIZE_TOOL" == "pygmentize" ]]; then pygmentize -O style="$ZSH_COLORIZE_STYLE" -g else - chroma --style="$ZSH_COLORIZE_STYLE" --formatter="${ZSH_COLORIZE_CHROMA_FORMATTER:-terminal}" + chroma --style="$ZSH_COLORIZE_STYLE" --formatter="${ZSH_COLORIZE_CHROMA_FORMATTER:-terminal}" "$@" fi return $? fi diff --git a/zsh/plugins/command-not-found/README.md b/zsh/plugins/command-not-found/README.md index 5a373c5..5079b1f 100644 --- a/zsh/plugins/command-not-found/README.md +++ b/zsh/plugins/command-not-found/README.md @@ -22,13 +22,15 @@ Try: sudo apt install It works out of the box with the command-not-found packages for: -- [Ubuntu](https://www.porcheron.info/command-not-found-for-zsh/) +- [Ubuntu](https://launchpad.net/ubuntu/+source/command-not-found) - [Debian](https://packages.debian.org/search?keywords=command-not-found) -- [Arch Linux](https://wiki.archlinux.org/index.php/Pkgfile#Command_not_found) -- [macOS (Homebrew)](https://github.com/Homebrew/homebrew-command-not-found) +- [Arch Linux](https://wiki.archlinux.org/title/Zsh#pkgfile_"command_not_found"_handler) +- [macOS (Homebrew)](https://github.com/Homebrew/brew/blob/main/docs/Command-Not-Found.md) - [Fedora](https://fedoraproject.org/wiki/Features/PackageKitCommandNotFound) - [NixOS](https://github.com/NixOS/nixpkgs/tree/master/nixos/modules/programs/command-not-found) - [Termux](https://github.com/termux/command-not-found) - [SUSE](https://www.unix.com/man-page/suse/1/command-not-found/) +- [Gentoo](https://github.com/AndrewAmmerlaan/command-not-found-gentoo/tree/main) +- [Void Linux](https://codeberg.org/classabbyamp/xbps-command-not-found) You can add support for other platforms by submitting a Pull Request. diff --git a/zsh/plugins/command-not-found/command-not-found.plugin.zsh b/zsh/plugins/command-not-found/command-not-found.plugin.zsh index cb8a898..a85dbfd 100644 --- a/zsh/plugins/command-not-found/command-not-found.plugin.zsh +++ b/zsh/plugins/command-not-found/command-not-found.plugin.zsh @@ -1,11 +1,18 @@ ## Platforms with a built-in command-not-found handler init file for file ( - # Arch Linux. Must have pkgfile installed: https://wiki.archlinux.org/index.php/Pkgfile#Command_not_found + # Arch Linux. Must have pkgfile installed: https://wiki.archlinux.org/title/Zsh#pkgfile_"command_not_found"_handler /usr/share/doc/pkgfile/command-not-found.zsh - # macOS (M1 and classic Homebrew): https://github.com/Homebrew/homebrew-command-not-found + # Void Linux: https://codeberg.org/classabbyamp/xbps-command-not-found + /usr/share/zsh/plugins/xbps-command-not-found/xbps-command-not-found.zsh + # Homebrew: https://github.com/Homebrew/brew/blob/main/docs/Command-Not-Found.md + /opt/homebrew/Library/Homebrew/command-not-found/handler.sh + /usr/local/Homebrew/Library/Homebrew/command-not-found/handler.sh + /home/linuxbrew/.linuxbrew/Homebrew/Library/Homebrew/command-not-found/handler.sh + # Old homebrew implementation /opt/homebrew/Library/Taps/homebrew/homebrew-command-not-found/handler.sh /usr/local/Homebrew/Library/Taps/homebrew/homebrew-command-not-found/handler.sh + /home/linuxbrew/.linuxbrew/Homebrew/Library/Taps/homebrew/homebrew-command-not-found/handler.sh ); do if [[ -r "$file" ]]; then source "$file" diff --git a/zsh/plugins/common-aliases/README.md b/zsh/plugins/common-aliases/README.md index 1417c30..79e3d0d 100644 --- a/zsh/plugins/common-aliases/README.md +++ b/zsh/plugins/common-aliases/README.md @@ -114,13 +114,13 @@ that file will be open with `acroread`. ### Listing files inside a packed file -| Alias | Command | Description | -| ------ | ---------- | --------------------------------- | -| zip | `unzip -l` | Lists files inside a .zip file | -| rar | `unrar l` | Lists files inside a .rar file | -| tar | `tar tf` | Lists files inside a .tar file | -| tar.gz | `echo` | Lists files inside a .tar.gz file | -| ace | `unace l` | Lists files inside a .ace file | +| Alias | Command | Description | +| ------ | ------------ | --------------------------------- | +| zip | `unzip -l` | Lists files inside a .zip file | +| rar | `unrar l` | Lists files inside a .rar file | +| tar | `tar tf` | Lists files inside a .tar file | +| tar.gz | `tar -ztf` | Lists files inside a .tar.gz file | +| ace | `unace l` | Lists files inside a .ace file | ### Some other features diff --git a/zsh/plugins/compleat/compleat.plugin.zsh b/zsh/plugins/compleat/compleat.plugin.zsh index 38f1b39..7fbd2b9 100644 --- a/zsh/plugins/compleat/compleat.plugin.zsh +++ b/zsh/plugins/compleat/compleat.plugin.zsh @@ -7,7 +7,7 @@ if (( ${+commands[compleat]} )); then local prefix="${commands[compleat]:h:h}" - local setup="${prefix}/share/compleat-1.0/compleat_setup" + local setup="${prefix}/share/compleat-1.0/compleat_setup" if [[ -f "$setup" ]]; then if ! bashcompinit >/dev/null 2>&1; then @@ -15,6 +15,6 @@ if (( ${+commands[compleat]} )); then bashcompinit -i fi - source "$setup" + source "$setup" fi fi diff --git a/zsh/plugins/conda-env/README.md b/zsh/plugins/conda-env/README.md new file mode 100644 index 0000000..ccf48a3 --- /dev/null +++ b/zsh/plugins/conda-env/README.md @@ -0,0 +1,44 @@ +# conda-env + +The plugin displays information of the created virtual container of conda and allows background theming. + +To use it, add `conda-env` to the plugins array of your zshrc file: +``` +plugins=(... conda-env) +``` + +The plugin creates a `conda_prompt_info` function that you can use in your theme, which displays the +basename of the current `$CONDA_DEFAULT_ENV`. + +You can use this prompt function in your themes, by adding it to the `PROMPT` or `RPROMPT` variables. See [Example](#example) for more information. + +## Settings + +It uses two variables to control how the information is shown: + +- `ZSH_THEME_CONDA_PREFIX`: sets the prefix of the CONDA_DEFAULT_ENV. +Defaults to `[`. + +- `ZSH_THEME_CONDA_SUFFIX`: sets the suffix of the CONDA_DEFAULT_ENV. +Defaults to `]`. + +## Example + +```sh +ZSH_THEME_CONDA_PREFIX='conda:%F{green}' +ZSH_THEME_CONDA_SUFFIX='%f' +RPROMPT='$(conda_prompt_info)' +``` + +## `CONDA_CHANGEPS1` + +This plugin also automatically sets the `CONDA_CHANGEPS1` variable to `false` to avoid conda changing the prompt +automatically. This has the same effect as running `conda config --set changeps1 false`. + +You can override this behavior by adding `unset CONDA_CHANGEPS1` in your `.zshrc` file, after Oh My Zsh has been +sourced. + +References: + +- https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#determining-your-current-environment +- https://conda.io/projects/conda/en/latest/user-guide/configuration/use-condarc.html#precedence diff --git a/zsh/plugins/conda-env/conda-env.plugin.zsh b/zsh/plugins/conda-env/conda-env.plugin.zsh new file mode 100644 index 0000000..c710c95 --- /dev/null +++ b/zsh/plugins/conda-env/conda-env.plugin.zsh @@ -0,0 +1,9 @@ +function conda_prompt_info(){ + [[ -n ${CONDA_DEFAULT_ENV} ]] || return + echo "${ZSH_THEME_CONDA_PREFIX=[}${CONDA_DEFAULT_ENV:t:gs/%/%%}${ZSH_THEME_CONDA_SUFFIX=]}" +} + +# Has the same effect as `conda config --set changeps1 false` +# - https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#determining-your-current-environment +# - https://conda.io/projects/conda/en/latest/user-guide/configuration/use-condarc.html#precedence +export CONDA_CHANGEPS1=false diff --git a/zsh/plugins/conda/README.md b/zsh/plugins/conda/README.md new file mode 100644 index 0000000..70530d0 --- /dev/null +++ b/zsh/plugins/conda/README.md @@ -0,0 +1,37 @@ +# conda plugin + +The conda plugin provides [aliases](#aliases) for `conda`, usually installed via [anaconda](https://www.anaconda.com/) or [miniconda](https://docs.conda.io/en/latest/miniconda.html). + +To use it, add `conda` to the plugins array in your zshrc file: + +```zsh +plugins=(... conda) +``` + +## Aliases + +| Alias | Command | Description | +| :------- | :-------------------------------------- | :------------------------------------------------------------------------------ | +| `cna` | `conda activate` | Activate the specified conda environment | +| `cnab` | `conda activate base` | Activate the base conda environment | +| `cncf` | `conda env create -f` | Create a new conda environment from a YAML file | +| `cncn` | `conda create -y -n` | Create a new conda environment with the given name | +| `cnconf` | `conda config` | View or modify conda configuration | +| `cncp` | `conda create -y -p` | Create a new conda environment with the given prefix | +| `cncr` | `conda create -n` | Create new virtual environment with given name | +| `cncss` | `conda config --show-source` | Show the locations of conda configuration sources | +| `cnde` | `conda deactivate` | Deactivate the current conda environment | +| `cnel` | `conda env list` | List all available conda environments | +| `cni` | `conda install` | Install given package | +| `cniy` | `conda install -y` | Install given package without confirmation | +| `cnl` | `conda list` | List installed packages in the current environment | +| `cnle` | `conda list --export` | Export the list of installed packages in the current environment | +| `cnles` | `conda list --explicit > spec-file.txt` | Export the list of installed packages in the current environment to a spec file | +| `cnr` | `conda remove` | Remove given package | +| `cnrn` | `conda remove -y -all -n` | Remove all packages in the specified environment | +| `cnrp` | `conda remove -y -all -p` | Remove all packages in the specified prefix | +| `cnry` | `conda remove -y` | Remove given package without confirmation | +| `cnsr` | `conda search` | Search conda repositories for package | +| `cnu` | `conda update` | Update conda package manager | +| `cnua` | `conda update --all` | Update all installed packages | +| `cnuc` | `conda update conda` | Update conda package manager | diff --git a/zsh/plugins/conda/conda.plugin.zsh b/zsh/plugins/conda/conda.plugin.zsh new file mode 100644 index 0000000..7a130ba --- /dev/null +++ b/zsh/plugins/conda/conda.plugin.zsh @@ -0,0 +1,23 @@ +alias cna='conda activate' +alias cnab='conda activate base' +alias cncf='conda env create -f' +alias cncn='conda create -y -n' +alias cnconf='conda config' +alias cncp='conda create -y -p' +alias cncr='conda create -n' +alias cncss='conda config --show-source' +alias cnde='conda deactivate' +alias cnel='conda env list' +alias cni='conda install' +alias cniy='conda install -y' +alias cnl='conda list' +alias cnle='conda list --export' +alias cnles='conda list --explicit > spec-file.txt' +alias cnr='conda remove' +alias cnrn='conda remove -y --all -n' +alias cnrp='conda remove -y --all -p' +alias cnry='conda remove -y' +alias cnsr='conda search' +alias cnu='conda update' +alias cnua='conda update --all' +alias cnuc='conda update conda' diff --git a/zsh/plugins/copybuffer/copybuffer.plugin.zsh b/zsh/plugins/copybuffer/copybuffer.plugin.zsh index e67f920..e636d97 100644 --- a/zsh/plugins/copybuffer/copybuffer.plugin.zsh +++ b/zsh/plugins/copybuffer/copybuffer.plugin.zsh @@ -1,8 +1,8 @@ -# copy the active line from the command line buffer +# copy the active line from the command line buffer # onto the system clipboard copybuffer () { - if which clipcopy &>/dev/null; then + if builtin which clipcopy &>/dev/null; then printf "%s" "$BUFFER" | clipcopy else zle -M "clipcopy not found. Please make sure you have Oh My Zsh installed correctly." diff --git a/zsh/plugins/copydir/README.md b/zsh/plugins/copydir/README.md deleted file mode 100644 index cf24b78..0000000 --- a/zsh/plugins/copydir/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# copydir plugin - -This plugin is deprecated. Use the [`copypath` plugin](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/copypath) instead. diff --git a/zsh/plugins/copydir/copydir.plugin.zsh b/zsh/plugins/copydir/copydir.plugin.zsh deleted file mode 100644 index a2b489e..0000000 --- a/zsh/plugins/copydir/copydir.plugin.zsh +++ /dev/null @@ -1,7 +0,0 @@ -echo ${(%):-'%F{yellow}The `%Bcopydir%b` plugin is deprecated. Use the `%Bcopypath%b` plugin instead.%f'} -source "$ZSH/plugins/copypath/copypath.plugin.zsh" - -# TODO: 2022-02-22: Remove deprecated copydir function. -function copydir { - copypath -} diff --git a/zsh/plugins/copyfile/copyfile.plugin.zsh b/zsh/plugins/copyfile/copyfile.plugin.zsh index f4eca5a..3281410 100644 --- a/zsh/plugins/copyfile/copyfile.plugin.zsh +++ b/zsh/plugins/copyfile/copyfile.plugin.zsh @@ -1,7 +1,19 @@ # Copies the contents of a given file to the system or X Windows clipboard # -# copyfile +# Usage: copyfile function copyfile { emulate -L zsh + + if [[ -z "$1" ]]; then + echo "Usage: copyfile " + return 1 + fi + + if [[ ! -f "$1" ]]; then + echo "Error: '$1' is not a valid file." + return 1 + fi + clipcopy $1 + echo ${(%):-"%B$1%b copied to clipboard."} } diff --git a/zsh/plugins/dash/README.md b/zsh/plugins/dash/README.md index 0ca3e4e..970c654 100644 --- a/zsh/plugins/dash/README.md +++ b/zsh/plugins/dash/README.md @@ -19,7 +19,7 @@ dash - Query for something in dash app: `dash query` ``` -dash golang +dash golang ``` - You can optionally provide a keyword: `dash [keyword:]query` diff --git a/zsh/plugins/dash/dash.plugin.zsh b/zsh/plugins/dash/dash.plugin.zsh index f6801a8..9abd691 100644 --- a/zsh/plugins/dash/dash.plugin.zsh +++ b/zsh/plugins/dash/dash.plugin.zsh @@ -1,5 +1,5 @@ # Usage: dash [keyword:]query -dash() { open -a Dash.app dash://"$*" } +dash() { open -a Dash.app "dash://$(omz_urlencode -r $*)" } compdef _dash dash _dash() { diff --git a/zsh/plugins/dbt/README.md b/zsh/plugins/dbt/README.md new file mode 100644 index 0000000..74ae631 --- /dev/null +++ b/zsh/plugins/dbt/README.md @@ -0,0 +1,27 @@ +# dbt plugin + +The `dbt plugin` adds several aliases for useful [dbt](https://docs.getdbt.com/) commands and +[aliases](#aliases). + +To use it, add `dbt` to the plugins array of your zshrc file: + +```zsh +plugins=(... dbt) +``` + +## Aliases + +| Alias | Command | Description | +| ------ | ------------------------------------------------ | ---------------------------------------------------- | +| dbtlm | `dbt ls -s state:modified` | List modified models only | +| dbtrm | `dbt run -s state:modified` | Run modified models only | +| dbttm | `dbt test -m state:modified` | Test modified models only | +| dbtrtm | `dbtrm && dbttm` | Run and test modified models only | +| dbtrs | `dbt clean; dbt deps; dbt seed` | Re-seed data | +| dbtfrt | `dbtrs; dbt run --full-refresh; dbt test` | Perform a full fresh run with tests | +| dbtcds | `dbt docs generate; dbt docs serve` | Generate docs without compiling | +| dbtds | `dbt docs generate --no-compile; dbt docs serve` | Generate and serve docs skipping doc. re-compilation | + +## Maintainer + +- [msempere](https://github.com/msempere) diff --git a/zsh/plugins/dbt/dbt.plugin.zsh b/zsh/plugins/dbt/dbt.plugin.zsh new file mode 100644 index 0000000..6fcc2ee --- /dev/null +++ b/zsh/plugins/dbt/dbt.plugin.zsh @@ -0,0 +1,23 @@ +# list modified models only +alias dbtlm="dbt ls -s state:modified" + +# run modified models only +alias dbtrm="dbt run -s state:modified" + +# test modified models only +alias dbttm="dbt test -m state:modified" + +# run and test modified models only +alias dbtrtm="dbtrm && dbttm" + +# re-seed data +alias dbtrs="dbt clean; dbt deps; dbt seed" + +# perform a full fresh run with tests +alias dbtfrt="dbtrs; dbt run --full-refresh; dbt test" + +# generate and serve docs +alias dbtcds="dbt docs generate; dbt docs serve" + +# generate and serve docs skipping doc. re-compilation +alias dbtds="dbt docs generate --no-compile; dbt docs serve" diff --git a/zsh/plugins/debian/README.md b/zsh/plugins/debian/README.md index 1db534f..6835ad6 100644 --- a/zsh/plugins/debian/README.md +++ b/zsh/plugins/debian/README.md @@ -13,7 +13,12 @@ plugins=(... debian) - `$apt_pref`: use aptitude or apt if installed, fallback is apt-get. - `$apt_upgr`: use upgrade or safe-upgrade (for aptitude). -Set `$apt_pref` and `$apt_upgr` to whatever command you want (before sourcing Oh My Zsh) to override this behavior. +Set **both** `$apt_pref` and `$apt_upgr` to whatever command you want (before sourcing Oh My Zsh) to override this behavior, e.g.: + +```sh +apt_pref='apt' +apt_upgr='full-upgrade' +``` ## Common Aliases diff --git a/zsh/plugins/debian/debian.plugin.zsh b/zsh/plugins/debian/debian.plugin.zsh index 2d8c466..980440c 100644 --- a/zsh/plugins/debian/debian.plugin.zsh +++ b/zsh/plugins/debian/debian.plugin.zsh @@ -51,7 +51,7 @@ if [[ $use_sudo -eq 1 ]]; then alias au="sudo $apt_pref $apt_upgr" alias ai="sudo $apt_pref install" # Install all packages given on the command line while using only the first word of each line: - # acs ... | ail + # acse ... | ail alias ail="sed -e 's/ */ /g' -e 's/ *//' | cut -s -d ' ' -f 1 | xargs sudo $apt_pref install" alias ap="sudo $apt_pref purge" @@ -83,9 +83,9 @@ else } alias ac="su -ls '$apt_pref clean' root" alias ad="su -lc '$apt_pref update' root" - alias adg="su -lc '$apt_pref update && aptitude $apt_upgr' root" - alias adu="su -lc '$apt_pref update && aptitude dist-upgrade' root" - alias afu="su -lc '$apt-file update'" + alias adg="su -lc '$apt_pref update && $apt_pref $apt_upgr' root" + alias adu="su -lc '$apt_pref update && $apt_pref dist-upgrade' root" + alias afu="su -lc 'apt-file update'" alias au="su -lc '$apt_pref $apt_upgr' root" function ai() { cmd="su -lc '$apt_pref install $@' root" diff --git a/zsh/plugins/deno/README.md b/zsh/plugins/deno/README.md index 6913183..38f9f20 100644 --- a/zsh/plugins/deno/README.md +++ b/zsh/plugins/deno/README.md @@ -4,16 +4,17 @@ This plugin sets up completion and aliases for [Deno](https://deno.land). ## Aliases -| Alias | Full command | -| ----- | ---------------- | -| db | deno bundle | -| dc | deno compile | -| dca | deno cache | -| dfmt | deno fmt | -| dh | deno help | -| dli | deno lint | -| drn | deno run | -| drA | deno run -A | -| drw | deno run --watch | -| dts | deno test | -| dup | deno upgrade | +| Alias | Full command | +| ----- | ------------------- | +| db | deno bundle | +| dc | deno compile | +| dca | deno cache | +| dfmt | deno fmt | +| dh | deno help | +| dli | deno lint | +| drn | deno run | +| drA | deno run -A | +| drw | deno run --watch | +| dru | deno run --unstable | +| dts | deno test | +| dup | deno upgrade | diff --git a/zsh/plugins/deno/deno.plugin.zsh b/zsh/plugins/deno/deno.plugin.zsh index 7708f84..bf97d6f 100644 --- a/zsh/plugins/deno/deno.plugin.zsh +++ b/zsh/plugins/deno/deno.plugin.zsh @@ -8,6 +8,7 @@ alias dli='deno lint' alias drn='deno run' alias drA='deno run -A' alias drw='deno run --watch' +alias dru='deno run --unstable' alias dts='deno test' alias dup='deno upgrade' diff --git a/zsh/plugins/dircycle/README.md b/zsh/plugins/dircycle/README.md index 3c9b3a9..c410555 100644 --- a/zsh/plugins/dircycle/README.md +++ b/zsh/plugins/dircycle/README.md @@ -37,13 +37,13 @@ Say you opened these directories on the terminal: 3 ~ ``` -By pressing Ctrl + Shift + Left, the current working directory or `$CWD` will be from `oh-my-zsh` to `Hacktoberfest`. Press it again and it will be at `Projects`. +By pressing Ctrl + Shift + Left, the current working directory or `$PWD` will be from `oh-my-zsh` to `Hacktoberfest`. Press it again and it will be at `Projects`. -And by pressing Ctrl + Shift + Right, the `$CWD` will be from `Projects` to `Hacktoberfest`. Press it again and it will be at `oh-my-zsh`. +And by pressing Ctrl + Shift + Right, the `$PWD` will be from `Projects` to `Hacktoberfest`. Press it again and it will be at `oh-my-zsh`. Here's a example history table with the same accessed directories like above: -| Current `$CWD` | Key press | New `$CWD` | +| Current `$PWD` | Key press | New `$PWD` | | --------------- | ----------------------------------------------------- | --------------- | | `oh-my-zsh` | Ctrl + Shift + Left | `Hacktoberfest` | | `Hacktoberfest` | Ctrl + Shift + Left | `Projects` | @@ -53,7 +53,7 @@ Here's a example history table with the same accessed directories like above: | `Hacktoberfest` | Ctrl + Shift + Right | `oh-my-zsh` | | `oh-my-zsh` | Ctrl + Shift + Right | `~` | -Note the last traversal, when pressing Ctrl + Shift + Right on a last known `$CWD`, it will change back to the first known `$CWD`, which in the example is `~`. +Note the last traversal, when pressing Ctrl + Shift + Right on a last known `$PWD`, it will change back to the first known `$PWD`, which in the example is `~`. Here's an asciinema cast demonstrating the example above: @@ -61,18 +61,22 @@ Here's an asciinema cast demonstrating the example above: ## Functions -| Function | Description | -| -------------------- | --------------------------------------------------------------------------------------------------------- | -| `insert-cycledleft` | Change `$CWD` to the previous known stack, binded on Ctrl + Shift + Left | -| `insert-cycledright` | Change `$CWD` to the next known stack, binded on Ctrl + Shift + Right | +| Function | Description | +| -------------------- | ------------------------------------------------------------------------------------------------------------------- | +| `insert-cycledleft` | Change `$PWD` to the previous known stack, bound to Ctrl + Shift + Left | +| `insert-cycledright` | Change `$PWD` to the next known stack, bound to Ctrl + Shift + Right | +| `insert-cycledup` | Change `$PWD` to the parent folder, bound to Ctrl + Shift + Up | +| `insert-cycleddown` | Change `$PWD` to the first alphabetical child folder, bound to Ctrl + Shift + Down | ## Rebinding keys -You can bind these functions to other key sequences, as long as you know the bindkey sequence. For example, these commands bind to Alt + Shift + Left / Right in `xterm-256color`: +You can bind these functions to other key sequences, as long as you know the bindkey sequence. For example, these commands bind to Alt + Shift + key in `xterm-256color`: ```zsh bindkey '^[[1;4D' insert-cycledleft bindkey '^[[1;4C' insert-cycledright +bindkey "\e[1;4A" insert-cycledup +bindkey "\e[1;4B" insert-cycleddown ``` You can get the bindkey sequence by pressing Ctrl + V, then pressing the keyboard shortcut you want to use. diff --git a/zsh/plugins/dircycle/dircycle.plugin.zsh b/zsh/plugins/dircycle/dircycle.plugin.zsh index bb69f6b..8c03594 100644 --- a/zsh/plugins/dircycle/dircycle.plugin.zsh +++ b/zsh/plugins/dircycle/dircycle.plugin.zsh @@ -8,7 +8,16 @@ # pushd +N: start counting from left of `dirs' output # pushd -N: start counting from right of `dirs' output +# Either switch to a directory from dirstack, using +N or -N syntax +# or switch to a directory by path, using `switch-to-dir -- ` switch-to-dir () { + # If $1 is --, then treat $2 as a directory path + if [[ $1 == -- ]]; then + # We use `-q` because we don't want chpwd to run, we'll do it manually + [[ -d "$2" ]] && builtin pushd -q "$2" &>/dev/null + return $? + fi + setopt localoptions nopushdminus [[ ${#dirstack} -eq 0 ]] && return 1 @@ -22,10 +31,10 @@ switch-to-dir () { } insert-cycledleft () { - switch-to-dir +1 || return + switch-to-dir +1 || return $? local fn - for fn (chpwd $chpwd_functions precmd $precmd_functions); do + for fn in chpwd $chpwd_functions precmd $precmd_functions; do (( $+functions[$fn] )) && $fn done zle reset-prompt @@ -33,22 +42,46 @@ insert-cycledleft () { zle -N insert-cycledleft insert-cycledright () { - switch-to-dir -0 || return + switch-to-dir -0 || return $? local fn - for fn (chpwd $chpwd_functions precmd $precmd_functions); do + for fn in chpwd $chpwd_functions precmd $precmd_functions; do (( $+functions[$fn] )) && $fn done zle reset-prompt } zle -N insert-cycledright +insert-cycledup () { + switch-to-dir -- .. || return $? + + local fn + for fn in chpwd $chpwd_functions precmd $precmd_functions; do + (( $+functions[$fn] )) && $fn + done + zle reset-prompt +} +zle -N insert-cycledup + +insert-cycleddown () { + switch-to-dir -- "$(find . -mindepth 1 -maxdepth 1 -type d | sort -n | head -n 1)" || return $? + + local fn + for fn in chpwd $chpwd_functions precmd $precmd_functions; do + (( $+functions[$fn] )) && $fn + done + zle reset-prompt +} +zle -N insert-cycleddown # These sequences work for xterm, Apple Terminal.app, and probably others. # Not for rxvt-unicode, but it doesn't seem differentiate Ctrl-Shift-Arrow # from plain Shift-Arrow, at least by default. +# # iTerm2 does not have these key combinations defined by default; you will need # to add them under "Keys" in your profile if you want to use this. You can do # this conveniently by loading the "xterm with Numeric Keypad" preset. -bindkey "\e[1;6D" insert-cycledleft -bindkey "\e[1;6C" insert-cycledright +bindkey "\e[1;6D" insert-cycledleft # Ctrl+Shift+Left +bindkey "\e[1;6C" insert-cycledright # Ctrl+Shift+Right +bindkey "\e[1;6A" insert-cycledup # Ctrl+Shift+Up +bindkey "\e[1;6B" insert-cycleddown # Ctrl+Shift+Down diff --git a/zsh/plugins/direnv/direnv.plugin.zsh b/zsh/plugins/direnv/direnv.plugin.zsh index 5e32c4c..c026dbe 100644 --- a/zsh/plugins/direnv/direnv.plugin.zsh +++ b/zsh/plugins/direnv/direnv.plugin.zsh @@ -1,5 +1,8 @@ -# Don't continue if direnv is not found -command -v direnv &>/dev/null || return +# If direnv is not found, don't continue and print a warning +if (( ! $+commands[direnv] )); then + echo "Warning: direnv not found. Please install direnv and ensure it's in your PATH before using this plugin." + return +fi _direnv_hook() { trap -- '' SIGINT; @@ -7,10 +10,10 @@ _direnv_hook() { trap - SIGINT; } typeset -ag precmd_functions; -if [[ -z ${precmd_functions[(r)_direnv_hook]} ]]; then +if [[ -z "${precmd_functions[(r)_direnv_hook]+1}" ]]; then precmd_functions=( _direnv_hook ${precmd_functions[@]} ) fi typeset -ag chpwd_functions; -if [[ -z ${chpwd_functions[(r)_direnv_hook]} ]]; then +if [[ -z "${chpwd_functions[(r)_direnv_hook]+1}" ]]; then chpwd_functions=( _direnv_hook ${chpwd_functions[@]} ) fi diff --git a/zsh/plugins/dirhistory/README.md b/zsh/plugins/dirhistory/README.md index ede9b54..66e3e04 100644 --- a/zsh/plugins/dirhistory/README.md +++ b/zsh/plugins/dirhistory/README.md @@ -60,3 +60,46 @@ to `/usr` again. After that, Alt + Down will probably go to `/usr/bin` if `bin` is the first directory in alphabetical order (depends on your `/usr` folder structure). Alt + Up will return to `/usr`, and once more will get you to the root folder (`/`). + +### cde + +This plugin also provides a `cde` alias that allows you to change to a directory without clearing the next directory stack. +This changes the default behavior of `dirhistory`, which is to clear the next directory stack when changing directories. + +For example, if the shell was started, and the following commands were entered: + +```shell +cd ~ +cd /usr +cd share +cd doc + +# +# +``` + +The directory stack would look like this: + +```sh +➜ /usr typeset -pm dirhistory_\* +typeset -ax dirhistory_past=( /home/user /usr ) +typeset -ax dirhistory_future=( /usr/share/doc /usr/share ) +``` + +This means that pressing Alt + Right, you'd go to `/usr/share` and `/usr/share/doc` (the "future" directories). + +If you run `cd /usr/bin`, the "future" directories will be removed, and you won't be able to access them with Alt + Right: + +```sh +➜ /u/bin typeset -pm dirhistory_\* +typeset -ax dirhistory_past=( /home/user /usr ) +typeset -ax dirhistory_future=( /usr/bin ) +``` + +If you instead run `cde /usr/bin`, the "future" directories will be preserved: + +```sh +➜ /u/bin typeset -pm dirhistory_\* +typeset -ax dirhistory_past=( /home/user /usr /usr/bin ) +typeset -ax dirhistory_future=( /usr/share/doc /usr/share ) +``` diff --git a/zsh/plugins/dirhistory/dirhistory.plugin.zsh b/zsh/plugins/dirhistory/dirhistory.plugin.zsh index 7021fc0..706bb6f 100644 --- a/zsh/plugins/dirhistory/dirhistory.plugin.zsh +++ b/zsh/plugins/dirhistory/dirhistory.plugin.zsh @@ -11,23 +11,26 @@ dirhistory_past=($PWD) dirhistory_future=() export dirhistory_past export dirhistory_future - export DIRHISTORY_SIZE=30 +alias cde='dirhistory_cd' + # Pop the last element of dirhistory_past. # Pass the name of the variable to return the result in. # Returns the element if the array was not empty, # otherwise returns empty string. function pop_past() { - typeset -g $1="${dirhistory_past[$#dirhistory_past]}" + setopt localoptions no_ksh_arrays if [[ $#dirhistory_past -gt 0 ]]; then + typeset -g $1="${dirhistory_past[$#dirhistory_past]}" dirhistory_past[$#dirhistory_past]=() fi } function pop_future() { - typeset -g $1="${dirhistory_future[$#dirhistory_future]}" + setopt localoptions no_ksh_arrays if [[ $#dirhistory_future -gt 0 ]]; then + typeset -g $1="${dirhistory_future[$#dirhistory_future]}" dirhistory_future[$#dirhistory_future]=() fi } @@ -35,6 +38,7 @@ function pop_future() { # Push a new element onto the end of dirhistory_past. If the size of the array # is >= DIRHISTORY_SIZE, the array is shifted function push_past() { + setopt localoptions no_ksh_arrays if [[ $#dirhistory_past -ge $DIRHISTORY_SIZE ]]; then shift dirhistory_past fi @@ -44,6 +48,7 @@ function push_past() { } function push_future() { + setopt localoptions no_ksh_arrays if [[ $#dirhistory_future -ge $DIRHISTORY_SIZE ]]; then shift dirhistory_future fi @@ -132,7 +137,11 @@ for keymap in emacs vicmd viins; do case "$TERM_PROGRAM" in Apple_Terminal) bindkey -M $keymap "^[b" dirhistory_zle_dirhistory_back ;; # Terminal.app - iTerm.app) bindkey -M $keymap "^[^[[D" dirhistory_zle_dirhistory_back ;; # iTerm2 + ghostty) bindkey -M $keymap "^[b" dirhistory_zle_dirhistory_back ;; # ghostty + iTerm.app) + bindkey -M $keymap "^[^[[D" dirhistory_zle_dirhistory_back + bindkey -M $keymap "^[b" dirhistory_zle_dirhistory_back + ;; esac if (( ${+terminfo[kcub1]} )); then @@ -147,7 +156,11 @@ for keymap in emacs vicmd viins; do case "$TERM_PROGRAM" in Apple_Terminal) bindkey -M $keymap "^[f" dirhistory_zle_dirhistory_future ;; # Terminal.app - iTerm.app) bindkey -M $keymap "^[^[[C" dirhistory_zle_dirhistory_future ;; # iTerm2 + ghostty) bindkey -M $keymap "^[f" dirhistory_zle_dirhistory_future ;; # ghostty + iTerm.app) + bindkey -M $keymap "^[^[[C" dirhistory_zle_dirhistory_future + bindkey -M $keymap "^[f" dirhistory_zle_dirhistory_future + ;; esac if (( ${+terminfo[kcuf1]} )); then @@ -196,6 +209,7 @@ for keymap in emacs vicmd viins; do case "$TERM_PROGRAM" in Apple_Terminal) bindkey -M $keymap "^[[A" dirhistory_zle_dirhistory_up ;; # Terminal.app iTerm.app) bindkey -M $keymap "^[^[[A" dirhistory_zle_dirhistory_up ;; # iTerm2 + ghostty) bindkey -M $keymap "^[[1;3A" dirhistory_zle_dirhistory_up ;; # ghostty esac if (( ${+terminfo[kcuu1]} )); then @@ -211,6 +225,7 @@ for keymap in emacs vicmd viins; do case "$TERM_PROGRAM" in Apple_Terminal) bindkey -M $keymap "^[[B" dirhistory_zle_dirhistory_down ;; # Terminal.app iTerm.app) bindkey -M $keymap "^[^[[B" dirhistory_zle_dirhistory_down ;; # iTerm2 + ghostty) bindkey -M $keymap "^[[1;3B" dirhistory_zle_dirhistory_down ;; # ghostty esac if (( ${+terminfo[kcud1]} )); then diff --git a/zsh/plugins/dnf/README.md b/zsh/plugins/dnf/README.md index dc0d1e0..f45c877 100644 --- a/zsh/plugins/dnf/README.md +++ b/zsh/plugins/dnf/README.md @@ -10,6 +10,9 @@ To use it, add `dnf` to the plugins array in your zshrc file: plugins=(... dnf) ``` +Classic `dnf` is getting superseded by `dnf5`; this plugin detects the presence +of `dnf5` and uses it as drop-in alternative to the slower `dnf`. + ## Aliases | Alias | Command | Description | diff --git a/zsh/plugins/dnf/_dnf5 b/zsh/plugins/dnf/_dnf5 new file mode 100644 index 0000000..3422fae --- /dev/null +++ b/zsh/plugins/dnf/_dnf5 @@ -0,0 +1,570 @@ +#compdef dnf5 +# based on dnf-5.2.6.2 + +# utility functions + +_dnf5_helper() { + _call_program specs $service "${(q-)@}" "${(q-)PREFIX}\*" \ + -qC --assumeno --nogpgcheck 2>/dev/null command' '*:: :->cmd_args' && ret=0 + + case $state in + command) _dnf5_commands && ret=0 ;; + cmd_args) _dnf5_subcmds_opts && ret=0 ;; + esac + return ret +} + +_dnf5 "$@" diff --git a/zsh/plugins/dnf/dnf.plugin.zsh b/zsh/plugins/dnf/dnf.plugin.zsh index 653ce7d..29bb64e 100644 --- a/zsh/plugins/dnf/dnf.plugin.zsh +++ b/zsh/plugins/dnf/dnf.plugin.zsh @@ -1,15 +1,27 @@ ## Aliases +local dnfprog="dnf" -alias dnfl="dnf list" # List packages -alias dnfli="dnf list installed" # List installed packages -alias dnfgl="dnf grouplist" # List package groups -alias dnfmc="dnf makecache" # Generate metadata cache -alias dnfp="dnf info" # Show package information -alias dnfs="dnf search" # Search package +# Prefer dnf5 if installed +command -v dnf5 > /dev/null && dnfprog=dnf5 -alias dnfu="sudo dnf upgrade" # Upgrade package -alias dnfi="sudo dnf install" # Install package -alias dnfgi="sudo dnf groupinstall" # Install package group -alias dnfr="sudo dnf remove" # Remove package -alias dnfgr="sudo dnf groupremove" # Remove package group -alias dnfc="sudo dnf clean all" # Clean cache +alias dnfl="${dnfprog} list" # List packages +alias dnfli="${dnfprog} list installed" # List installed packages +alias dnfmc="${dnfprog} makecache" # Generate metadata cache +alias dnfp="${dnfprog} info" # Show package information +alias dnfs="${dnfprog} search" # Search package + +alias dnfu="sudo ${dnfprog} upgrade" # Upgrade package +alias dnfi="sudo ${dnfprog} install" # Install package +alias dnfr="sudo ${dnfprog} remove" # Remove package +alias dnfc="sudo ${dnfprog} clean all" # Clean cache + +# Conditional aliases based on dnfprog value +if [[ "${dnfprog}" == "dnf5" ]]; then + alias dnfgl="${dnfprog} group list" # List package groups (dnf5) + alias dnfgi="sudo ${dnfprog} group install" # Install package group (dnf5) + alias dnfgr="sudo ${dnfprog} group remove" # Remove package group (dnf5) +else + alias dnfgl="${dnfprog} grouplist" # List package groups (dnf) + alias dnfgi="sudo ${dnfprog} groupinstall" # Install package group (dnf) + alias dnfgr="sudo ${dnfprog} groupremove" # Remove package group (dnf) +fi diff --git a/zsh/plugins/docker-compose/README.md b/zsh/plugins/docker-compose/README.md index 13f3c2c..5a02904 100644 --- a/zsh/plugins/docker-compose/README.md +++ b/zsh/plugins/docker-compose/README.md @@ -2,6 +2,8 @@ This plugin provides completion for [docker-compose](https://docs.docker.com/compose/) as well as some aliases for frequent docker-compose commands. +This plugin chooses automatically between the legacy `docker-compose` command and the modern +`docker compose` subcommand, preferring `docker-compose` when both are available. To use it, add docker-compose to the plugins array of your zshrc file: @@ -11,22 +13,24 @@ plugins=(... docker-compose) ## Aliases -| Alias | Command | Description | -|-----------|--------------------------------|------------------------------------------------------------------| -| dco | `docker-compose` | Docker-compose main command | -| dcb | `docker-compose build` | Build containers | -| dce | `docker-compose exec` | Execute command inside a container | -| dcps | `docker-compose ps` | List containers | -| dcrestart | `docker-compose restart` | Restart container | -| dcrm | `docker-compose rm` | Remove container | -| dcr | `docker-compose run` | Run a command in container | -| dcstop | `docker-compose stop` | Stop a container | -| dcup | `docker-compose up` | Build, (re)create, start, and attach to containers for a service | -| dcupb | `docker-compose up --build` | Same as `dcup`, but build images before starting containers | -| dcupd | `docker-compose up -d` | Same as `dcup`, but starts as daemon | -| dcdn | `docker-compose down` | Stop and remove containers | -| dcl | `docker-compose logs` | Show logs of container | -| dclf | `docker-compose logs -f` | Show logs and follow output | -| dcpull | `docker-compose pull` | Pull image of a service | -| dcstart | `docker-compose start` | Start a container | -| dck | `docker-compose kill` | Kills containers | +| Alias | Command | Description | +|-----------|----------------------------------|----------------------------------------------------------------------------------| +| dco | `docker-compose` | Docker-compose main command | +| dcb | `docker-compose build` | Build containers | +| dce | `docker-compose exec` | Execute command inside a container | +| dcps | `docker-compose ps` | List containers | +| dcrestart | `docker-compose restart` | Restart container | +| dcrm | `docker-compose rm` | Remove container | +| dcr | `docker-compose run` | Run a command in container | +| dcstop | `docker-compose stop` | Stop a container | +| dcup | `docker-compose up` | Build, (re)create, start, and attach to containers for a service | +| dcupb | `docker-compose up --build` | Same as `dcup`, but build images before starting containers | +| dcupd | `docker-compose up -d` | Same as `dcup`, but starts as daemon | +| dcupdb | `docker-compose up -d --build` | Same as `dcup`, but build images before starting containers and starts as daemon | +| dcdn | `docker-compose down` | Stop and remove containers | +| dcl | `docker-compose logs` | Show logs of container | +| dclf | `docker-compose logs -f` | Show logs and follow output | +| dclF | `docker-compose logs -f --tail0` | Just follow recent logs | +| dcpull | `docker-compose pull` | Pull image of a service | +| dcstart | `docker-compose start` | Start a container | +| dck | `docker-compose kill` | Kills containers | diff --git a/zsh/plugins/docker-compose/_docker-compose b/zsh/plugins/docker-compose/_docker-compose index c6b7335..d0ebfe5 100644 --- a/zsh/plugins/docker-compose/_docker-compose +++ b/zsh/plugins/docker-compose/_docker-compose @@ -128,7 +128,7 @@ __docker-compose_subcommand() { '--resolve-image-digests[Pin image tags to digests.]' \ '--services[Print the service names, one per line.]' \ '--volumes[Print the volume names, one per line.]' \ - '--hash[Print the service config hash, one per line. Set "service1,service2" for a list of specified services.]' \ && ret=0 + '--hash[Print the service config hash, one per line. Set "service1,service2" for a list of specified services.]' && ret=0 ;; (create) _arguments \ diff --git a/zsh/plugins/docker-compose/docker-compose.plugin.zsh b/zsh/plugins/docker-compose/docker-compose.plugin.zsh index b8a4b06..7863c4f 100644 --- a/zsh/plugins/docker-compose/docker-compose.plugin.zsh +++ b/zsh/plugins/docker-compose/docker-compose.plugin.zsh @@ -1,5 +1,8 @@ -# support Compose v2 as docker CLI plugin -(( ${+commands[docker-compose]} )) && dccmd='docker-compose' || dccmd='docker compose' +# Support Compose v2 as docker CLI plugin +# +# This tests that the (old) docker-compose command is in $PATH and that +# it resolves to an existing executable file if it's a symlink. +[[ -x "${commands[docker-compose]:A}" ]] && dccmd='docker-compose' || dccmd='docker compose' alias dco="$dccmd" alias dcb="$dccmd build" @@ -12,9 +15,11 @@ alias dcstop="$dccmd stop" alias dcup="$dccmd up" alias dcupb="$dccmd up --build" alias dcupd="$dccmd up -d" +alias dcupdb="$dccmd up -d --build" alias dcdn="$dccmd down" alias dcl="$dccmd logs" alias dclf="$dccmd logs -f" +alias dclF="$dccmd logs -f --tail 0" alias dcpull="$dccmd pull" alias dcstart="$dccmd start" alias dck="$dccmd kill" diff --git a/zsh/plugins/docker-machine/README.md b/zsh/plugins/docker-machine/README.md deleted file mode 100644 index 308a6cf..0000000 --- a/zsh/plugins/docker-machine/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# docker-machine plugin for oh my zsh - -### Usage - -#### docker-vm -Will create a docker-machine with the name "dev" (required only once) -To create a second machine call "docker-vm foobar" or pass any other name - -#### docker-up -This will start your "dev" docker-machine (if necessary) and set it as the active one -To start a named machine use "docker-up foobar" - -#### docker-switch dev -Use this to activate a running docker-machine (or to switch between multiple machines) -You need to call either this or docker-up when opening a new terminal - -#### docker-stop -This will stop your "dev" docker-machine -To stop a named machine use "docker-stop foobar" \ No newline at end of file diff --git a/zsh/plugins/docker-machine/_docker-machine b/zsh/plugins/docker-machine/_docker-machine deleted file mode 100644 index fbd36d7..0000000 --- a/zsh/plugins/docker-machine/_docker-machine +++ /dev/null @@ -1,359 +0,0 @@ -#compdef docker-machine -# Description -# ----------- -# zsh completion for docker-machine -# https://github.com/leonhartX/docker-machine-zsh-completion -# ------------------------------------------------------------------------- -# Version -# ------- -# 0.1.1 -# ------------------------------------------------------------------------- -# Authors -# ------- -# * Ke Xu -# ------------------------------------------------------------------------- -# Inspiration -# ----------- -# * @sdurrheimer docker-compose-zsh-completion https://github.com/sdurrheimer/docker-compose-zsh-completion -# * @ilkka _docker-machine - - -__docker-machine_get_hosts() { - [[ $PREFIX = -* ]] && return 1 - local state - declare -a hosts - state=$1; shift - if [[ $state != all ]]; then - hosts=(${(f)"$(_call_program commands docker-machine ls -q --filter state=$state)"}) - else - hosts=(${(f)"$(_call_program commands docker-machine ls -q)"}) - fi - _describe 'host' hosts "$@" && ret=0 - return ret -} - -__docker-machine_hosts_with_state() { - declare -a hosts - hosts=(${(f)"$(_call_program commands docker-machine ls -f '{{.Name}}\:{{.DriverName}}\({{.State}}\)\ {{.URL}}')"}) - _describe 'host' hosts -} - -__docker-machine_hosts_all() { - __docker-machine_get_hosts all "$@" -} - -__docker-machine_hosts_running() { - __docker-machine_get_hosts Running "$@" -} - -__docker-machine_get_swarm() { - declare -a swarms - swarms=(${(f)"$(_call_program commands docker-machine ls -f {{.Swarm}} | awk '{print $1}')"}) - _describe 'swarm' swarms -} - -__docker-machine_hosts_and_files() { - _alternative "hosts:host:__docker-machine_hosts_all -qS ':'" 'files:files:_path_files' -} - -__docker-machine_filters() { - [[ $PREFIX = -* ]] && return 1 - integer ret=1 - - if compset -P '*='; then - case "${${words[-1]%=*}#*=}" in - (driver) - _describe -t driver-filter-opts "driver filter" opts_driver && ret=0 - ;; - (swarm) - __docker-machine_get_swarm && ret=0 - ;; - (state) - opts_state=('Running' 'Paused' 'Saved' 'Stopped' 'Stopping' 'Starting' 'Error') - _describe -t state-filter-opts "state filter" opts_state && ret=0 - ;; - (name) - __docker-machine_hosts_all && ret=0 - ;; - (label) - _message 'label' && ret=0 - ;; - *) - _message 'value' && ret=0 - ;; - esac - else - opts=('driver' 'swarm' 'state' 'name' 'label') - _describe -t filter-opts "filter" opts -qS "=" && ret=0 - fi - return ret -} - -__get_swarm_discovery() { - declare -a masters services - local service - services=() - masters=($(docker-machine ls -f {{.Swarm}} |grep '(master)' |awk '{print $1}')) - for master in $masters; do - service=${${${(f)"$(_call_program commands docker-machine inspect -f '{{.HostOptions.SwarmOptions.Discovery}}:{{.Name}}' $master)"}/:/\\:}} - services=($services $service) - done - _describe -t services "swarm service" services && ret=0 - return ret -} - -__get_create_argument() { - typeset -g docker_machine_driver - if [[ CURRENT -le 2 ]]; then - docker_machine_driver="none" - elif [[ CURRENT > 2 && $words[CURRENT-2] = '-d' || $words[CURRENT-2] = '--driver' ]]; then - docker_machine_driver=$words[CURRENT-1] - elif [[ $words[CURRENT-1] =~ '^(-d|--driver)=' ]]; then - docker_machine_driver=${${words[CURRENT-1]}/*=/} - fi - local driver_opt_cmd - local -a opts_provider opts_common opts_read_argument - opts_read_argument=( - ": :->argument" - ) - opts_common=( - $opts_help \ - '(--driver -d)'{--driver=,-d=}'[Driver to create machine with]:dirver:->driver-option' \ - '--engine-install-url=[Custom URL to use for engine installation]:url' \ - '*--engine-opt=[Specify arbitrary flags to include with the created engine in the form flag=value]:flag' \ - '*--engine-insecure-registry=[Specify insecure registries to allow with the created engine]:registry' \ - '*--engine-registry-mirror=[Specify registry mirrors to use]:mirror' \ - '*--engine-label=[Specify labels for the created engine]:label' \ - '--engine-storage-driver=[Specify a storage driver to use with the engine]:storage-driver:->storage-driver-option' \ - '*--engine-env=[Specify environment variables to set in the engine]:environment' \ - '--swarm[Configure Machine with Swarm]' \ - '--swarm-image=[Specify Docker image to use for Swarm]:image' \ - '--swarm-master[Configure Machine to be a Swarm master]' \ - '--swarm-discovery=[Discovery service to use with Swarm]:service:->swarm-service' \ - '--swarm-strategy=[Define a default scheduling strategy for Swarm]:strategy:(spread binpack random)' \ - '*--swarm-opt=[Define arbitrary flags for swarm]:flag' \ - '*--swarm-join-opt=[Define arbitrary flags for Swarm join]:flag' \ - '--swarm-host=[ip/socket to listen on for Swarm master]:host' \ - '--swarm-addr=[addr to advertise for Swarm (default: detect and use the machine IP)]:address' \ - '--swarm-experimental[Enable Swarm experimental features]' \ - '*--tls-san=[Support extra SANs for TLS certs]:option' - ) - driver_opt_cmd="docker-machine create -d $docker_machine_driver | grep $docker_machine_driver | sed -e 's/\(--.*\)\ *\[\1[^]]*\]/*\1/g' -e 's/\(\[[^]]*\)/\\\\\\1\\\\/g' -e 's/\".*\"\(.*\)/\1/g' | awk '{printf \"%s[\", \$1; for(i=2;i<=NF;i++) {printf \"%s \", \$i}; print \"]\"}'" - if [[ $docker_machine_driver != "none" ]]; then - opts_provider=(${(f)"$(_call_program commands $driver_opt_cmd)"}) - _arguments \ - $opts_provider \ - $opts_read_argument \ - $opts_common && ret=0 - else - _arguments $opts_common && ret=0 - fi - case $state in - (driver-option) - _describe -t driver-option "driver" opts_driver && ret=0 - ;; - (storage-driver-option) - _describe -t storage-driver-option "storage driver" opts_storage_driver && ret=0 - ;; - (swarm-service) - __get_swarm_discovery && ret=0 - ;; - (argument) - ret=0 - ;; - esac - return ret -} - - -__docker-machine_subcommand() { - local -a opts_help - opts_help=("(- :)--help[Print usage]") - local -a opts_only_host opts_driver opts_storage_driver opts_state - opts_only_host=( - "$opts_help" - "*:host:__docker-machine_hosts_all" - ) - opts_driver=('amazonec2' 'azure' 'digitalocean' 'exoscale' 'generic' 'google' 'hyperv' 'none' 'openstack' 'rackspace' 'softlayer' 'virtualbox' 'vmwarefusion' 'vmwarevcloudair' 'vmwarevsphere') - opts_storage_driver=('overlay' 'aufs' 'btrfs' 'devicemapper' 'vfs' 'zfs') - integer ret=1 - - case "$words[1]" in - (active) - _arguments \ - $opts_help \ - '(--timeout -t)'{--timeout=,-t=}'[Timeout in seconds, default to 10s]:seconds' && ret=0 - ;; - (config) - _arguments \ - $opts_help \ - '--swarm[Display the Swarm config instead of the Docker daemon]' \ - "*:host:__docker-machine_hosts_all" && ret=0 - ;; - (create) - __get_create_argument - ;; - (env) - _arguments \ - $opts_help \ - '--swarm[Display the Swarm config instead of the Docker daemon]' \ - '--shell=[Force environment to be configured for a specified shell: \[fish, cmd, powershell\], default is auto-detect]:shell' \ - '(--unset -u)'{--unset,-u}'[Unset variables instead of setting them]' \ - '--no-proxy[Add machine IP to NO_PROXY environment variable]' \ - '*:host:__docker-machine_hosts_running' && ret=0 - ;; - (help) - _arguments ':subcommand:__docker-machine_commands' && ret=0 - ;; - (inspect) - _arguments \ - $opts_help \ - '(--format -f)'{--format=,-f=}'[Format the output using the given go template]:template' \ - '*:host:__docker-machine_hosts_all' && ret=0 - ;; - (ip) - _arguments \ - $opts_help \ - '*:host:__docker-machine_hosts_running' && ret=0 - ;; - (kill) - _arguments \ - $opts_help \ - '*:host:__docker-machine_hosts_with_state' && ret=0 - ;; - (ls) - _arguments \ - $opts_help \ - '(--quiet -q)'{--quiet,-q}'[Enable quiet mode]' \ - '*--filter=[Filter output based on conditions provided]:filter:->filter-options' \ - '(--timeout -t)'{--timeout=,-t=}'[Timeout in seconds, default to 10s]:seconds' \ - '(--format -f)'{--format=,-f=}'[Pretty-print machines using a Go template]:template' && ret=0 - case $state in - (filter-options) - __docker-machine_filters && ret=0 - ;; - esac - ;; - (provision) - _arguments $opts_only_host && ret=0 - ;; - (regenerate-certs) - _arguments \ - $opts_help \ - '(--force -f)'{--force,-f}'[Force rebuild and do not prompt]' \ - '*:host:__docker-machine_hosts_all' && ret=0 - ;; - (restart) - _arguments \ - $opts_help \ - '*:host:__docker-machine_hosts_with_state' && ret=0 - ;; - (rm) - _arguments \ - $opts_help \ - '(--force -f)'{--force,-f}'[Remove local configuration even if machine cannot be removed, also implies an automatic yes (`-y`)]' \ - '-y[Assumes automatic yes to proceed with remove, without prompting further user confirmation]' \ - '*:host:__docker-machine_hosts_with_state' && ret=0 - ;; - (scp) - _arguments \ - $opts_help \ - '(--recursive -r)'{--recursive,-r}'[Copy files recursively (required to copy directories))]' \ - '*:files:__docker-machine_hosts_and_files' && ret=0 - ;; - (ssh) - _arguments \ - $opts_help \ - '*:host:__docker-machine_hosts_running' && ret=0 - ;; - (start) - _arguments \ - $opts_help \ - '*:host:__docker-machine_hosts_with_state' && ret=0 - ;; - (status) - _arguments $opts_only_host && ret=0 - ;; - (stop) - _arguments \ - $opts_help \ - '*:host:__docker-machine_hosts_with_state' && ret=0 - ;; - (upgrade) - _arguments $opts_only_host && ret=0 - ;; - (url) - _arguments \ - $opts_help \ - '*:host:__docker-machine_hosts_running' && ret=0 - ;; - esac - - return ret -} - - -__docker-machine_commands() { - local cache_policy - - zstyle -s ":completion:${curcontext}:" cache-policy cache_policy - if [[ -z "$cache_policy" ]]; then - zstyle ":completion:${curcontext}:" cache-policy __docker-machine_caching_policy - fi - - if ( [[ ${+_docker_machine_subcommands} -eq 0 ]] || _cache_invalid docker_machine_subcommands) \ - && ! _retrieve_cache docker_machine_subcommands; - then - local -a lines - lines=(${(f)"$(_call_program commands docker-machine 2>&1)"}) - _docker_machine_subcommands=(${${${lines[$((${lines[(i)Commands:]} + 1)),${lines[(I) *]}]}## #}/$'\t'##/:}) - (( $#_docker_machine_subcommands > 0 )) && _store_cache docker_machine_subcommands _docker_machine_subcommands - fi - _describe -t docker-machine-commands "docker-machine command" _docker_machine_subcommands -} - -__docker-machine_caching_policy() { - oldp=( "$1"(Nmh+1) ) - (( $#oldp )) -} - -_docker-machine() { - if [[ $service != docker-machine ]]; then - _call_function - _$service - return - fi - - local curcontext="$curcontext" state line - integer ret=1 - typeset -A opt_args - - _arguments -C \ - "(- :)"{-h,--help}"[Show help]" \ - "(-D --debug)"{-D,--debug}"[Enable debug mode]" \ - '(-s --storage-path)'{-s,--storage-path}'[Configures storage path]:file:_files' \ - '--tls-ca-cert[CA to verify remotes against]:file:_files' \ - '--tls-ca-key[Private key to generate certificates]:file:_files' \ - '--tls-client-cert[Client cert to use for TLS]:file:_files' \ - '--tls-client-key[Private key used in client TLS auth]:file:_files' \ - '--github-api-token[Token to use for requests to the Github API]' \ - '--native-ssh[Use the native (Go-based) SSH implementation.]' \ - '--bugsnag-api-token[BugSnag API token for crash reporting]' \ - '(- :)'{-v,--version}'[Print the version]' \ - "(-): :->command" \ - "(-)*:: :->option-or-argument" && ret=0 - - case $state in - (command) - __docker-machine_commands && ret=0 - ;; - (option-or-argument) - curcontext=${curcontext%:*:*}:docker-machine-$words[1]: - __docker-machine_subcommand && ret=0 - ret=0 - ;; - esac - - return ret -} - -_docker-machine "$@" diff --git a/zsh/plugins/docker-machine/docker-machine.plugin.zsh b/zsh/plugins/docker-machine/docker-machine.plugin.zsh deleted file mode 100644 index 235d90e..0000000 --- a/zsh/plugins/docker-machine/docker-machine.plugin.zsh +++ /dev/null @@ -1,33 +0,0 @@ -DEFAULT_MACHINE="default" - -docker-up() { - if [ -z "$1" ] - then - docker-machine start "${DEFAULT_MACHINE}" - eval $(docker-machine env "${DEFAULT_MACHINE}") - else - docker-machine start $1 - eval $(docker-machine env $1) - fi - echo $DOCKER_HOST -} -docker-stop() { - if [ -z "$1" ] - then - docker-machine stop "${DEFAULT_MACHINE}" - else - docker-machine stop $1 - fi -} -docker-switch() { - eval $(docker-machine env $1) - echo $DOCKER_HOST -} -docker-vm() { - if [ -z "$1" ] - then - docker-machine create -d virtualbox --virtualbox-disk-size 20000 --virtualbox-memory 4096 --virtualbox-cpu-count 2 "${DEFAULT_MACHINE}" - else - docker-machine create -d virtualbox --virtualbox-disk-size 20000 --virtualbox-memory 4096 --virtualbox-cpu-count 2 $1 - fi -} \ No newline at end of file diff --git a/zsh/plugins/docker/README.md b/zsh/plugins/docker/README.md index 606690f..79b42bd 100644 --- a/zsh/plugins/docker/README.md +++ b/zsh/plugins/docker/README.md @@ -13,18 +13,15 @@ https://github.com/docker/cli/blob/master/contrib/completion/zsh/_docker ## Settings -By default, the completion doesn't allow option-stacking, meaning if you try to -complete `docker run -it ` it won't work, because you're _stacking_ the -`-i` and `-t` options. +By default, the completion doesn't allow option-stacking, meaning if you try to complete +`docker run -it ` it won't work, because you're _stacking_ the `-i` and `-t` options. -[You can enable it](https://github.com/docker/cli/commit/b10fb43048) by **adding -the lines below to your zshrc file**, but be aware of the side effects: +[You can enable it](https://github.com/docker/cli/commit/b10fb43048) by **adding the lines below to your zshrc +file**, but be aware of the side effects: -> This enables Zsh to understand commands like `docker run -it -> ubuntu`. However, by enabling this, this also makes Zsh complete -> `docker run -u` with `docker run -uapprox` which is not valid. The -> users have to put the space or the equal sign themselves before trying -> to complete. +> This enables Zsh to understand commands like `docker run -it ubuntu`. However, by enabling this, this also +> makes Zsh complete `docker run -u` with `docker run -uapprox` which is not valid. The users have to put +> the space or the equal sign themselves before trying to complete. > > Therefore, this behavior is disabled by default. To enable it: > @@ -33,41 +30,60 @@ the lines below to your zshrc file**, but be aware of the side effects: > zstyle ':completion:*:*:docker-*:*' option-stacking yes > ``` +### Use old-style completion + +If the current completion does not work well for you, you can enable legacy completion instead with the +following setting. See https://github.com/ohmyzsh/ohmyzsh/issues/11789 for more information. + +```zsh +zstyle ':omz:plugins:docker' legacy-completion yes +``` + +### For Podman's Docker wrapper users + +If you use Podman's Docker wrapper, you need to enable legacy completion. See above section. + ## Aliases -| Alias | Command | Description | -| :------ | :-------------------------- | :--------------------------------------------------------------------------------------- | -| dbl | `docker build` | Build an image from a Dockerfile | -| dcin | `docker container inspect` | Display detailed information on one or more containers | -| dlo | `docker container logs` | Fetch the logs of a docker container | -| dcls | `docker container ls` | List all the running docker containers | -| dclsa | `docker container ls -a` | List all running and stopped containers | -| dpo | `docker container port` | List port mappings or a specific mapping for the container | -| dpu | `docker pull` | Pull an image or a repository from a registry | -| dr | `docker container run` | Create a new container and start it using the specified command | -| drit | `docker container run -it` | Create a new container and start it in an interactive shell | -| drm | `docker container rm` | Remove the specified container(s) | -| drm! | `docker container rm -f` | Force the removal of a running container (uses SIGKILL) | -| dst | `docker container start` | Start one or more stopped containers | -| dstp | `docker container stop` | Stop one or more running containers | -| dtop | `docker top` | Display the running processes of a container | -| dxc | `docker container exec` | Run a new command in a running container | -| dxcit | `docker container exec -it` | Run a new command in a running container in an interactive shell | -| | | **Docker Images** | -| dib | `docker image build` | Build an image from a Dockerfile (same as docker build) | -| dii | `docker image inspect` | Display detailed information on one or more images | -| dils | `docker image ls` | List docker images | -| dipu | `docker image push` | Push an image or repository to a remote registry | -| dirm | `docker image rm` | Remove one or more images | -| dit | `docker image tag` | Add a name and tag to a particular image | -| | | **Docker Network** | -| dnc | `docker network create` | Create a new network | -| dncn | `docker network connect` | Connect a container to a network | -| dndcn | `docker network disconnect` | Disconnect a container from a network | -| dni | `docker network inspect` | Return information about one or more networks | -| dnls | `docker network ls` | List all networks the engine daemon knows about, including those spanning multiple hosts | -| dnrm | `docker network rm` | Remove one or more networks | -| | | **Docker Volume** | -| dvi | `docker volume inspect` | Display detailed information about one or more volumes | -| dvls | `docker volume ls` | List all the volumes known to docker | -| dvprune | `docker volume prune` | Cleanup dangling volumes | +| Alias | Command | Description | +| :------ | :---------------------------- | :--------------------------------------------------------------------------------------- | +| dbl | `docker build` | Build an image from a Dockerfile | +| dcin | `docker container inspect` | Display detailed information on one or more containers | +| dcls | `docker container ls` | List all the running docker containers | +| dclsa | `docker container ls -a` | List all running and stopped containers | +| dcprune | `docker container prune` | Remove all stopped containers | +| dib | `docker image build` | Build an image from a Dockerfile (same as docker build) | +| dii | `docker image inspect` | Display detailed information on one or more images | +| dils | `docker image ls` | List docker images | +| dipu | `docker image push` | Push an image or repository to a remote registry | +| dipru | `docker image prune -a` | Remove all images not referenced by any container | +| dirm | `docker image rm` | Remove one or more images | +| dit | `docker image tag` | Add a name and tag to a particular image | +| dlo | `docker container logs` | Fetch the logs of a docker container | +| dnc | `docker network create` | Create a new network | +| dncn | `docker network connect` | Connect a container to a network | +| dndcn | `docker network disconnect` | Disconnect a container from a network | +| dni | `docker network inspect` | Return information about one or more networks | +| dnls | `docker network ls` | List all networks the engine daemon knows about, including those spanning multiple hosts | +| dnprune | `docker network prune` | Remove all unused networks | +| dnrm | `docker network rm` | Remove one or more networks | +| dpo | `docker container port` | List port mappings or a specific mapping for the container | +| dps | `docker ps` | List all the running docker containers | +| dpsa | `docker ps -a` | List all running and stopped containers | +| dpu | `docker pull` | Pull an image or a repository from a registry | +| dr | `docker container run` | Create a new container and start it using the specified command | +| drit | `docker container run -it` | Create a new container and start it in an interactive shell | +| drm | `docker container rm` | Remove the specified container(s) | +| drm! | `docker container rm -f` | Force the removal of a running container (uses SIGKILL) | +| dsprune | `docker system prune` | Remove unused data | +| dst | `docker container start` | Start one or more stopped containers | +| drs | `docker container restart` | Restart one or more containers | +| dsta | `docker stop $(docker ps -q)` | Stop all running containers | +| dstp | `docker container stop` | Stop one or more running containers | +| dsts | `docker stats` | Display real-time streaming statistics for containers | +| dtop | `docker top` | Display the running processes of a container | +| dvi | `docker volume inspect` | Display detailed information about one or more volumes | +| dvls | `docker volume ls` | List all the volumes known to docker | +| dvprune | `docker volume prune` | Cleanup dangling volumes | +| dxc | `docker container exec` | Run a new command in a running container | +| dxcit | `docker container exec -it` | Run a new command in a running container in an interactive shell | diff --git a/zsh/plugins/docker/_docker b/zsh/plugins/docker/completions/_docker similarity index 97% rename from zsh/plugins/docker/_docker rename to zsh/plugins/docker/completions/_docker index 8ee35ab..466b09d 100644 --- a/zsh/plugins/docker/_docker +++ b/zsh/plugins/docker/completions/_docker @@ -567,7 +567,7 @@ __docker_container_commands() { "cp:Copy files/folders between a container and the local filesystem" "create:Create a new container" "diff:Inspect changes on a container's filesystem" - "exec:Run a command in a running container" + "exec:Execute a command in a running container" "export:Export a container's filesystem as a tar archive" "inspect:Display detailed information on one or more containers" "kill:Kill one or more running containers" @@ -579,7 +579,7 @@ __docker_container_commands() { "rename:Rename a container" "restart:Restart one or more containers" "rm:Remove one or more containers" - "run:Run a command in a new container" + "run:Create and run a new container from an image" "start:Start one or more stopped containers" "stats:Display a live stream of container(s) resource usage statistics" "stop:Stop one or more running containers" @@ -602,6 +602,7 @@ __docker_container_subcommand() { opts_create_run=( "($help -a --attach)"{-a=,--attach=}"[Attach to stdin, stdout or stderr]:device:(STDIN STDOUT STDERR)" "($help)*--add-host=[Add a custom host-to-IP mapping]:host\:ip mapping: " + "($help)*--annotation=[Add an annotation to the container (passed through to the OCI runtime)]:annotations: " "($help)*--blkio-weight-device=[Block IO (relative device weight)]:device:Block IO weight: " "($help)*--cap-add=[Add Linux capabilities]:capability: " "($help)*--cap-drop=[Drop Linux capabilities]:capability: " @@ -650,6 +651,7 @@ __docker_container_subcommand() { "($help)*"{-p=,--publish=}"[Expose a container's port to the host]:port:_ports" "($help)--pid=[PID namespace to use]:PID namespace:__docker_complete_pid" "($help)--privileged[Give extended privileges to this container]" + "($help -q --quiet)"{-q,--quiet}"[Suppress the pull output]" "($help)--read-only[Mount the container's root filesystem as read only]" "($help)*--security-opt=[Security options]:security option: " "($help)*--shm-size=[Size of '/dev/shm' (format is '')]:shm size: " @@ -661,7 +663,7 @@ __docker_container_subcommand() { "($help)*--ulimit=[ulimit options]:ulimit: " "($help)--userns=[Container user namespace]:user namespace:(host)" "($help)--tmpfs[mount tmpfs]" - "($help)*-v[Bind mount a volume]:volume: " + "($help)*-v[Bind mount a volume]:volume:_directories -W / -P '/' -S '\:' -r '/ '" "($help)--volume-driver=[Optional volume driver for the container]:volume driver:(local)" "($help)*--volumes-from=[Mount volumes from the specified container]:volume: " "($help -w --workdir)"{-w=,--workdir=}"[Working directory inside the container]:directory:_directories" @@ -802,7 +804,7 @@ __docker_container_subcommand() { "($help -a --all)"{-a,--all}"[Show all containers]" \ "($help)--before=[Show only container created before...]:containers:__docker_complete_containers" \ "($help)*"{-f=,--filter=}"[Filter values]:filter:__docker_complete_ps_filters" \ - "($help)--format=[Pretty-print containers using a Go template]:template: " \ + "($help)--format=[Format the output using the given Go template]:template: " \ "($help -l --latest)"{-l,--latest}"[Show only the latest created container]" \ "($help -n --last)"{-n=,--last=}"[Show n last created containers (includes all states)]:n:(1 5 10 25 50)" \ "($help)--no-trunc[Do not truncate output]" \ @@ -907,7 +909,7 @@ __docker_container_subcommand() { _arguments $(__docker_arguments) \ $opts_help \ "($help -a --all)"{-a,--all}"[Show all containers (default shows just running)]" \ - "($help)--format=[Pretty-print images using a Go template]:template: " \ + "($help)--format=[Format the output using the given Go template]:template: " \ "($help)--no-stream[Disable streaming stats and only pull the first result]" \ "($help)--no-trunc[Do not truncate output]" \ "($help -)*:containers:__docker_complete_running_containers" && ret=0 @@ -973,8 +975,8 @@ __docker_image_commands() { "load:Load an image from a tar archive or STDIN" "ls:List images" "prune:Remove unused images" - "pull:Pull an image or a repository from a registry" - "push:Push an image or a repository to a registry" + "pull:Download an image from a registry" + "push:Upload an image to a registry" "rm:Remove one or more images" "save:Save one or more images to a tar archive (streamed to STDOUT by default)" "tag:Tag an image into a repository" @@ -1060,7 +1062,7 @@ __docker_image_subcommand() { "($help -a --all)"{-a,--all}"[Show all images]" \ "($help)--digests[Show digests]" \ "($help)*"{-f=,--filter=}"[Filter values]:filter:__docker_complete_images_filters" \ - "($help)--format=[Pretty-print images using a Go template]:template: " \ + "($help)--format=[Format the output using the given Go template]:template: " \ "($help)--no-trunc[Do not truncate output]" \ "($help -q --quiet)"{-q,--quiet}"[Only show image IDs]" \ "($help -): :__docker_complete_repositories" && ret=0 @@ -1082,7 +1084,7 @@ __docker_image_subcommand() { (push) _arguments $(__docker_arguments) \ $opts_help \ - "($help -a --all-tags)"{-a,--all-tags}"[Push all tagged images in the repository]" \ + "($help -a --all-tags)"{-a,--all-tags}"[Push all tags of an image to the repository]" \ "($help)--disable-content-trust[Skip image signing]" \ "($help -): :__docker_complete_images" && ret=0 ;; @@ -1292,7 +1294,7 @@ __docker_network_subcommand() { $opts_help \ "($help)--no-trunc[Do not truncate the output]" \ "($help)*"{-f=,--filter=}"[Provide filter values]:filter:__docker_network_complete_ls_filters" \ - "($help)--format=[Pretty-print networks using a Go template]:template: " \ + "($help)--format=[Format the output using the given Go template]:template: " \ "($help -q --quiet)"{-q,--quiet}"[Only display network IDs]" && ret=0 ;; (prune) @@ -2050,7 +2052,7 @@ __docker_service_subcommand() { _arguments $(__docker_arguments) \ $opts_help \ "($help)*"{-f=,--filter=}"[Filter output based on conditions provided]:filter:__docker_service_complete_ls_filters" \ - "($help)--format=[Pretty-print services using a Go template]:template: " \ + "($help)--format=[Format the output using the given Go template]:template: " \ "($help -q --quiet)"{-q,--quiet}"[Only display IDs]" && ret=0 ;; (rm|remove) @@ -2253,7 +2255,7 @@ __docker_stack_subcommand() { _arguments $(__docker_arguments) \ $opts_help \ "($help)*"{-f=,--filter=}"[Filter output based on conditions provided]:filter:__docker_stack_complete_services_filters" \ - "($help)--format=[Pretty-print services using a Go template]:template: " \ + "($help)--format=[Format the output using the given Go template]:template: " \ "($help -q --quiet)"{-q,--quiet}"[Only display IDs]" \ "($help -):stack:__docker_complete_stacks" && ret=0 ;; @@ -2520,12 +2522,14 @@ __docker_volume_subcommand() { _arguments $(__docker_arguments) \ $opts_help \ "($help)*"{-f=,--filter=}"[Provide filter values]:filter:__docker_volume_complete_ls_filters" \ - "($help)--format=[Pretty-print volumes using a Go template]:template: " \ + "($help)--format=[Format the output using the given Go template]:template: " \ "($help -q --quiet)"{-q,--quiet}"[Only display volume names]" && ret=0 ;; (prune) _arguments $(__docker_arguments) \ $opts_help \ + "($help -a --all)"{-a,--all}"[Remove all unused local volumes, not just anonymous ones]" \ + "($help)*--filter=[Filter values]:filter:__docker_complete_prune_filters" \ "($help -f --force)"{-f,--force}"[Do not prompt for confirmation]" && ret=0 ;; (rm) @@ -2582,10 +2586,8 @@ __docker_context_subcommand() { (create) _arguments $(__docker_arguments) \ $opts_help \ - "($help)--default-stack-orchestrator=[Default orchestrator for stack operations to use with this context]:default-stack-orchestrator:(swarm kubernetes all)" \ "($help)--description=[Description of the context]:description:" \ "($help)--docker=[Set the docker endpoint]:docker:" \ - "($help)--kubernetes=[Set the kubernetes endpoint]:kubernetes:" \ "($help)--from=[Create context from a named context]:from:__docker_complete_contexts" \ "($help -):name: " && ret=0 ;; @@ -2607,10 +2609,8 @@ __docker_context_subcommand() { (update) _arguments $(__docker_arguments) \ $opts_help \ - "($help)--default-stack-orchestrator=[Default orchestrator for stack operations to use with this context]:default-stack-orchestrator:(swarm kubernetes all)" \ "($help)--description=[Description of the context]:description:" \ "($help)--docker=[Set the docker endpoint]:docker:" \ - "($help)--kubernetes=[Set the kubernetes endpoint]:kubernetes:" \ "($help -):name:" && ret=0 ;; esac @@ -2734,9 +2734,6 @@ __docker_subcommand() { "($help -b --bridge)"{-b=,--bridge=}"[Attach containers to a network bridge]:bridge:_net_interfaces" \ "($help)--bip=[Network bridge IP]:IP address: " \ "($help)--cgroup-parent=[Parent cgroup for all containers]:cgroup: " \ - "($help)--cluster-advertise=[Address or interface name to advertise]:Instance to advertise (host\:port): " \ - "($help)--cluster-store=[URL of the distributed storage backend]:Cluster Store:->cluster-store" \ - "($help)*--cluster-store-opt=[Cluster store options]:Cluster options:->cluster-store-options" \ "($help)--config-file=[Path to daemon configuration file]:Config File:_files" \ "($help)--containerd=[Path to containerd socket]:socket:_files -g \"*.sock\"" \ "($help)--containerd-namespace=[Containerd namespace to use]:containerd namespace:" \ @@ -2771,16 +2768,16 @@ __docker_subcommand() { "($help)--live-restore[Enable live restore of docker when containers are still running]" \ "($help)--log-driver=[Default driver for container logs]:logging driver:__docker_complete_log_drivers" \ "($help)*--log-opt=[Default log driver options for containers]:log driver options:__docker_complete_log_options" \ - "($help)--max-concurrent-downloads[Set the max concurrent downloads for each pull]" \ - "($help)--max-concurrent-uploads[Set the max concurrent uploads for each push]" \ + "($help)--max-concurrent-downloads[Set the max concurrent downloads]" \ + "($help)--max-concurrent-uploads[Set the max concurrent uploads]" \ "($help)--max-download-attempts[Set the max download attempts for each pull]" \ "($help)--mtu=[Network MTU]:mtu:(0 576 1420 1500 9000)" \ "($help)--oom-score-adjust=[Set the oom_score_adj for the daemon]:oom-score:(-500)" \ "($help -p --pidfile)"{-p=,--pidfile=}"[Path to use for daemon PID file]:PID file:_files" \ "($help)--raw-logs[Full timestamps without ANSI coloring]" \ - "($help)*--registry-mirror=[Preferred Docker registry mirror]:registry mirror: " \ + "($help)*--registry-mirror=[Preferred registry mirror]:registry mirror: " \ "($help)--seccomp-profile=[Path to seccomp profile]:path:_files -g \"*.json\"" \ - "($help -s --storage-driver)"{-s=,--storage-driver=}"[Storage driver to use]:driver:(aufs btrfs devicemapper overlay overlay2 vfs zfs)" \ + "($help -s --storage-driver)"{-s=,--storage-driver=}"[Storage driver to use]:driver:(btrfs devicemapper overlay2 vfs zfs)" \ "($help)--selinux-enabled[Enable selinux support]" \ "($help)--shutdown-timeout=[Set the shutdown timeout value in seconds]:time: " \ "($help)*--storage-opt=[Storage driver options]:storage driver options: " \ @@ -2795,22 +2792,6 @@ __docker_subcommand() { "($help)--validate[Validate daemon configuration and exit]" && ret=0 case $state in - (cluster-store) - if compset -P '*://'; then - _message 'host:port' && ret=0 - else - store=('consul' 'etcd' 'zk') - _describe -t cluster-store "Cluster Store" store -qS "://" && ret=0 - fi - ;; - (cluster-store-options) - if compset -P '*='; then - _files && ret=0 - else - opts=('discovery.heartbeat' 'discovery.ttl' 'kv.cacertfile' 'kv.certfile' 'kv.keyfile' 'kv.path') - _describe -t cluster-store-opts "Cluster Store Options" opts -qS "=" && ret=0 - fi - ;; (users-groups) if compset -P '*:'; then _groups && ret=0 @@ -3095,6 +3076,7 @@ _docker() { _arguments $(__docker_arguments) -C \ "(: -)"{-h,--help}"[Print usage]" \ "($help)--config[Location of client config files]:path:_directories" \ + "($help -c --context)"{-c=,--context=}"[Execute the command in a docker context]:context:__docker_complete_contexts" \ "($help -D --debug)"{-D,--debug}"[Enable debug mode]" \ "($help -H --host)"{-H=,--host=}"[tcp://host:port to bind/connect to]:host: " \ "($help -l --log-level)"{-l=,--log-level=}"[Logging level]:level:(debug info warn error fatal)" \ @@ -3110,7 +3092,8 @@ _docker() { local host=${opt_args[-H]}${opt_args[--host]} local config=${opt_args[--config]} - local docker_options="${host:+--host $host} ${config:+--config $config}" + local context=${opt_args[-c]}${opt_args[--context]} + local docker_options="${host:+--host $host} ${config:+--config $config} ${context:+--context $context} " case $state in (command) diff --git a/zsh/plugins/docker/docker.plugin.zsh b/zsh/plugins/docker/docker.plugin.zsh index 9c8ad8a..9d7cf86 100644 --- a/zsh/plugins/docker/docker.plugin.zsh +++ b/zsh/plugins/docker/docker.plugin.zsh @@ -1,39 +1,69 @@ alias dbl='docker build' -alias dpu='docker pull' -alias dtop='docker top' - -# docker containers alias dcin='docker container inspect' -alias dlo='docker container logs' alias dcls='docker container ls' alias dclsa='docker container ls -a' -alias dpo='docker container port' -alias dr='docker container run' -alias drit='docker container run -it' -alias drm='docker container rm' -alias 'drm!'='docker container rm -f' -alias dst='docker container start' -alias dstp='docker container stop' -alias dxc='docker container exec' -alias dxcit='docker container exec -it' - -# docker images +alias dcprune='docker container prune' alias dib='docker image build' alias dii='docker image inspect' alias dils='docker image ls' alias dipu='docker image push' +alias dipru='docker image prune -a' alias dirm='docker image rm' alias dit='docker image tag' - -# docker network +alias dlo='docker container logs' alias dnc='docker network create' alias dncn='docker network connect' alias dndcn='docker network disconnect' alias dni='docker network inspect' alias dnls='docker network ls' +alias dnprune='docker network prune' alias dnrm='docker network rm' - -# docker volume +alias dpo='docker container port' +alias dps='docker ps' +alias dpsa='docker ps -a' +alias dpu='docker pull' +alias dr='docker container run' +alias drit='docker container run -it' +alias drm='docker container rm' +alias 'drm!'='docker container rm -f' +alias dsprune='docker system prune' +alias dst='docker container start' +alias drs='docker container restart' +alias dsta='docker stop $(docker ps -q)' +alias dstp='docker container stop' +alias dsts='docker stats' +alias dtop='docker top' alias dvi='docker volume inspect' alias dvls='docker volume ls' alias dvprune='docker volume prune' +alias dxc='docker container exec' +alias dxcit='docker container exec -it' + +if (( ! $+commands[docker] )); then + return +fi + +# Standardized $0 handling +# https://zdharma-continuum.github.io/Zsh-100-Commits-Club/Zsh-Plugin-Standard.html +0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" +0="${${(M)0:#/*}:-$PWD/$0}" + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `docker`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_docker" ]]; then + typeset -g -A _comps + autoload -Uz _docker + _comps[docker]=_docker +fi + +{ + # `docker completion` is only available from 23.0.0 on + # docker version returns `Docker version 24.0.2, build cb74dfcd85` + # with `s:,:` remove the comma after the version, and select third word of it + if zstyle -t ':omz:plugins:docker' legacy-completion || \ + ! is-at-least 23.0.0 ${${(s:,:z)"$(command docker --version)"}[3]}; then + command cp "${0:h}/completions/_docker" "$ZSH_CACHE_DIR/completions/_docker" + else + command docker completion zsh | tee "$ZSH_CACHE_DIR/completions/_docker" > /dev/null + fi +} &| diff --git a/zsh/plugins/doctl/doctl.plugin.zsh b/zsh/plugins/doctl/doctl.plugin.zsh index d23ed08..7b3a384 100644 --- a/zsh/plugins/doctl/doctl.plugin.zsh +++ b/zsh/plugins/doctl/doctl.plugin.zsh @@ -4,6 +4,14 @@ # # Author: https://github.com/HalisCz -if [ $commands[doctl] ]; then - source <(doctl completion zsh) +if (( ! $+commands[doctl] )); then + return fi + +if [[ ! -f "$ZSH_CACHE_DIR/completions/_doctl" ]]; then + typeset -g -A _comps + autoload -Uz _doctl + _comps[doctl]=_doctl +fi + +doctl completion zsh >| "$ZSH_CACHE_DIR/completions/_doctl" &| diff --git a/zsh/plugins/dotenv/README.md b/zsh/plugins/dotenv/README.md index ab9d329..5dbcf0f 100644 --- a/zsh/plugins/dotenv/README.md +++ b/zsh/plugins/dotenv/README.md @@ -78,6 +78,14 @@ change. NOTE: if a directory is found in both the allowed and disallowed lists, the disallowed list takes preference, _i.e._ the .env file will never be sourced. +## Named Pipe (FIFO) Support + +The plugin supports `.env` files provided as UNIX named pipes (FIFOs) in addition to regular files. +This is useful when secrets managers like [1Password Environments](https://developer.1password.com/docs/environment/) +mount `.env` files as named pipes to inject secrets on-the-fly without writing them to disk. + +No additional configuration is required — the plugin automatically detects and sources named pipes. + ## Version Control **It's strongly recommended to add `.env` file to `.gitignore`**, because usually it contains sensitive information such as your credentials, secret keys, passwords etc. You don't want to commit this file, it's supposed to be local only. diff --git a/zsh/plugins/dotenv/dotenv.plugin.zsh b/zsh/plugins/dotenv/dotenv.plugin.zsh index 46cd4b1..c44c369 100644 --- a/zsh/plugins/dotenv/dotenv.plugin.zsh +++ b/zsh/plugins/dotenv/dotenv.plugin.zsh @@ -11,7 +11,7 @@ ## Functions source_env() { - if [[ ! -f "$ZSH_DOTENV_FILE" ]]; then + if [[ ! -f "$ZSH_DOTENV_FILE" ]] && [[ ! -p "$ZSH_DOTENV_FILE" ]]; then return fi diff --git a/zsh/plugins/dotnet/README.md b/zsh/plugins/dotnet/README.md index 87dfd8f..2b06d88 100644 --- a/zsh/plugins/dotnet/README.md +++ b/zsh/plugins/dotnet/README.md @@ -1,6 +1,6 @@ -# .NET Core CLI plugin +# .NET CLI plugin -This plugin provides completion and useful aliases for [.NET Core CLI](https://dotnet.microsoft.com/). +This plugin provides completion and useful aliases for [.NET CLI](https://dotnet.microsoft.com/). To use it, add `dotnet` to the plugins array in your zshrc file. @@ -17,8 +17,10 @@ plugins=(... dotnet) | dt | dotnet test | Run unit tests using the test runner specified in a .NET project. | | dw | dotnet watch | Watch for source file changes and restart the dotnet command. | | dwr | dotnet watch run | Watch for source file changes and restart the `run` command. | +| dwt | dotnet watch test| Watch for source file changes and restart the `test` command. | | ds | dotnet sln | Modify Visual Studio solution files. | | da | dotnet add | Add a package or reference to a .NET project. | | dp | dotnet pack | Create a NuGet package. | | dng | dotnet nuget | Provides additional NuGet commands. | | db | dotnet build | Build a .NET project | +| dres | dotnet restore | Restore dependencies and project-specific tools for a project. | diff --git a/zsh/plugins/dotnet/dotnet.plugin.zsh b/zsh/plugins/dotnet/dotnet.plugin.zsh index 8ea31cd..2b77824 100644 --- a/zsh/plugins/dotnet/dotnet.plugin.zsh +++ b/zsh/plugins/dotnet/dotnet.plugin.zsh @@ -1,33 +1,27 @@ # This scripts is copied from (MIT License): -# https://github.com/dotnet/toolset/blob/master/scripts/register-completions.zsh +# https://raw.githubusercontent.com/dotnet/sdk/main/scripts/register-completions.zsh -_dotnet_zsh_complete() -{ - local completions=("$(dotnet complete "$words")") - - # If the completion list is empty, just continue with filename selection - if [ -z "$completions" ] - then - _arguments '*::arguments: _normal' - return - fi - - # This is not a variable assignment, don't remove spaces! - _values = "${(ps:\n:)completions}" +#compdef dotnet +_dotnet_completion() { + local -a completions=("${(@f)$(dotnet complete "${words}")}") + compadd -a completions + _files } -compdef _dotnet_zsh_complete dotnet +compdef _dotnet_completion dotnet -# Aliases bellow are here for backwards compatibility -# added by Shaun Tabone (https://github.com/xontab) +# Aliases below are here for backwards compatibility +# added by Shaun Tabone (https://github.com/xontab) alias dn='dotnet new' alias dr='dotnet run' alias dt='dotnet test' alias dw='dotnet watch' alias dwr='dotnet watch run' +alias dwt='dotnet watch test' alias ds='dotnet sln' alias da='dotnet add' alias dp='dotnet pack' alias dng='dotnet nuget' alias db='dotnet build' +alias dres='dotnet restore' diff --git a/zsh/plugins/emacs/README.md b/zsh/plugins/emacs/README.md index c8e33b5..47c7644 100644 --- a/zsh/plugins/emacs/README.md +++ b/zsh/plugins/emacs/README.md @@ -25,6 +25,6 @@ The plugin uses a custom launcher (which we'll call here `$EMACS_LAUNCHER`) that | e | `emacs` | Same as emacs alias | | te | `$EMACS_LAUNCHER -nw` | Open terminal emacsclient | | eeval | `$EMACS_LAUNCHER --eval` | Same as `M-x eval` but from outside Emacs | -| eframe | `emacsclient --alternate-editor "" --create-frame` | Create new X frame | +| eframe | `emacsclient --alternate-editor="" --create-frame` | Create new X frame | | efile | - | Print the path to the file open in the current buffer | -| ecd | - | Print the directory of the file open in the the current buffer | +| ecd | - | Print the directory of the file open in the current buffer | diff --git a/zsh/plugins/emacs/emacs.plugin.zsh b/zsh/plugins/emacs/emacs.plugin.zsh index fede5b0..3ed6cee 100644 --- a/zsh/plugins/emacs/emacs.plugin.zsh +++ b/zsh/plugins/emacs/emacs.plugin.zsh @@ -32,10 +32,10 @@ alias te="$EMACS_PLUGIN_LAUNCHER -nw" # same than M-x eval but from outside Emacs. alias eeval="$EMACS_PLUGIN_LAUNCHER --eval" # create a new X frame -alias eframe='emacsclient --alternate-editor "" --create-frame' +alias eframe='emacsclient --alternate-editor="" --create-frame' # Emacs ANSI Term tracking -if [[ -n "$INSIDE_EMACS" ]]; then +if [[ -n "$INSIDE_EMACS" ]] && [[ "$INSIDE_EMACS" != "vterm" ]]; then chpwd_emacs() { print -P "\033AnSiTc %d"; } print -P "\033AnSiTc %d" # Track current working directory print -P "\033AnSiTu %n" # Track username @@ -60,7 +60,7 @@ function efile { } # Write to standard output the directory of the file -# opened in the the current buffer +# opened in the current buffer function ecd { local file file="$(efile)" || return $? diff --git a/zsh/plugins/emacs/emacsclient.sh b/zsh/plugins/emacs/emacsclient.sh index 96893c9..172c0ae 100755 --- a/zsh/plugins/emacs/emacsclient.sh +++ b/zsh/plugins/emacs/emacsclient.sh @@ -15,11 +15,11 @@ emacsfun() { # Only create another X frame if there isn't one present if [ -z "$frames" -o "$frames" = nil ]; then - emacsclient --alternate-editor "" --create-frame "$@" + emacsclient --alternate-editor="" --create-frame "$@" return $? fi - emacsclient --alternate-editor "" "$@" + emacsclient --alternate-editor="" "$@" } # Adapted from https://github.com/davidshepherd7/emacs-read-stdin/blob/master/emacs-read-stdin.sh diff --git a/zsh/plugins/ember-cli/README.md b/zsh/plugins/ember-cli/README.md index 419704a..1532eea 100644 --- a/zsh/plugins/ember-cli/README.md +++ b/zsh/plugins/ember-cli/README.md @@ -29,5 +29,5 @@ plugins=(... ember-cli) - [BilalBudhani](https://github.com/BilalBudhani) - [eubenesa](https://github.com/eubenesa) -- [scottkidder](https://github.com/scottkidder] +- [scottkidder](https://github.com/scottkidder) - [t-sauer](https://www.github.com/t-sauer) diff --git a/zsh/plugins/emoji/emoji.plugin.zsh b/zsh/plugins/emoji/emoji.plugin.zsh index f9e476e..f7be56c 100644 --- a/zsh/plugins/emoji/emoji.plugin.zsh +++ b/zsh/plugins/emoji/emoji.plugin.zsh @@ -24,7 +24,7 @@ unset _omz_emoji_plugin_dir # This is a combining character that can be placed after any other character to surround # it in a "keycap" symbol. -# The digits 0-9 are already in the emoji table as keycap_digit_, keycap_ten, etc. +# The digits 0-9 are already in the emoji table as keycap_digit_, keycap_ten, etc. # It's unclear whether this should be in the $emoji array, because those characters are all ones # which can be displayed on their own. @@ -63,9 +63,9 @@ function random_emoji() { [[ $list_size -eq 0 ]] && return 1 local random_index=$(( ( RANDOM % $list_size ) + 1 )) local name=${names[$random_index]} - if [[ "$group" == "flags" ]]; then + if [[ "$group" == "flags" ]]; then echo ${emoji_flags[$name]} - else + else echo ${emoji[$name]} fi } @@ -86,22 +86,22 @@ function display_emoji() { # terminals treat these emoji chars as single-width. local counter=1 for i in $names; do - if [[ "$group" == "flags" ]]; then + if [[ "$group" == "flags" ]]; then printf '%s ' "$emoji_flags[$i]" - else - printf '%s ' "$emoji[$i]" + else + printf '%s ' "$emoji[$i]" fi # New line every 20 emoji, to avoid weirdnesses if (($counter % 20 == 0)); then - printf "\n" + printf "\n" fi let counter=$counter+1 done print for i in $names; do - if [[ "$group" == "flags" ]]; then + if [[ "$group" == "flags" ]]; then echo "${emoji_flags[$i]} = $i" - else + else echo "${emoji[$i]} = $i" fi done diff --git a/zsh/plugins/emoji/update_emoji.py b/zsh/plugins/emoji/update_emoji.py index 18b3c06..9e115a7 100644 --- a/zsh/plugins/emoji/update_emoji.py +++ b/zsh/plugins/emoji/update_emoji.py @@ -1,6 +1,6 @@ """ Update Emoji.py -Refeshes OMZ emoji database based on the latest Unicode spec +Refreshes OMZ emoji database based on the latest Unicode spec """ import re import json @@ -95,7 +95,7 @@ def name_to_omz(_name, _group, _subgroup, _status): shortname = snake_case(_name) # Special treatment by status # Enables us to have every emoji combination, - # even the one that are not officially sanctionned + # even the one that are not officially sanctioned # and are implemented by, say, only one vendor if _status == "unqualified": shortname += "_unqualified" diff --git a/zsh/plugins/emotty/emotty.plugin.zsh b/zsh/plugins/emotty/emotty.plugin.zsh index 661169a..b48d121 100644 --- a/zsh/plugins/emotty/emotty.plugin.zsh +++ b/zsh/plugins/emotty/emotty.plugin.zsh @@ -4,7 +4,7 @@ # AUTHOR: Alexis Hildebrandt (afh[at]surryhill.net) # VERSION: 1.0.0 # DEPENDS: emoji plugin -# +# # There are different sets of emoji characters available, to choose a different # set export emotty_set to the name of the set you would like to use, e.g.: # % export emotty_set=nature diff --git a/zsh/plugins/encode64/README.md b/zsh/plugins/encode64/README.md index 86320cf..e3e25a7 100644 --- a/zsh/plugins/encode64/README.md +++ b/zsh/plugins/encode64/README.md @@ -10,10 +10,11 @@ plugins=(... encode64) ## Functions and Aliases -| Function | Alias | Description | -| ---------- | ----- | ------------------------------ | -| `encode64` | `e64` | Encodes given data to base64 | -| `decode64` | `d64` | Decodes given data from base64 | +| Function | Alias | Description | +| -------------- | ------ | -------------------------------------- | +| `encode64` | `e64` | Encodes given data to base64 | +| `encodefile64` | `ef64` | Encodes given file's content to base64 | +| `decode64` | `d64` | Decodes given data from base64 | ## Usage and examples @@ -37,6 +38,20 @@ plugins=(... encode64) b2gtbXktenNo== ``` +### Encoding a file + +Encode a file's contents to base64 and save output to text file. +**NOTE:** Takes provided file and saves encoded content as new file with `.txt` extension + +- From parameter + + ```console + $ encodefile64 ohmyzsh.icn + ohmyzsh.icn's content encoded in base64 and saved as ohmyzsh.icn.txt + $ ef64 "oh-my-zsh" + ohmyzsh.icn's content encoded in base64 and saved as ohmyzsh.icn.txt + ``` + ### Decoding - From parameter diff --git a/zsh/plugins/encode64/encode64.plugin.zsh b/zsh/plugins/encode64/encode64.plugin.zsh index 979e067..8e6fdb1 100644 --- a/zsh/plugins/encode64/encode64.plugin.zsh +++ b/zsh/plugins/encode64/encode64.plugin.zsh @@ -6,6 +6,15 @@ encode64() { fi } +encodefile64() { + if [[ $# -eq 0 ]]; then + echo "You must provide a filename" + else + base64 $1 > $1.txt + echo "${1}'s content encoded in base64 and saved as ${1}.txt" + fi +} + decode64() { if [[ $# -eq 0 ]]; then cat | base64 --decode @@ -14,4 +23,5 @@ decode64() { fi } alias e64=encode64 +alias ef64=encodefile64 alias d64=decode64 diff --git a/zsh/plugins/extract/README.md b/zsh/plugins/extract/README.md index 44f0b05..7bedfb1 100644 --- a/zsh/plugins/extract/README.md +++ b/zsh/plugins/extract/README.md @@ -1,10 +1,10 @@ # extract plugin -This plugin defines a function called `extract` that extracts the archive file -you pass it, and it supports a wide variety of archive filetypes. +This plugin defines a function called `extract` that extracts the archive file you pass it, and it supports a +wide variety of archive filetypes. -This way you don't have to know what specific command extracts a file, you just -do `extract ` and the function takes care of the rest. +This way you don't have to know what specific command extracts a file, you just do `extract ` and +the function takes care of the rest. To use it, add `extract` to the plugins array in your zshrc file: @@ -14,47 +14,56 @@ plugins=(... extract) ## Supported file extensions -| Extension | Description | -|:------------------|:-------------------------------------| -| `7z` | 7zip file | -| `Z` | Z archive (LZW) | -| `apk` | Android app file | -| `aar` | Android library file | -| `bz2` | Bzip2 file | -| `cab` | Microsoft cabinet archive | -| `cpio` | Cpio archive | -| `deb` | Debian package | -| `ear` | Enterprise Application aRchive | -| `gz` | Gzip file | -| `ipa` | iOS app package | -| `ipsw` | iOS firmware file | -| `jar` | Java Archive | -| `lrz` | LRZ archive | -| `lz4` | LZ4 archive | -| `lzma` | LZMA archive | -| `rar` | WinRAR archive | -| `rpm` | RPM package | -| `sublime-package` | Sublime Text package | -| `tar` | Tarball | -| `tar.bz2` | Tarball with bzip2 compression | -| `tar.gz` | Tarball with gzip compression | -| `tar.lrz` | Tarball with lrzip compression | -| `tar.lz` | Tarball with lzip compression | -| `tar.lz4` | Tarball with lz4 compression | -| `tar.xz` | Tarball with lzma2 compression | -| `tar.zma` | Tarball with lzma compression | -| `tar.zst` | Tarball with zstd compression | -| `tbz` | Tarball with bzip compression | -| `tbz2` | Tarball with bzip2 compression | -| `tgz` | Tarball with gzip compression | -| `tlz` | Tarball with lzma compression | -| `txz` | Tarball with lzma2 compression | -| `tzst` | Tarball with zstd compression | -| `war` | Web Application archive (Java-based) | -| `xpi` | Mozilla XPI module file | -| `xz` | LZMA2 archive | -| `zip` | Zip archive | -| `zst` | Zstandard file (zstd) | +| Extension | Description | +| :---------------- | :-------------------------------------- | +| `7z` | 7zip file | +| `apk` | Android app file | +| `aar` | Android library file | +| `bz2` | Bzip2 file | +| `cab` | Microsoft cabinet archive | +| `cpio` | Cpio archive | +| `deb` | Debian package | +| `ear` | Enterprise Application aRchive | +| `exe` | Windows executable file | +| `gz` | Gzip file | +| `ipa` | iOS app package | +| `ipsw` | iOS firmware file | +| `jar` | Java Archive | +| `lrz` | LRZ archive | +| `lz4` | LZ4 archive | +| `lzma` | LZMA archive | +| `obscpio` | cpio archive used on OBS | +| `pk3` | Renamed Zip archive used by Quake games | +| `pk4` | Renamed Zip archive used by Quake games | +| `pk7` | Renamed 7zip file used by Quake games | +| `rar` | WinRAR archive | +| `rpm` | RPM package | +| `sublime-package` | Sublime Text package | +| `tar` | Tarball | +| `tar.bz2` | Tarball with bzip2 compression | +| `tar.gz` | Tarball with gzip compression | +| `tar.lrz` | Tarball with lrzip compression | +| `tar.lz` | Tarball with lzip compression | +| `tar.lz4` | Tarball with lz4 compression | +| `tar.xz` | Tarball with lzma2 compression | +| `tar.zma` | Tarball with lzma compression | +| `tar.zst` | Tarball with zstd compression | +| `tbz` | Tarball with bzip compression | +| `tbz2` | Tarball with bzip2 compression | +| `tgz` | Tarball with gzip compression | +| `tlz` | Tarball with lzma compression | +| `txz` | Tarball with lzma2 compression | +| `tzst` | Tarball with zstd compression | +| `vsix` | VS Code extension zip file | +| `war` | Web Application archive (Java-based) | +| `whl` | Python wheel file | +| `xpi` | Mozilla XPI module file | +| `xz` | LZMA2 archive | +| `Z` | Z archive (LZW) | +| `zip` | Zip archive | +| `zlib` | zlib archive | +| `zst` | Zstandard file (zstd) | +| `zpaq` | Zpaq file | -See [list of archive formats](https://en.wikipedia.org/wiki/List_of_archive_formats) for -more information regarding archive formats. +See [list of archive formats](https://en.wikipedia.org/wiki/List_of_archive_formats) for more information +regarding archive formats. diff --git a/zsh/plugins/extract/_extract b/zsh/plugins/extract/_extract index 27b099c..6641443 100644 --- a/zsh/plugins/extract/_extract +++ b/zsh/plugins/extract/_extract @@ -1,7 +1,57 @@ #compdef extract #autoload +local -a exts=( + 7z + aar + apk + bz2 + cab + cpio + crx + deb + ear + gz + ipa + ipsw + jar + lrz + lz4 + lzma + obscpio + pk3 + pk4 + pk7 + rar + rpm + sublime-package + tar + tar.bz2 + tar.gz + tar.lrz + tar.lz + tar.lz4 + tar.xz + tar.zma + tar.zst + tbz + tbz2 + tgz + tlz + txz + tzst + vsix + war + whl + xpi + xz + Z + zip + zpaq + zst +) + _arguments \ '(-r --remove)'{-r,--remove}'[Remove archive.]' \ - "*::archive file:_files -g '(#i)*.(7z|Z|apk|aar|bz2|cab|cpio|deb|ear|gz|ipa|ipsw|jar|lrz|lz4|lzma|rar|rpm|sublime-package|tar|tar.bz2|tar.gz|tar.lrz|tar.lz|tar.lz4|tar.xz|tar.zma|tar.zst|tbz|tbz2|tgz|tlz|txz|tzst|war|whl|xpi|xz|zip|zst)(-.)'" \ + "*::archive file:_files -g '(#i)*.(${(j:|:)exts})(-.)'" \ && return 0 diff --git a/zsh/plugins/extract/extract.plugin.zsh b/zsh/plugins/extract/extract.plugin.zsh index 1112dd5..aed77e7 100644 --- a/zsh/plugins/extract/extract.plugin.zsh +++ b/zsh/plugins/extract/extract.plugin.zsh @@ -27,59 +27,119 @@ EOF fi local success=0 - local extract_dir="${1:t:r}" local file="$1" full_path="${1:A}" + local extract_dir="${1:t:r}" + + # Remove the .tar extension if the file name is .tar.* + if [[ $extract_dir =~ '\.tar$' ]]; then + extract_dir="${extract_dir:r}" + fi + + # If there's a file or directory with the same name as the archive + # add a random string to the end of the extract directory + if [[ -e "$extract_dir" ]]; then + local rnd="${(L)"${$(( [##36]$RANDOM*$RANDOM ))}":1:5}" + extract_dir="${extract_dir}-${rnd}" + fi + + # Create an extraction directory based on the file name + command mkdir -p "$extract_dir" + builtin cd -q "$extract_dir" + echo "extract: extracting to $extract_dir" >&2 + case "${file:l}" in - (*.tar.gz|*.tgz) (( $+commands[pigz] )) && { pigz -dc "$file" | tar xv } || tar zxvf "$file" ;; - (*.tar.bz2|*.tbz|*.tbz2) tar xvjf "$file" ;; + (*.tar.gz|*.tgz) + (( $+commands[pigz] )) && { tar -I pigz -xvf "$full_path" } || tar zxvf "$full_path" ;; + (*.tar.bz2|*.tbz|*.tbz2) + (( $+commands[pbzip2] )) && { tar -I pbzip2 -xvf "$full_path" } || tar xvjf "$full_path" ;; (*.tar.xz|*.txz) + (( $+commands[pixz] )) && { tar -I pixz -xvf "$full_path" } || { tar --xz --help &> /dev/null \ - && tar --xz -xvf "$file" \ - || xzcat "$file" | tar xvf - ;; + && tar --xz -xvf "$full_path" \ + || xzcat "$full_path" | tar xvf - } ;; (*.tar.zma|*.tlz) tar --lzma --help &> /dev/null \ - && tar --lzma -xvf "$file" \ - || lzcat "$file" | tar xvf - ;; + && tar --lzma -xvf "$full_path" \ + || lzcat "$full_path" | tar xvf - ;; (*.tar.zst|*.tzst) tar --zstd --help &> /dev/null \ - && tar --zstd -xvf "$file" \ - || zstdcat "$file" | tar xvf - ;; - (*.tar) tar xvf "$file" ;; - (*.tar.lz) (( $+commands[lzip] )) && tar xvf "$file" ;; - (*.tar.lz4) lz4 -c -d "$file" | tar xvf - ;; - (*.tar.lrz) (( $+commands[lrzuntar] )) && lrzuntar "$file" ;; - (*.gz) (( $+commands[pigz] )) && pigz -dk "$file" || gunzip -k "$file" ;; - (*.bz2) bunzip2 "$file" ;; - (*.xz) unxz "$file" ;; - (*.lrz) (( $+commands[lrunzip] )) && lrunzip "$file" ;; - (*.lz4) lz4 -d "$file" ;; - (*.lzma) unlzma "$file" ;; - (*.z) uncompress "$file" ;; - (*.zip|*.war|*.jar|*.ear|*.sublime-package|*.ipa|*.ipsw|*.xpi|*.apk|*.aar|*.whl) unzip "$file" -d "$extract_dir" ;; - (*.rar) unrar x -ad "$file" ;; + && tar --zstd -xvf "$full_path" \ + || zstdcat "$full_path" | tar xvf - ;; + (*.tar) tar xvf "$full_path" ;; + (*.tar.lz) (( $+commands[lzip] )) && tar xvf "$full_path" ;; + (*.tar.lz4) lz4 -c -d "$full_path" | tar xvf - ;; + (*.tar.lrz) (( $+commands[lrzuntar] )) && lrzuntar "$full_path" ;; + (*.gz) (( $+commands[pigz] )) && pigz -cdk "$full_path" > "${file:t:r}" || gunzip -ck "$full_path" > "${file:t:r}" ;; + (*.bz2) (( $+commands[pbzip2] )) && pbzip2 -d "$full_path" || bunzip2 "$full_path" ;; + (*.xz) unxz "$full_path" ;; + (*.lrz) (( $+commands[lrunzip] )) && lrunzip "$full_path" ;; + (*.lz4) lz4 -d "$full_path" ;; + (*.lzma) unlzma "$full_path" ;; + (*.z) uncompress "$full_path" ;; + (*.zip|*.war|*.jar|*.ear|*.sublime-package|*.ipa|*.ipsw|*.xpi|*.apk|*.aar|*.whl|*.vsix|*.crx|*.pk3|*.pk4) unzip "$full_path" ;; + (*.rar) + if (( $+commands[unrar] )); then + unrar x -ad "$full_path" + elif (( $+commands[unar] )); then + unar -o . "$full_path" + else + echo "extract: cannot extract RAR files: install unrar or unar" >&2 + success=1 + fi ;; (*.rpm) - command mkdir -p "$extract_dir" && builtin cd -q "$extract_dir" \ - && rpm2cpio "$full_path" | cpio --quiet -id ;; - (*.7z) 7za x "$file" ;; + rpm2cpio "$full_path" | cpio --quiet -id ;; + (*.7z | *.7z.[0-9]* | *.pk7) 7za x "$full_path" ;; (*.deb) - command mkdir -p "$extract_dir/control" "$extract_dir/data" - builtin cd -q "$extract_dir"; ar vx "$full_path" > /dev/null + command mkdir -p "control" "data" + ar vx "$full_path" > /dev/null builtin cd -q control; extract ../control.tar.* builtin cd -q ../data; extract ../data.tar.* builtin cd -q ..; command rm *.tar.* debian-binary ;; - (*.zst) unzstd "$file" ;; - (*.cab) cabextract -d "$extract_dir" "$file" ;; - (*.cpio) cpio -idmvF "$file" ;; + (*.zst) unzstd --stdout "$full_path" > "${file:t:r}" ;; + (*.cab|*.exe) cabextract "$full_path" ;; + (*.cpio|*.obscpio) cpio -idmvF "$full_path" ;; + (*.zpaq) zpaq x "$full_path" ;; + (*.zlib) zlib-flate -uncompress < "$full_path" > "${file:r}" ;; (*) echo "extract: '$file' cannot be extracted" >&2 success=1 ;; esac (( success = success > 0 ? success : $? )) - (( success == 0 && remove_archive == 0 )) && rm "$full_path" + (( success == 0 && remove_archive == 0 )) && command rm "$full_path" shift - # Go back to original working directory in case we ran cd previously + # Go back to original working directory builtin cd -q "$pwd" + + # If content of extract dir is a single directory, move its contents up + # Glob flags: + # - D: include files starting with . + # - N: no error if directory is empty + # - Y2: at most give 2 files + local -a content + content=("${extract_dir}"/*(DNY2)) + if [[ ${#content} -eq 1 && -e "${content[1]}" ]]; then + # The extracted file/folder (${content[1]}) may have the same name as $extract_dir + # If so, we need to rename it to avoid conflicts in a 3-step process + # + # 1. Move and rename the extracted file/folder to a temporary random name + # 2. Delete the empty folder + # 3. Rename the extracted file/folder to the original name + if [[ "${content[1]:t}" == "$extract_dir" ]]; then + # =(:) gives /tmp/zsh, with :t it gives zsh + local tmp_name==(:); tmp_name="${tmp_name:t}" + command mv "${content[1]}" "$tmp_name" \ + && command rmdir "$extract_dir" \ + && command mv "$tmp_name" "$extract_dir" + # Otherwise, if the extracted folder name already exists in the current + # directory (because of a previous file / folder), keep the extract_dir + elif [[ ! -e "${content[1]:t}" ]]; then + command mv "${content[1]}" . \ + && command rmdir "$extract_dir" + fi + elif [[ ${#content} -eq 0 ]]; then + command rmdir "$extract_dir" + fi done } diff --git a/zsh/plugins/eza/README.md b/zsh/plugins/eza/README.md new file mode 100644 index 0000000..bec1f85 --- /dev/null +++ b/zsh/plugins/eza/README.md @@ -0,0 +1,144 @@ +# eza plugin + +This provides aliases that invoke the [`eza`](https://github.com/eza-community/eza) utility rather than `ls` + +To use it add `eza` to the plugins array in your zshrc file: + +```zsh +plugins=(... eza) +``` + +## Configuration + +All configurations are done using the `zstyle` command in the `:omz:plugins:eza` namespace. + +**NOTE:** The configuring needs to be done prior to OMZ loading the plugins. When the plugin is loaded, +changing the `zstyle` won't have any effect. + +### `dirs-first` + +```zsh +zstyle ':omz:plugins:eza' 'dirs-first' yes|no +``` + +If `yes`, directories will be grouped first. + +Default: `no` + +### `git-status` + +```zsh +zstyle ':omz:plugins:eza' 'git-status' yes|no +``` + +If `yes`, always add `--git` flag to indicate git status (if tracked / in a git repo). + +Default: `no` + +### `header` + +```zsh +zstyle ':omz:plugins:eza' 'header' yes|no +``` + +If `yes`, always add `-h` flag to add a header row for each column. + +Default: `no` + +### `show-group` + +```zsh +zstyle ':omz:plugins:eza' 'show-group' yes|no +``` + +If `yes` (default), always add `-g` flag to show the group ownership. + +Default: `yes` + +### `icons` + +```zsh +zstyle ':omz:plugins:eza' 'icons' yes|no +``` + +If `yes`, sets the `--icons` option of `eza`, adding icons for files and folders. + +Default: `no` + +### `color-scale` + +```zsh +zstyle ':omz:plugins:eza' 'color-scale' all|age|size +``` + +Highlight levels of field(s) distinctly. Use comma(,) separated list of `all`, `age`, `size` + +Default: `none` + +### `color-scale-mode` + +```zsh +zstyle ':omz:plugins:eza' 'color-scale-mode' gradient|fixed +``` + +Choose the mode for highlighting: + +- `gradient` (default) -- gradient coloring +- `fixed` -- fixed coloring + +Default: `gradient` + +### `size-prefix` + +```zsh +zstyle ':omz:plugins:eza' 'size-prefix' (binary|none|si) +``` + +Choose the prefix to be used in displaying file size: + +- `binary` -- use [binary prefixes](https://en.wikipedia.org/wiki/Binary_prefix) such as "Ki", "Mi", "Gi" and + so on +- `none` -- don't use any prefix, show size in bytes +- `si` (default) -- use [Metric/S.I. prefixes](https://en.wikipedia.org/wiki/Metric_prefix) + +Default: `si` + +### `time-style` + +```zsh +zstyle ':omz:plugins:eza' 'time-style' $TIME_STYLE +``` + +Sets the `--time-style` option of `eza`. (See `man eza` for the options) + +Default: Not set, which means the default behavior of `eza` will take place. + +### `hyperlink` + +```zsh +zstyle ':omz:plugins:eza' 'hyperlink' yes|no +``` + +If `yes`, always add `--hyperlink` flag to create hyperlink with escape codes. + +Default: `no` + +## Aliases + +**Notes:** + +- Aliases may be modified by Configuration +- The term "files" without "only" qualifier means both files & directories + +| Alias | Command | Description | +| ------ | ----------------- | -------------------------------------------------------------------------- | +| `la` | `eza -la` | List all files (except . and ..) as a long list | +| `ldot` | `eza -ld .*` | List dotfiles only (directories shown as entries instead of recursed into) | +| `lD` | `eza -lD` | List only directories (excluding dotdirs) as a long list | +| `lDD` | `eza -laD` | List only directories (including dotdirs) as a long list | +| `ll` | `eza -l` | List files as a long list | +| `ls` | `eza` | Plain eza call | +| `lsd` | `eza -d` | List specified files with directories as entries, in a grid | +| `lsdl` | `eza -dl` | List specified files with directories as entries, in a long list | +| `lS` | `eza -l -ssize` | List files as a long list, sorted by size | +| `lT` | `eza -l -snewest` | List files as a long list, sorted by date (newest last) | diff --git a/zsh/plugins/eza/eza.plugin.zsh b/zsh/plugins/eza/eza.plugin.zsh new file mode 100644 index 0000000..60ed1eb --- /dev/null +++ b/zsh/plugins/eza/eza.plugin.zsh @@ -0,0 +1,76 @@ +if ! (( $+commands[eza] )); then + print "zsh eza plugin: eza not found. Please install eza before using this plugin." >&2 + return 1 +fi + +typeset -a _EZA_HEAD +typeset -a _EZA_TAIL + +function _configure_eza() { + local _val + # Get the head flags + if zstyle -T ':omz:plugins:eza' 'show-group'; then + _EZA_HEAD+=("g") + fi + if zstyle -t ':omz:plugins:eza' 'header'; then + _EZA_HEAD+=("h") + fi + zstyle -s ':omz:plugins:eza' 'size-prefix' _val + case "${_val:l}" in + binary) + _EZA_HEAD+=("b") + ;; + none) + _EZA_HEAD+=("B") + ;; + esac + # Get the tail long-options + if zstyle -t ':omz:plugins:eza' 'dirs-first'; then + _EZA_TAIL+=("--group-directories-first") + fi + if zstyle -t ':omz:plugins:eza' 'git-status'; then + _EZA_TAIL+=("--git") + fi + if zstyle -t ':omz:plugins:eza' 'icons'; then + _EZA_TAIL+=("--icons=auto") + fi + zstyle -s ':omz:plugins:eza' 'color-scale' _val + if [[ $_val ]]; then + _EZA_TAIL+=("--color-scale=$_val") + fi + zstyle -s ':omz:plugins:eza' 'color-scale-mode' _val + if [[ $_val == (gradient|fixed) ]]; then + _EZA_TAIL+=("--color-scale-mode=$_val") + fi + zstyle -s ':omz:plugins:eza' 'time-style' _val + if [[ $_val ]]; then + _EZA_TAIL+=("--time-style='$_val'") + fi + if zstyle -t ":omz:plugins:eza" "hyperlink"; then + _EZA_TAIL+=("--hyperlink") + fi +} + +_configure_eza + +function _alias_eza() { + local _head="${(j::)_EZA_HEAD}$2" + local _tail="${(j: :)_EZA_TAIL}" + alias "$1"="eza${_head:+ -}${_head}${_tail:+ }${_tail}${3:+ }$3" +} + +_alias_eza la la +_alias_eza ldot ld ".*" +_alias_eza lD lD +_alias_eza lDD lDa +_alias_eza ll l +_alias_eza ls +_alias_eza lsd d +_alias_eza lsdl dl +_alias_eza lS "l -ssize" +_alias_eza lT "l -snewest" + +unfunction _alias_eza +unfunction _configure_eza +unset _EZA_HEAD +unset _EZA_TAIL diff --git a/zsh/plugins/fancy-ctrl-z/README.md b/zsh/plugins/fancy-ctrl-z/README.md index f1b1dfa..7766c51 100644 --- a/zsh/plugins/fancy-ctrl-z/README.md +++ b/zsh/plugins/fancy-ctrl-z/README.md @@ -1,14 +1,24 @@ -# Use Ctrl-Z to switch back to Vim +# fancy-ctrl-z -I frequently need to execute random commands in my shell. To achieve it I pause +Allows pressing Ctrl-Z again to switch back to a background job. + +To use it, add `fancy-ctrl-z` to the plugins array in your zshrc file: + +```zsh +plugins=(... fancy-ctrl-z) +``` + +## Motivation + +I frequently need to execute random commands in my shell. To achieve it I pause Vim by pressing Ctrl-z, type command and press fg to switch back to Vim. -The fg part really hurts me. I just wanted to hit Ctrl-z once again to get back -to Vim. I could not find a solution, so I developed one on my own that +The fg part really hurts me. I just wanted to hit Ctrl-z once again to get back +to Vim. I could not find a solution, so I developed one on my own that works wonderfully with ZSH. Source: http://sheerun.net/2014/03/21/how-to-boost-your-vim-productivity/ -Credits: +Credits: - original idea by @sheerun - added to OMZ by @mbologna diff --git a/zsh/plugins/fasd/README.md b/zsh/plugins/fasd/README.md index a5c74e5..7c44ac8 100644 --- a/zsh/plugins/fasd/README.md +++ b/zsh/plugins/fasd/README.md @@ -10,7 +10,7 @@ plugins=(... fasd) ## Installation -Please find detailed installation guide [`here`](https://github.com/clvv/fasd#install) +Please find detailed installation guide [`here`](https://github.com/whjvenyl/fasd#install) ## Aliases diff --git a/zsh/plugins/fastfile/README.md b/zsh/plugins/fastfile/README.md index 32f619f..7291fde 100644 --- a/zsh/plugins/fastfile/README.md +++ b/zsh/plugins/fastfile/README.md @@ -71,13 +71,13 @@ them, add `=` to your zshrc file, before Oh My Zsh is sourced. For example: `fastfile_var_prefix='@'`. - `fastfile_var_prefix`: prefix for the global aliases created. Controls the prefix of the - created global aliases. + created global aliases. **Default:** `§` (section sign), easy to type in a german keyboard via the combination [`⇧ Shift`+`3`](https://en.wikipedia.org/wiki/German_keyboard_layout#/media/File:KB_Germany.svg), or using `⌥ Option`+`6` in macOS. - `fastfile_dir`: directory where the fastfile shortcuts are stored. Needs to end - with a trailing slash. + with a trailing slash. **Default:** `$HOME/.fastfile/`. ## Author diff --git a/zsh/plugins/fastfile/fastfile.plugin.zsh b/zsh/plugins/fastfile/fastfile.plugin.zsh index 896fed5..86f224b 100644 --- a/zsh/plugins/fastfile/fastfile.plugin.zsh +++ b/zsh/plugins/fastfile/fastfile.plugin.zsh @@ -5,8 +5,8 @@ # If they are not set yet, they will be # overwritten with their default values -default fastfile_dir "${HOME}/.fastfile" -default fastfile_var_prefix "§" +fastfile_dir="${fastfile_dir:-${HOME}/.fastfile}" +fastfile_var_prefix="${fastfile_var_prefix:-§}" ########################### # Impl diff --git a/zsh/plugins/fd/README.md b/zsh/plugins/fd/README.md deleted file mode 100644 index f334161..0000000 --- a/zsh/plugins/fd/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# fd - -This plugin adds completion for the file search tool [`fd`](https://github.com/sharkdp/fd), also known as `fd-find`. - -To use it, add `fd` to the plugins array in your zshrc file: - -```zsh -plugins=(... fd) -``` diff --git a/zsh/plugins/fd/_fd b/zsh/plugins/fd/_fd deleted file mode 100644 index 45b8ca4..0000000 --- a/zsh/plugins/fd/_fd +++ /dev/null @@ -1,273 +0,0 @@ -#compdef fd - -## -# zsh completion function for fd -# -# Based on ripgrep completion function. -# Originally based on code from the zsh-users project — see copyright notice -# below. - -autoload -U is-at-least - -_fd() { - local curcontext="$curcontext" no='!' ret=1 - local -a context line state state_descr _arguments_options fd_types fd_args - local -A opt_args - - if is-at-least 5.2; then - _arguments_options=( -s -S ) - else - _arguments_options=( -s ) - fi - - fd_types=( - {f,file}'\:"regular files"' - {d,directory}'\:"directories"' - {l,symlink}'\:"symbolic links"' - {e,empty}'\:"empty files or directories"' - {x,executable}'\:"executable (files)"' - {s,socket}'\:"sockets"' - {p,pipe}'\:"named pipes (FIFOs)"' - ) - - # Do not complete rare options unless either the current prefix - # matches one of those options or the user has the `complete-all` - # style set. Note that this prefix check has to be updated manually to account - # for all of the potential negation options listed below! - if - # (--[bpsu]* => match all options marked with '$no') - [[ $PREFIX$SUFFIX == --[bopsu]* ]] || - zstyle -t ":complete:$curcontext:*" complete-all - then - no= - fi - - # We make heavy use of argument groups here to prevent the option specs from - # growing unwieldy. These aren't supported in zsh <5.4, though, so we'll strip - # them out below if necessary. This makes the exclusions inaccurate on those - # older versions, but oh well — it's not that big a deal - fd_args=( - + '(hidden)' # hidden files - {-H,--hidden}'[search hidden files/directories]' - - + '(no-ignore-full)' # all ignore files - '(no-ignore-partial)'{-I,--no-ignore}"[don't respect .(git|fd)ignore and global ignore files]" - $no'(no-ignore-partial)*'{-u,--unrestricted}'[alias for --no-ignore, when repeated also alias for --hidden]' - - + no-ignore-partial # some ignore files - "(no-ignore-full --no-ignore-vcs)--no-ignore-vcs[don't respect .gitignore files]" - "!(no-ignore-full --no-global-ignore-file)--no-global-ignore-file[don't respect the global ignore file]" - $no'(no-ignore-full --no-ignore-parent)--no-ignore-parent[]' - - + '(case)' # case-sensitivity - {-s,--case-sensitive}'[perform a case-sensitive search]' - {-i,--ignore-case}'[perform a case-insensitive search]' - - + '(regex-pattern)' # regex-based search pattern - '(no-regex-pattern)--regex[perform a regex-based search (default)]' - - + '(no-regex-pattern)' # non-regex-based search pattern - {-g,--glob}'[perform a glob-based search]' - {-F,--fixed-strings}'[treat pattern as literal string instead of a regex]' - - + '(match-full)' # match against full path - {-p,--full-path}'[match the pattern against the full path instead of the basename]' - - + '(follow)' # follow symlinks - {-L,--follow}'[follow symbolic links to directories]' - - + '(abs-path)' # show absolute paths - '(long-listing)'{-a,--absolute-path}'[show absolute paths instead of relative paths]' - - + '(null-sep)' # use null separator for output - '(long-listing)'{-0,--print0}'[separate search results by the null character]' - - + '(long-listing)' # long-listing output - '(abs-path null-sep max-results exec-cmds)'{-l,--list-details}'[use a long listing format with file metadata]' - - + '(max-results)' # max number of results - '(long-listing exec-cmds)--max-results=[limit number of search results to given count and quit]:count' - '(long-listing exec-cmds)-1[limit to a single search result and quit]' - - + '(fs-errors)' # file-system errors - $no'--show-errors[enable the display of filesystem errors]' - - + '(fs-traversal)' # file-system traversal - $no"--one-file-system[don't descend into directories on other file systems]" - '!--mount' - '!--xdev' - - + dir-depth # directory depth - '(--exact-depth -d --max-depth)'{-d+,--max-depth=}'[set max directory depth to descend when searching]:depth' - '!(--exact-depth -d --max-depth)--maxdepth:depth' - '(--exact-depth --min-depth)--min-depth=[set directory depth to descend before start searching]:depth' - '(--exact-depth -d --max-depth --maxdepth --min-depth)--exact-depth=[only search at the exact given directory depth]:depth' - - + prune # pruning - "--prune[don't traverse into matching directories]" - - + filter-misc # filter search - '*'{-t+,--type=}"[filter search by type]:type:(($fd_types))" - '*'{-e+,--extension=}'[filter search by file extension]:extension' - '*'{-E+,--exclude=}'[exclude files/directories that match the given glob pattern]:glob pattern' - '*'{-S+,--size=}'[limit search by file size]:size limit:->size' - '(-o --owner)'{-o+,--owner=}'[filter by owning user and/or group]:owner and/or group:->owner' - - + ignore-file # extra ignore files - '*--ignore-file=[add a custom, low-precedence ignore-file with .gitignore format]: :_files' - - + '(filter-mtime-newer)' # filter by files modified after than - '--changed-within=[limit search to files/directories modified within the given date/duration]:date or duration' - '!--change-newer-than=:date/duration' - '!--newer=:date/duration' - - + '(filter-mtime-older)' # filter by files modified before than - '--changed-before=[limit search to files/directories modified before the given date/duration]:date or duration' - '!--change-older-than=:date/duration' - '!--older=:date/duration' - - + '(color)' # colorize output - {-c+,--color=}'[declare when to colorize search results]:when to colorize:(( - auto\:"show colors if the output goes to an interactive console (default)" - never\:"do not use colorized output" - always\:"always use colorized output" - ))' - - + '(threads)' - {-j+,--threads=}'[set the number of threads for searching and executing]:number of threads' - - + '(exec-cmds)' # execute command - '(long-listing max-results)'{-x+,--exec=}'[execute command for each search result]:command: _command_names -e:*\;::program arguments: _normal' - '(long-listing max-results)'{-X+,--exec-batch=}'[execute command for all search results at once]:command: _command_names -e:*\;::program arguments: _normal' - '(long-listing max-results)--batch-size=[max number of args for each -X call]:size' - - + other - '!(--max-buffer-time)--max-buffer-time=[set amount of time to buffer before showing output]:time (ms)' - - + '(about)' # about flags - '(: * -)'{-h,--help}'[display help message]' - '(: * -)'{-v,--version}'[display version information]' - - + path-sep # set path separator for output - $no'(--path-separator)--path-separator=[set the path separator to use when printing file paths]:path separator' - - + search-path - $no'(--base-directory)--base-directory=[change the current working directory to the given path]:directory:_files -/' - $no'(*)*--search-path=[set search path (instead of positional arguments)]:directory:_files -/' - - + strip-cwd-prefix - $no'(strip-cwd-prefix exec-cmds)--strip-cwd-prefix[Strip ./ prefix when output is redirected]' - - + args # positional arguments - '1: :_guard "^-*" pattern' - '(--search-path)*:directory:_files -/' - ) - - # Strip out argument groups where unsupported (see above) - is-at-least 5.4 || - fd_args=( ${(@)args:#(#i)(+|[a-z0-9][a-z0-9_-]#|\([a-z0-9][a-z0-9_-]#\))} ) - - _arguments $_arguments_options : $fd_args && ret=0 - - case ${state} in - owner) - compset -P '(\\|)\!' - if compset -P '*:'; then - _groups && ret=0 - else - if - compset -S ':*' || - # Do not add the colon suffix when completing "!user - # (with a starting double-quote) otherwise pressing tab again - # after the inserted colon "!user: will complete history modifiers - [[ $IPREFIX == (\\|\!)* && ($QIPREFIX == \"* && -z $QISUFFIX) ]] - then - _users && ret=0 - else - local q - # Since quotes are needed when using the negation prefix !, - # automatically remove the colon suffix also when closing the quote - if [[ $QIPREFIX == [\'\"]* ]]; then - q=${QIPREFIX:0:1} - fi - _users -r ": \t\n\-$q" -S : && ret=0 - fi - fi - ;; - - size) - if compset -P '[-+][0-9]##'; then - local -a suff=( - 'B:bytes' - 'K:kilobytes (10^3 = 1000 bytes)' - 'M:megabytes (10^6 = 1000^2 bytes)' - 'G:gigabytes (10^9 = 1000^3 bytes)' - 'T:terabytes (10^12 = 1000^4 bytes)' - 'Ki:kibibytes ( 2^10 = 1024 bytes)' - 'Mi:mebibytes ( 2^20 = 1024^2 bytes)' - 'Gi:gigibytes ( 2^30 = 1024^3 bytes)' - 'Ti:tebibytes ( 2^40 = 1024^4 bytes)' - ) - _describe -t units 'size limit units' suff -V 'units' - elif compset -P '[-+]'; then - _message -e 'size limit number (full format: <+->)' - else - _values 'size limit prefix (full format: )' \ - '\+[file size must be greater or equal to]'\ - '-[file size must be less than or equal to]' && ret=0 - fi - ;; - esac - - return ret -} - -_fd "$@" - -# ------------------------------------------------------------------------------ -# Copyright (c) 2011 GitHub zsh-users - http://github.com/zsh-users -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of the zsh-users nor the -# names of its contributors may be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL ZSH-USERS BE LIABLE FOR ANY -# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ------------------------------------------------------------------------------ -# Description -# ----------- -# -# Completion script for fd -# -# ------------------------------------------------------------------------------ -# Authors -# ------- -# -# * smancill (https://github.com/smancill) -# -# ------------------------------------------------------------------------------ - -# Local Variables: -# mode: shell-script -# coding: utf-8-unix -# indent-tabs-mode: nil -# sh-indentation: 2 -# sh-basic-offset: 2 -# End: -# vim: ft=zsh sw=2 ts=2 et diff --git a/zsh/plugins/fig/README.md b/zsh/plugins/fig/README.md deleted file mode 100644 index 3861958..0000000 --- a/zsh/plugins/fig/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Fig plugin - -This plugin sets up completion for [Fig](https://fig.io/). - -To use it, add `fig` to the plugins array in your zshrc file: - -```zsh -plugins=(... fig) -``` diff --git a/zsh/plugins/fig/fig.plugin.zsh b/zsh/plugins/fig/fig.plugin.zsh deleted file mode 100644 index cddb6c7..0000000 --- a/zsh/plugins/fig/fig.plugin.zsh +++ /dev/null @@ -1,13 +0,0 @@ -if ! (( $+commands[fig] )); then - return -fi - -# If the completion file doesn't exist yet, we need to autoload it and -# bind it to `fig`. Otherwise, compinit will have already done that -if [[ ! -f "$ZSH_CACHE_DIR/completions/_fig" ]]; then - autoload -Uz _fig - typeset -g -A _comps - _comps[fig]=_fig -fi - -fig completion zsh >| "$ZSH_CACHE_DIR/completions/_fig" &| diff --git a/zsh/plugins/firewalld/firewalld.plugin.zsh b/zsh/plugins/firewalld/firewalld.plugin.zsh index 5b10906..b2c0f64 100644 --- a/zsh/plugins/firewalld/firewalld.plugin.zsh +++ b/zsh/plugins/firewalld/firewalld.plugin.zsh @@ -9,7 +9,7 @@ function fwl () { zones=("${(@f)$(sudo firewall-cmd --get-active-zones | grep -v 'interfaces\|sources')}") for i in $zones; do - sudo firewall-cmd --zone $i --list-all + sudo firewall-cmd --zone ${i/ \(default\)} --list-all done echo 'Direct Rules:' diff --git a/zsh/plugins/flutter/_flutter b/zsh/plugins/flutter/_flutter deleted file mode 100644 index ab6ce42..0000000 --- a/zsh/plugins/flutter/_flutter +++ /dev/null @@ -1,37 +0,0 @@ -#compdef flutter -#autoload - -local -a _1st_arguments -_1st_arguments=( - "analyze":"Analyze the project's Dart code." - "assemble":"Assemble and build flutter resources." - "attach":"Attach to a running application." - "build":"Flutter build commands." - "channel":"List or switch flutter channels." - "clean":"Delete the build/ and .dart_tool/ directories." - "config":"Configure Flutter settings." - "create":"Create a new Flutter project." - "devices":"List all connected devices." - "doctor":"Show information about the installed tooling." - "drive":"Runs Flutter Driver tests for the current project." - "emulators":"List, launch and create emulators." - "format":" Format one or more dart files." - "help":"Display help information for flutter." - "install":"Install a Flutter app on an attached device." - "logs":"Show log output for running Flutter apps." - "make-host-app-editable":"Moves host apps from generated directories to non-generated directories so that they can be edited by developers." - "precache":"Populates the Flutter tool's cache of binary artifacts." - "pub":"Commands for managing Flutter packages." - "run":"Run your Flutter app on an attached device." - "screenshot":"Take a screenshot from a connected device." - "test":"Run Flutter unit tests for the current project." - "upgrade":"Upgrade your copy of Flutter." - "version":"List or switch flutter versions." -) - -_arguments -C '*:: :->subcmds' - -if (( CURRENT == 1 )); then - _describe -t commands "flutter command" _1st_arguments - return -fi diff --git a/zsh/plugins/flutter/flutter.plugin.zsh b/zsh/plugins/flutter/flutter.plugin.zsh index 44d196c..5e853b7 100644 --- a/zsh/plugins/flutter/flutter.plugin.zsh +++ b/zsh/plugins/flutter/flutter.plugin.zsh @@ -26,4 +26,4 @@ if [[ ! -f "$ZSH_CACHE_DIR/completions/_flutter" ]]; then _comps[flutter]=_flutter fi -flutter zsh-completion >| "$ZSH_CACHE_DIR/completions/_flutter" &| \ No newline at end of file +flutter zsh-completion < /dev/null >| "$ZSH_CACHE_DIR/completions/_flutter" &| \ No newline at end of file diff --git a/zsh/plugins/fluxcd/README.md b/zsh/plugins/fluxcd/README.md new file mode 100644 index 0000000..9723fcc --- /dev/null +++ b/zsh/plugins/fluxcd/README.md @@ -0,0 +1,9 @@ +# FluxCD plugin + +This plugin adds completion for [FluxCD](https://fluxcd.io), an open and extensible continuous delivery solution for Kubernetes. Powered by GitOps Toolkit. + +To use it, add `fluxcd` to the plugins array in your zshrc file: + +```zsh +plugins=(... fluxcd) +``` diff --git a/zsh/plugins/fluxcd/fluxcd.plugin.zsh b/zsh/plugins/fluxcd/fluxcd.plugin.zsh new file mode 100644 index 0000000..d30866a --- /dev/null +++ b/zsh/plugins/fluxcd/fluxcd.plugin.zsh @@ -0,0 +1,14 @@ +# Autocompletion for the FluxCD CLI (flux). +if (( ! $+commands[flux] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `flux`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_flux" ]]; then + typeset -g -A _comps + autoload -Uz _flux + _comps[flux]=_flux +fi + +flux completion zsh >| "$ZSH_CACHE_DIR/completions/_flux" &| diff --git a/zsh/plugins/foot/README.md b/zsh/plugins/foot/README.md new file mode 100644 index 0000000..67777d9 --- /dev/null +++ b/zsh/plugins/foot/README.md @@ -0,0 +1,35 @@ +# foot + +This plugin adds shell integration for [foot, a fast, lightweight and +minimalistic Wayland terminal emulator](https://codeberg.org/dnkl/foot). + +To use, add `foot` to the list of plugins in your `.zshrc` file: + +```zsh +plugins=(... foot) +``` + +## Spawning new terminal instances in the current working directory + +When spawning a new terminal instance (with `ctrl+shift+n` by default), the new +instance will start in the current working directory. + +## Jumping between prompts + +Foot can move the current viewport to focus prompts of already executed +commands (bound to ctrl+shift+z/x by default). + +## Piping last command's output + +The key binding `pipe-command-output` can pipe the last command's output to an +application of your choice (similar to the other `pipe-*` key bindings): + +``` +[key-bindings] +pipe-command-output=[sh -c "f=$(mktemp); cat - > $f; footclient emacsclient -nw $f; rm $f"] Control+Shift+g +``` + +When pressing ctrl+shift+g, the last command's output is written to a +temporary file, then an emacsclient is started in a new footclient instance. +The temporary file is removed after the footclient instance has closed. + diff --git a/zsh/plugins/foot/foot.plugin.zsh b/zsh/plugins/foot/foot.plugin.zsh new file mode 100644 index 0000000..c1d077e --- /dev/null +++ b/zsh/plugins/foot/foot.plugin.zsh @@ -0,0 +1,10 @@ +function precmd { + print -Pn "\e]133;A\e\\" + if ! builtin zle; then + print -n "\e]133;D\e\\" + fi +} + +function preexec { + print -n "\e]133;C\e\\" +} diff --git a/zsh/plugins/forklift/forklift.plugin.zsh b/zsh/plugins/forklift/forklift.plugin.zsh index 8588948..4bc7495 100644 --- a/zsh/plugins/forklift/forklift.plugin.zsh +++ b/zsh/plugins/forklift/forklift.plugin.zsh @@ -2,6 +2,7 @@ # Author: Adam Strzelecki nanoant.com, modified by Bodo Tasche bitboxer.de # Updated to support ForkLift 2 and ForkLift 3 by Johan Kaving # Updated to support ForkLift from Setapp by Paul Rudkin +# Updated to support ForkLift 4 by Michal Szymanski (misiektoja) # # Usage: # fl [] @@ -58,7 +59,7 @@ function fl { tell application forkLiftSetapp activate set forkLiftVersion to version - end tell + end tell else if forkLift3 is not null and application forkLift3 is running then tell application forkLift3 activate @@ -84,7 +85,7 @@ function fl { else if forkLift is not null then set appName to forkLift end if - + tell application appName activate set forkLiftVersion to version @@ -110,6 +111,11 @@ function fl { tell pop over of list of group of splitter group of splitter group of topWindow set value of text field 1 to "$PWD" end tell + else if forkLiftVersion starts with "4" then + tell pop over of list of group of splitter group of splitter group of topWindow + keystroke "$PWD" + delay 0.1 + end tell else tell sheet 1 of topWindow set value of text field 1 to "$PWD" diff --git a/zsh/plugins/frontend-search/README.md b/zsh/plugins/frontend-search/README.md index 0500589..9207950 100644 --- a/zsh/plugins/frontend-search/README.md +++ b/zsh/plugins/frontend-search/README.md @@ -60,12 +60,22 @@ Available search contexts are: | typescript | `https://google.com/search?as_sitesearch=www.typescriptlang.org/docs&as_q=` | | unheap | `http://www.unheap.com/?s=` | | vuejs | `https://www.google.com/search?as_sitesearch=vuejs.org&as_q=` | +| nextjs | `https://www.google.com/search?as_sitesearch=nextjs.org&as_q=` | If you want to have another context, open an Issue and tell us! ## Fallback search behaviour -The plugin will use Google as a fallback if the docs site for a search context does not have a search function. You can set the fallback search engine to DuckDuckGo by setting `FRONTEND_SEARCH_FALLBACK='duckduckgo'` in your `~/.zshrc` file before Oh My Zsh is sourced. +The plugin will use Google as a fallback if the docs site for a search context does not have a search +function. You can set the fallback search engine to DuckDuckGo by setting +`FRONTEND_SEARCH_FALLBACK='duckduckgo'` in your `~/.zshrc` file before Oh My Zsh is sourced. + +## DuckDuckGo Lucky Search + +Enable DuckDuckGo's "ducky" (lucky) search feature to automatically access the top search result. This feature +is optimized for DuckDuckGo, as Google redirects to an intermediate page. The FRONTEND_SEARCH_FALLBACK_LUCKY +environment variable triggers the use of DuckDuckGo's lucky search, rendering the FRONTEND_SEARCH_FALLBACK +setting unnecessary in this context. ## Author diff --git a/zsh/plugins/frontend-search/_frontend b/zsh/plugins/frontend-search/_frontend index 15f8d23..aca4920 100644 --- a/zsh/plugins/frontend-search/_frontend +++ b/zsh/plugins/frontend-search/_frontend @@ -37,7 +37,7 @@ function _frontend() { 'lodash: Search in Lo-Dash website' 'mdn: Search in MDN website' 'nodejs: Search in NodeJS website' - 'npmjs: Search in NPMJS website' + 'npmjs: Search in npmjs website' 'packagephobia: Search in Packagephobia website' 'qunit: Search in Qunit website' 'reactjs: Search in React website' diff --git a/zsh/plugins/frontend-search/frontend-search.plugin.zsh b/zsh/plugins/frontend-search/frontend-search.plugin.zsh index b9e2fe9..c96596e 100644 --- a/zsh/plugins/frontend-search/frontend-search.plugin.zsh +++ b/zsh/plugins/frontend-search/frontend-search.plugin.zsh @@ -27,12 +27,19 @@ alias stackoverflow='frontend stackoverflow' alias typescript='frontend typescript' alias unheap='frontend unheap' alias vuejs='frontend vuejs' +alias nextjs='frontend nextjs' function _frontend_fallback() { - case "$FRONTEND_SEARCH_FALLBACK" in - duckduckgo) echo "https://duckduckgo.com/?sites=$1&q=" ;; - *) echo "https://google.com/search?as_sitesearch=$1&as_q=" ;; - esac + if [[ "$FRONTEND_SEARCH_FALLBACK_LUCKY" == "true" ]]; then + case true in + *) echo "https://duckduckgo.com/?q=!ducky+site%3A$1+" ;; + esac + else + case "$FRONTEND_SEARCH_FALLBACK" in + duckduckgo) echo "https://duckduckgo.com/?sites=$1&q=" ;; + *) echo "https://google.com/search?as_sitesearch=$1&as_q=" ;; + esac + fi } function frontend() { @@ -70,6 +77,7 @@ function frontend() { typescript $(_frontend_fallback 'www.typescriptlang.org/docs') unheap 'http://www.unheap.com/?s=' vuejs $(_frontend_fallback 'vuejs.org') + nextjs $(_frontend_fallback 'nextjs.org') ) # show help for command list @@ -81,7 +89,7 @@ function frontend() { print -P "" print -P " angular, angularjs, bem, bootsnipp, caniuse, codepen, compassdoc, cssflow, packagephobia" print -P " dartlang, emberjs, fontello, flowtype, github, html5please, jestjs, jquery, lodash," - print -P " mdn, npmjs, nodejs, qunit, reactjs, smacss, stackoverflow, unheap, vuejs, bundlephobia" + print -P " mdn, npmjs, nodejs, qunit, reactjs, smacss, stackoverflow, unheap, vuejs, bundlephobia, nextjs" print -P "" print -P "For example: frontend npmjs mocha (or just: npmjs mocha)." print -P "" @@ -96,7 +104,7 @@ function frontend() { echo "" echo " angular, angularjs, bem, bootsnipp, caniuse, codepen, compassdoc, cssflow, packagephobia" echo " dartlang, emberjs, fontello, github, html5please, jest, jquery, lodash," - echo " mdn, npmjs, nodejs, qunit, reactjs, smacss, stackoverflow, unheap, vuejs, bundlephobia" + echo " mdn, npmjs, nodejs, qunit, reactjs, smacss, stackoverflow, unheap, vuejs, bundlephobia, nextjs" echo "" return 1 fi diff --git a/zsh/plugins/fzf/fzf.plugin.zsh b/zsh/plugins/fzf/fzf.plugin.zsh index a946cf7..e244b4c 100644 --- a/zsh/plugins/fzf/fzf.plugin.zsh +++ b/zsh/plugins/fzf/fzf.plugin.zsh @@ -1,3 +1,16 @@ +function fzf_setup_using_fzf() { + (( ${+commands[fzf]} )) || return 1 + + # we remove "fzf " prefix, this fixes really old fzf versions behaviour + # see https://github.com/ohmyzsh/ohmyzsh/issues/12387 + local fzf_ver=${"$(fzf --version)"#fzf } + + autoload -Uz is-at-least + is-at-least 0.48.0 ${${(s: :)fzf_ver}[1]} || return 1 + + eval "$(fzf --zsh)" +} + function fzf_setup_using_base_dir() { local fzf_base fzf_shell fzfdirs dir @@ -8,7 +21,9 @@ function fzf_setup_using_base_dir() { "${HOME}/.fzf" "${HOME}/.nix-profile/share/fzf" "${XDG_DATA_HOME:-$HOME/.local/share}/fzf" + "${MSYSTEM_PREFIX}/share/fzf" "/usr/local/opt/fzf" + "/opt/homebrew/opt/fzf" "/usr/share/fzf" "/usr/local/share/examples/fzf" ) @@ -59,8 +74,8 @@ function fzf_setup_using_base_dir() { function fzf_setup_using_debian() { - if (( ! $+commands[dpkg] )) || ! dpkg -s fzf &>/dev/null; then - # Either not a debian based distro, or no fzf installed + if (( ! $+commands[apt] && ! $+commands[apt-get] )); then + # Not a debian based distro return 1 fi @@ -71,11 +86,19 @@ function fzf_setup_using_debian() { case $PREFIX in *com.termux*) + if [[ ! -f "${PREFIX}/bin/fzf" ]]; then + # fzf not installed + return 1 + fi # Support Termux package completions="${PREFIX}/share/fzf/completion.zsh" key_bindings="${PREFIX}/share/fzf/key-bindings.zsh" ;; *) + if [[ ! -d /usr/share/doc/fzf/examples ]]; then + # fzf not installed + return 1 + fi # Determine completion file path: first bullseye/sid, then buster/stretch completions="/usr/share/doc/fzf/examples/completion.zsh" [[ -f "$completions" ]] || completions="/usr/share/zsh/vendor-completions/_fzf" @@ -125,6 +148,27 @@ function fzf_setup_using_opensuse() { return 0 } +function fzf_setup_using_fedora() { + (( $+commands[fzf] )) || return 1 + + local completions="/usr/share/zsh/site-functions/fzf" + local key_bindings="/usr/share/fzf/shell/key-bindings.zsh" + + if [[ ! -f "$completions" || ! -f "$key_bindings" ]]; then + return 1 + fi + + if [[ -o interactive && "$DISABLE_FZF_AUTO_COMPLETION" != "true" ]]; then + source "$completions" 2>/dev/null + fi + + if [[ "$DISABLE_FZF_KEY_BINDINGS" != "true" ]]; then + source "$key_bindings" 2>/dev/null + fi + + return 0 +} + function fzf_setup_using_openbsd() { # openBSD installs fzf in /usr/local/bin/fzf if [[ "$OSTYPE" != openbsd* ]] || (( ! $+commands[fzf] )); then @@ -178,7 +222,7 @@ function fzf_setup_using_macports() { (( $+commands[fzf] )) || return 1 # The fzf-zsh-completion package installs the auto-completion in - local completions="/opt/local/share/zsh/site-functions/fzf" + local completions="/opt/local/share/fzf/shell/completion.zsh" # The fzf-zsh-completion package installs the key-bindings file in local key_bindings="/opt/local/share/fzf/shell/key-bindings.zsh" @@ -207,9 +251,11 @@ Please add `export FZF_BASE=/path/to/fzf/install/dir` to your .zshrc EOF } -fzf_setup_using_openbsd \ +fzf_setup_using_fzf \ + || fzf_setup_using_openbsd \ || fzf_setup_using_debian \ || fzf_setup_using_opensuse \ + || fzf_setup_using_fedora \ || fzf_setup_using_cygwin \ || fzf_setup_using_macports \ || fzf_setup_using_base_dir \ diff --git a/zsh/plugins/gas/README.md b/zsh/plugins/gas/README.md index 47b3fb9..a0a7a56 100644 --- a/zsh/plugins/gas/README.md +++ b/zsh/plugins/gas/README.md @@ -1,6 +1,6 @@ # Gas plugin -This plugin adds autocompletion for the [gas](http://walle.github.com/gas) command, +This plugin adds autocompletion for the [gas](http://ramblingsby.me/gas/) command, a utility to manage Git authors. To use it, add `gas` to the plugins array of your zshrc file: diff --git a/zsh/plugins/gatsby/README.md b/zsh/plugins/gatsby/README.md index 36846a2..cc1bd39 100644 --- a/zsh/plugins/gatsby/README.md +++ b/zsh/plugins/gatsby/README.md @@ -1,6 +1,6 @@ # gatsby autocomplete plugin -* Adds autocomplete options for all gatsby commands. +Adds autocomplete options for all gatsby commands. ## Requirements diff --git a/zsh/plugins/gb/README.md b/zsh/plugins/gb/README.md deleted file mode 100644 index 822c29a..0000000 --- a/zsh/plugins/gb/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# `gb` plugin - -> A project based build tool for the Go programming language. - -See https://getgb.io for the full `gb` documentation - -* * * * - -- Adds completion support for all `gb` commands. -- Also supports completion for the [`gb-vendor` plugin](https://godoc.org/github.com/constabulary/gb/cmd/gb-vendor). - -To use it, add `gb` to your plugins array: -```sh -plugins=(... gb) -``` - -## Caveats - -The `git` plugin defines an alias `gb` that usually conflicts with the `gb` program. -If you're having trouble with it, remove it by adding `unalias gb` at the end of your -zshrc file. diff --git a/zsh/plugins/gb/_gb b/zsh/plugins/gb/_gb deleted file mode 100644 index 8148adf..0000000 --- a/zsh/plugins/gb/_gb +++ /dev/null @@ -1,111 +0,0 @@ -#compdef gb -#autoload - -_gb () { - local ret=1 state - _arguments -C ':command:->command' '*::options:->options' && ret=0 - - case $state in - (command) - local -a subcommands - subcommands=( - "build:build a package" - "doc:show documentation for a package or symbol" - "env:print project environment variables" - "generate:generate Go files by processing source" - "help:displays the help" - "info:info returns information about this project" - "list:list the packages named by the importpaths" - "test:test packages" - "vendor:manage your vendored dependencies" - ) - _describe -t subcommands 'gb subcommands' subcommands && ret=0 - ;; - (options) - case $line[1] in - (build) - _arguments \ - -f'[ignore cached packages]' \ - -F'[do not cache packages]' \ - -q'[decreases verbosity]' \ - -P'[the number of build jobs to run in parallel]' \ - -R'[sets the base of the project root search path]' \ - -dotfile'[output a dot formatted file of the build steps]' \ - -ldflags'["flag list" arguments to pass to the linker]' \ - -gcflags'["arg list" arguments to pass to the compiler]' \ - -race'[enable data race detection]' \ - -tags'["tag list" additional build tags]' - ;; - (list) - _arguments \ - -f'[alternate format for the list, using the syntax of package template]' \ - -s'[read format template from STDIN]' \ - -json'[prints output in structured JSON format]' - ;; - (test) - _arguments \ - -v'[print output from test subprocess]' \ - -ldflags'["flag list" arguments to pass to the linker]' \ - -gcflags'["arg list" arguments to pass to the compiler]' \ - -race'[enable data race detection]' \ - -tags'["tag list" additional build tags]' - ;; - (vendor) - _gb-vendor - esac - ;; - esac - - return ret -} - -_gb-vendor () { - local curcontext="$curcontext" state line - _arguments -C ':command:->command' '*::options:->options' - - case $state in - (command) - local -a subcommands - subcommands=( - 'delete:deletes a local dependency' - 'fetch:fetch a remote dependency' - 'list:lists dependencies, one per line' - 'purge:remove all unreferenced dependencies' - 'restore:restore dependencies from the manifest' - 'update:update a local dependency' - ) - _describe -t subcommands 'gb vendor subcommands' subcommands && ret=0 - ;; - (options) - case $line[1] in - (delete) - _arguments \ - -all'[remove all dependencies]' - ;; - (fetch) - _arguments \ - -branch'[fetch from a particular branch]' \ - -no-recurse'[do not fetch recursively]' \ - -tag'[fetch the specified tag]' \ - -revision'[fetch the specific revision from the branch (if supplied)]' \ - -precaire'[allow the use of insecure protocols]' \ - ;; - (list) - _arguments \ - -f'[controls the template used for printing each manifest entry]' - ;; - (restore) - _arguments \ - -precaire'[allow the use of insecure protocols]' - ;; - (update) - _arguments \ - -all'[update all dependencies in the manifest or supply a given dependency]' \ - -precaire'[allow the use of insecure protocols]' - ;; - esac - ;; - esac -} - -_gb diff --git a/zsh/plugins/gcloud/gcloud.plugin.zsh b/zsh/plugins/gcloud/gcloud.plugin.zsh index 9be9d68..fa8f884 100644 --- a/zsh/plugins/gcloud/gcloud.plugin.zsh +++ b/zsh/plugins/gcloud/gcloud.plugin.zsh @@ -6,14 +6,19 @@ if [[ -z "${CLOUDSDK_HOME}" ]]; then search_locations=( "$HOME/google-cloud-sdk" + "/usr/local/share/google-cloud-sdk" "/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk" "/opt/homebrew/Caskroom/google-cloud-sdk/latest/google-cloud-sdk" + "/opt/homebrew/share/google-cloud-sdk" "/usr/share/google-cloud-sdk" "/snap/google-cloud-sdk/current" + "/snap/google-cloud-cli/current" "/usr/lib/google-cloud-sdk" "/usr/lib64/google-cloud-sdk" "/opt/google-cloud-sdk" + "/opt/google-cloud-cli" "/opt/local/libexec/google-cloud-sdk" + "$HOME/.asdf/installs/gcloud/*/" ) for gcloud_sdk_location in $search_locations; do @@ -26,11 +31,9 @@ if [[ -z "${CLOUDSDK_HOME}" ]]; then fi if (( ${+CLOUDSDK_HOME} )); then - # Only source this if gcloud isn't already on the path - if (( ! $+commands[gcloud] )); then - if [[ -f "${CLOUDSDK_HOME}/path.zsh.inc" ]]; then - source "${CLOUDSDK_HOME}/path.zsh.inc" - fi + # Source path file + if [[ -f "${CLOUDSDK_HOME}/path.zsh.inc" ]]; then + source "${CLOUDSDK_HOME}/path.zsh.inc" fi # Look for completion file in different paths diff --git a/zsh/plugins/gem/_gem b/zsh/plugins/gem/completions/_gem similarity index 100% rename from zsh/plugins/gem/_gem rename to zsh/plugins/gem/completions/_gem diff --git a/zsh/plugins/gem/gem.plugin.zsh b/zsh/plugins/gem/gem.plugin.zsh index 938f5c9..41c434a 100644 --- a/zsh/plugins/gem/gem.plugin.zsh +++ b/zsh/plugins/gem/gem.plugin.zsh @@ -4,4 +4,29 @@ alias gemp="gem push *.gem" # gemy GEM 0.0.0 = gem yank GEM -v 0.0.0 function gemy { gem yank $1 -v $2 -} \ No newline at end of file +} + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `gem`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_gem" ]]; then + typeset -g -A _comps + autoload -Uz _gem + _comps[gem]=_gem +fi + +# zsh 5.5 already provides completion for `_gem`. With this we ensure that +# our provided completion (which is not optimal but is enough in most cases) +# is used for older versions +autoload -Uz is-at-least +if is-at-least 5.5; then + return 0 +fi + +{ + # Standardized $0 handling + # https://zdharma-continuum.github.io/Zsh-100-Commits-Club/Zsh-Plugin-Standard.html + 0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" + 0="${${(M)0:#/*}:-$PWD/$0}" + + command cp -f "${0:h}/completions/_gem" "$ZSH_CACHE_DIR/completions/_gem" +} &| diff --git a/zsh/plugins/git-auto-fetch/README.md b/zsh/plugins/git-auto-fetch/README.md index e96ab42..0d7431b 100644 --- a/zsh/plugins/git-auto-fetch/README.md +++ b/zsh/plugins/git-auto-fetch/README.md @@ -18,7 +18,7 @@ You can change the fetch interval in your .zshrc: GIT_AUTO_FETCH_INTERVAL=1200 # in seconds ``` -A log of `git fetch --all` will be saved in `.git/FETCH_LOG`. +A log of `git-fetch-all` will be saved in `.git/FETCH_LOG`. ## Toggle auto-fetch per folder diff --git a/zsh/plugins/git-auto-fetch/git-auto-fetch.plugin.zsh b/zsh/plugins/git-auto-fetch/git-auto-fetch.plugin.zsh index 2df34bb..f8dfec7 100644 --- a/zsh/plugins/git-auto-fetch/git-auto-fetch.plugin.zsh +++ b/zsh/plugins/git-auto-fetch/git-auto-fetch.plugin.zsh @@ -29,7 +29,7 @@ function git-fetch-all { date -R &>! "$gitdir/FETCH_LOG" GIT_SSH_COMMAND="command ssh -o BatchMode=yes" \ GIT_TERMINAL_PROMPT=0 \ - command git fetch --all 2>/dev/null &>> "$gitdir/FETCH_LOG" + command git fetch --all --recurse-submodules=yes 2>/dev/null &>> "$gitdir/FETCH_LOG" ) &| } diff --git a/zsh/plugins/git-commit/README.md b/zsh/plugins/git-commit/README.md new file mode 100644 index 0000000..f812ee2 --- /dev/null +++ b/zsh/plugins/git-commit/README.md @@ -0,0 +1,47 @@ +# git-commit plugin + +The git-commit plugin adds several +[git aliases](https://www.git-scm.com/docs/git-config#Documentation/git-config.txt-alias) for +[conventional commit](https://www.conventionalcommits.org/en/v1.0.0/#summary) messages. + +To use it, add `git-commit` to the plugins array in your zshrc file: + +```zsh +plugins=(... git-commit) +``` + +## Syntax + +```zsh +git [(-s, --scope) ""] [(-a, --attention)] "" +``` + +Where `type` is one of the following: + +- `build` +- `chore` +- `ci` +- `docs` +- `feat` +- `fix` +- `perf` +- `refactor` +- `rev` +- `style` +- `test` +- `wip` + +> NOTE: the alias for `revert` type is `rev`, as otherwise it conflicts with the git command of the same name. +> It will still generate a commit message in the format `revert: ` + +> ⚠️ Enabling this plugin will (potentially) overwrite all `alias.` that you manually set. Use with +> care! + +## Examples + +| Git alias | Command | +| --------------------------------------------- | ---------------------------------------------------- | +| `git style "remove trailing whitespace"` | `git commit -m "style: remove trailing whitespace"` | +| `git wip "work in progress"` | `git commit -m "work in progress"` | +| `git fix -s "router" "correct redirect link"` | `git commit -m "fix(router): correct redirect link"` | +| `git rev -s "api" "rollback v2"` | `git commit -m "revert(api): rollback v2"` | diff --git a/zsh/plugins/git-commit/git-commit.plugin.zsh b/zsh/plugins/git-commit/git-commit.plugin.zsh new file mode 100644 index 0000000..c4df77c --- /dev/null +++ b/zsh/plugins/git-commit/git-commit.plugin.zsh @@ -0,0 +1,58 @@ +local _rev="$(git -C $ZSH rev-parse HEAD 2> /dev/null)" +if [[ $_rev == $(git config --global --get oh-my-zsh.git-commit-alias 2> /dev/null) ]]; then + return +fi +git config --global oh-my-zsh.git-commit-alias "$_rev" + +local -a _git_commit_aliases +_git_commit_aliases=( + 'build' + 'chore' + 'ci' + 'docs' + 'feat' + 'fix' + 'perf' + 'refactor' + 'revert' + 'style' + 'test' + 'wip' +) + +local _alias _type +for _type in "${_git_commit_aliases[@]}"; do + # an alias can't be named "revert" because the git command takes precedence + # https://stackoverflow.com/a/3538791 + case "$_type" in + revert) _alias=rev ;; + *) _alias=$_type ;; + esac + + local _func='!a() { +local _scope _attention _message +while [ $# -ne 0 ]; do +case $1 in + -s | --scope ) + if [ -z $2 ]; then + echo "Missing scope!" + return 1 + fi + _scope="$2" + shift 2 + ;; + -a | --attention ) + _attention="!" + shift 1 + ;; + * ) + _message="${_message} $1" + shift 1 + ;; +esac +done +git commit -m "'$_type'${_scope:+(${_scope})}${_attention}:${_message}" +}; a' + + git config --global alias.$_alias "$_func" +done diff --git a/zsh/plugins/git-extras/README.md b/zsh/plugins/git-extras/README.md index 2adc9d4..7eb53fc 100644 --- a/zsh/plugins/git-extras/README.md +++ b/zsh/plugins/git-extras/README.md @@ -1,6 +1,6 @@ # git-extras -This plugin provides completion definitions for some of the commands defined by [git-extras](https://github.com/tj/git-extras). +This plugin provides completion definitions for some of the commands defined by [git-extras](https://github.com/tj/git-extras), which must already be installed. To use it, add `git-extras` to the plugins array in your zshrc file: diff --git a/zsh/plugins/git-extras/git-extras.plugin.zsh b/zsh/plugins/git-extras/git-extras.plugin.zsh index b86d7c5..f5fd387 100644 --- a/zsh/plugins/git-extras/git-extras.plugin.zsh +++ b/zsh/plugins/git-extras/git-extras.plugin.zsh @@ -51,7 +51,7 @@ __gitex_remote_names() { local expl declare -a remote_names remote_names=(${(f)"$(_call_program remotes git remote 2>/dev/null)"}) - __git_command_successful || return + __gitex_command_successful || return _wanted remote-names expl remote-name compadd $* - $remote_names } @@ -59,7 +59,7 @@ __gitex_tag_names() { local expl declare -a tag_names tag_names=(${${(f)"$(_call_program tags git for-each-ref --format='"%(refname)"' refs/tags 2>/dev/null)"}#refs/tags/}) - __git_command_successful || return + __gitex_command_successful || return _wanted tag-names expl tag-name compadd $* - $tag_names } @@ -68,7 +68,7 @@ __gitex_branch_names() { local expl declare -a branch_names branch_names=(${${(f)"$(_call_program branchrefs git for-each-ref --format='"%(refname)"' refs/heads 2>/dev/null)"}#refs/heads/}) - __git_command_successful || return + __gitex_command_successful || return _wanted branch-names expl branch-name compadd $* - $branch_names } @@ -76,31 +76,19 @@ __gitex_specific_branch_names() { local expl declare -a branch_names branch_names=(${${(f)"$(_call_program branchrefs git for-each-ref --format='"%(refname)"' refs/heads/"$1" 2>/dev/null)"}#refs/heads/$1/}) - __git_command_successful || return + __gitex_command_successful || return _wanted branch-names expl branch-name compadd - $branch_names } -__gitex_chore_branch_names() { - __gitex_specific_branch_names 'chore' -} - __gitex_feature_branch_names() { __gitex_specific_branch_names 'feature' } -__gitex_refactor_branch_names() { - __gitex_specific_branch_names 'refactor' -} - -__gitex_bug_branch_names() { - __gitex_specific_branch_names 'bug' -} - __gitex_submodule_names() { local expl declare -a submodule_names submodule_names=(${(f)"$(_call_program branchrefs git submodule status | awk '{print $2}')"}) # ' - __git_command_successful || return + __gitex_command_successful || return _wanted submodule-names expl submodule-name compadd $* - $submodule_names } @@ -109,93 +97,34 @@ __gitex_author_names() { local expl declare -a author_names author_names=(${(f)"$(_call_program branchrefs git log --format='%aN' | sort -u)"}) - __git_command_successful || return + __gitex_command_successful || return _wanted author-names expl author-name compadd $* - $author_names } # subcommands +# new subcommand should be added in alphabetical order _git-authors() { _arguments -C \ '(--list -l)'{--list,-l}'[show authors]' \ '--no-email[without email]' \ } -_git-bug() { - local curcontext=$curcontext state line ret=1 - declare -A opt_args - - _arguments -C \ - ': :->command' \ - '*:: :->option-or-argument' && ret=0 - - case $state in - (command) - declare -a commands - commands=( - 'finish:merge bug into the current branch' - ) - _describe -t commands command commands && ret=0 - ;; - (option-or-argument) - curcontext=${curcontext%:*}-$line[1]: - case $line[1] in - (finish) - _arguments -C \ - ':branch-name:__gitex_bug_branch_names' - ;; - -r|--remote ) - _arguments -C \ - ':remote-name:__gitex_remote_names' - ;; - esac - return 0 - esac - - _arguments \ - '(--remote -r)'{--remote,-r}'[setup remote tracking branch]' -} - - _git-changelog() { _arguments \ '(-l --list)'{-l,--list}'[list commits]' \ } -_git-chore() { - local curcontext=$curcontext state line ret=1 - declare -A opt_args - - _arguments -C \ - ': :->command' \ - '*:: :->option-or-argument' && ret=0 - - case $state in - (command) - declare -a commands - commands=( - 'finish:merge and delete the chore branch' - ) - _describe -t commands command commands && ret=0 - ;; - (option-or-argument) - curcontext=${curcontext%:*}-$line[1]: - case $line[1] in - (finish) - _arguments -C \ - ':branch-name:__gitex_chore_branch_names' - ;; - -r|--remote ) - _arguments -C \ - ':remote-name:__gitex_remote_names' - ;; - esac - return 0 - esac - +_git-clear() { _arguments \ - '(--remote -r)'{--remote,-r}'[setup remote tracking branch]' + '(-f --force)'{-f,--force}'[force clear]' \ + '(-h --help)'{-h,--help}'[help message]' \ } +_git-coauthor() { + _arguments \ + ':co-author[co-author to add]' \ + ':co-author-email[email address of co-author to add]' +} _git-contrib() { _arguments \ @@ -235,6 +164,11 @@ _git-delete-branch() { ':branch-name:__gitex_branch_names' } +_git-delete-squashed-branches() { + _arguments \ + ':branch-name:__gitex_branch_names' +} + _git-delete-submodule() { _arguments \ @@ -298,6 +232,7 @@ _git-feature() { case $line[1] in (finish) _arguments -C \ + '--squash[Use squash merge]' \ ':branch-name:__gitex_feature_branch_names' ;; -r|--remote ) @@ -327,20 +262,17 @@ _git-guilt() { } _git-ignore() { - _arguments -C \ + _arguments -C \ '(--local -l)'{--local,-l}'[show local gitignore]' \ '(--global -g)'{--global,-g}'[show global gitignore]' \ '(--private -p)'{--private,-p}'[show repo gitignore]' } -_git-ignore() { - _arguments -C \ - '(--append -a)'{--append,-a}'[append .gitignore]' \ - '(--replace -r)'{--replace,-r}'[replace .gitignore]' \ - '(--list-in-table -l)'{--list-in-table,-l}'[print available types in table format]' \ - '(--list-alphabetically -L)'{--list-alphabetically,-L}'[print available types in alphabetical order]' \ - '(--search -s)'{--search,-s}'[search word in available types]' +_git-info() { + _arguments -C \ + '(--color -c)'{--color,-c}'[use color for information titles]' \ + '--no-config[do not show list all variables set in config file, along with their values]' } @@ -357,50 +289,27 @@ _git-missing() { ':second-branch-name:__gitex_branch_names' } - -_git-refactor() { - local curcontext=$curcontext state line ret=1 - declare -A opt_args - +_git-release() { _arguments -C \ - ': :->command' \ - '*:: :->option-or-argument' && ret=0 - - case $state in - (command) - declare -a commands - commands=( - 'finish:merge refactor into the current branch' - ) - _describe -t commands command commands && ret=0 - ;; - (option-or-argument) - curcontext=${curcontext%:*}-$line[1]: - case $line[1] in - (finish) - _arguments -C \ - ':branch-name:__gitex_refactor_branch_names' - ;; - -r|--remote ) - _arguments -C \ - ':remote-name:__gitex_remote_names' - ;; - esac - return 0 - esac - - _arguments \ - '(--remote -r)'{--remote,-r}'[setup remote tracking branch]' + '-c[Generates/populates the changelog with all commit message since the last tag.]' \ + '-r[The "remote" repository that is destination of a push operation.]' \ + '-m[use the custom commit information instead of the default message.]' \ + '-s[Create a signed and annotated tag.]' \ + '-u[Create a tag, annotated and signed with the given key.]' \ + '--semver[If the latest tag in your repo matches the semver format requirement, you could increase part of it as the new release tag.]' \ + '--prefix[Add a prefix string to semver to allow more complex tags.]' \ + '--no-empty-commit[Avoid creating empty commit if nothing could be committed.]' \ + '--[The arguments listed after "--" separator will be passed to pre/post-release hook.]' } - _git-squash() { + _arguments '--squash-msg[commit with the squashed commit messages]' _arguments \ ':branch-name:__gitex_branch_names' } _git-stamp() { - _arguments -C \ + _arguments -C \ '(--replace -r)'{--replace,-r}'[replace stamps with same id]' } @@ -413,17 +322,19 @@ _git-standup() { '-g[Display GPG signed info]' \ '-h[Display help message]' \ '-L[Enable the inclusion of symbolic links]' \ - '-m[The depth of recursive directory search]' + '-m[The depth of recursive directory search]' \ + '-B[Display the commits in branch groups]' } _git-summary() { _arguments '--line[summarize with lines rather than commits]' + _arguments '--dedup-by-email[remove duplicate users by the email address]' + _arguments '--no-merges[exclude merge commits]' __gitex_commits } - _git-undo(){ - _arguments -C \ + _arguments -C \ '(--soft -s)'{--soft,-s}'[only rolls back the commit but changes remain un-staged]' \ '(--hard -h)'{--hard,-h}'[wipes your commit(s)]' } @@ -432,21 +343,26 @@ zstyle -g existing_user_commands ':completion:*:*:git:*' user-commands zstyle ':completion:*:*:git:*' user-commands $existing_user_commands \ alias:'define, search and show aliases' \ + abort:'abort current revert, merge, rebase, or cherry-pick process' \ archive-file:'export the current head of the git repository to an archive' \ authors:'generate authors report' \ - back:'undo and stage latest commits' \ + browse:'open repo website in browser' \ + browse-ci:'open repo CI page in browser' \ bug:'create bug branch' \ bulk:'run bulk commands' \ + brv:'list branches sorted by their last commit date'\ changelog:'generate a changelog report' \ chore:'create chore branch' \ clear-soft:'soft clean up a repository' \ clear:'rigorously clean up a repository' \ + coauthor:'add a co-author to the last commit' \ commits-since:'show commit logs since some date' \ contrib:'show user contributions' \ count:'show commit count' \ create-branch:'create branches' \ delete-branch:'delete branches' \ delete-merged-branches:'delete merged branches' \ + delete-squashed-branches:'delete squashed branches' \ delete-submodule:'delete submodules' \ delete-tag:'delete tags' \ delta:'lists changed files' \ @@ -465,11 +381,13 @@ zstyle ':completion:*:*:git:*' user-commands $existing_user_commands \ local-commits:'list local commits' \ lock:'lock a file excluded from version control' \ locked:'ls files that have been locked' \ + magic:'commits everything with a generated message' \ merge-into:'merge one branch into another' \ merge-repo:'merge two repo histories' \ missing:'show commits missing from another branch' \ mr:'checks out a merge request locally' \ obliterate:'rewrite past commits to remove some files' \ + paste:'send patches to pastebin sites' \ pr:'checks out a pull request locally' \ psykorebase:'rebase a branch with a merge commit' \ pull-request:'create pull request to GitHub project' \ @@ -479,6 +397,7 @@ zstyle ':completion:*:*:git:*' user-commands $existing_user_commands \ release:'commit, tag and push changes to the repository' \ rename-branch:'rename a branch' \ rename-tag:'rename a tag' \ + rename-remote:'rename a remote' \ repl:'git read-eval-print-loop' \ reset-file:'reset one file' \ root:'show path of root' \ @@ -495,4 +414,5 @@ zstyle ':completion:*:*:git:*' user-commands $existing_user_commands \ sync:'sync local branch with remote branch' \ touch:'touch and add file to the index' \ undo:'remove latest commits' \ - unlock:'unlock a file excluded from version control' + unlock:'unlock a file excluded from version control' \ + utimes:'change files modification time to their last commit date' diff --git a/zsh/plugins/git-prompt/README.md b/zsh/plugins/git-prompt/README.md index 8775af8..8f42c68 100644 --- a/zsh/plugins/git-prompt/README.md +++ b/zsh/plugins/git-prompt/README.md @@ -9,6 +9,10 @@ To use it, add `git-prompt` to the plugins array in your zshrc file: plugins=(... git-prompt) ``` +You may also need to [customize your theme](https://github.com/ohmyzsh/ohmyzsh/issues/9395#issuecomment-1027130429) +to change the way the prompt is built. See the +[OMZ wiki on customizing themes](https://github.com/ohmyzsh/ohmyzsh/wiki/Customization#overriding-and-adding-themes). + See the [original repository](https://github.com/olivierverdier/zsh-git-prompt). ## Requirements @@ -45,6 +49,7 @@ The symbols are as follows: | ●n | there are `n` staged files | | ✖n | there are `n` unmerged files | | ✚n | there are `n` unstaged files | +| -n | there are `n` deleted files | | ⚑n | there are `n` stashed changes | | … | there are some untracked files | @@ -59,6 +64,7 @@ The symbols are as follows: ## Customisation - Set the variable `ZSH_THEME_GIT_PROMPT_CACHE` to any value in order to enable caching. +- Set the variable `ZSH_THEME_GIT_SHOW_UPSTREAM` to any value to display the upstream branch. - You may also change a number of variables (whose name start with `ZSH_THEME_GIT_PROMPT_`) to change the appearance of the prompt. Take a look at the bottom of the [plugin file](git-prompt.plugin.zsh)` to see what variables are available. diff --git a/zsh/plugins/git-prompt/git-prompt.plugin.zsh b/zsh/plugins/git-prompt/git-prompt.plugin.zsh index 0485e31..4873320 100644 --- a/zsh/plugins/git-prompt/git-prompt.plugin.zsh +++ b/zsh/plugins/git-prompt/git-prompt.plugin.zsh @@ -47,12 +47,19 @@ function update_current_git_vars() { GIT_UNTRACKED=$__CURRENT_GIT_STATUS[7] GIT_STASHED=$__CURRENT_GIT_STATUS[8] GIT_CLEAN=$__CURRENT_GIT_STATUS[9] + GIT_DELETED=$__CURRENT_GIT_STATUS[10] + + if [ -z ${ZSH_THEME_GIT_SHOW_UPSTREAM+x} ]; then + GIT_UPSTREAM= + else + GIT_UPSTREAM=$(git rev-parse --abbrev-ref --symbolic-full-name "@{upstream}" 2>/dev/null) && GIT_UPSTREAM="${ZSH_THEME_GIT_PROMPT_UPSTREAM_SEPARATOR}${GIT_UPSTREAM}" + fi } git_super_status() { precmd_update_git_vars if [ -n "$__CURRENT_GIT_STATUS" ]; then - STATUS="$ZSH_THEME_GIT_PROMPT_PREFIX$ZSH_THEME_GIT_PROMPT_BRANCH$GIT_BRANCH%{${reset_color}%}" + STATUS="$ZSH_THEME_GIT_PROMPT_PREFIX$ZSH_THEME_GIT_PROMPT_BRANCH$GIT_BRANCH$GIT_UPSTREAM%{${reset_color}%}" if [ "$GIT_BEHIND" -ne "0" ]; then STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_BEHIND$GIT_BEHIND%{${reset_color}%}" fi @@ -69,6 +76,9 @@ git_super_status() { if [ "$GIT_CHANGED" -ne "0" ]; then STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_CHANGED$GIT_CHANGED%{${reset_color}%}" fi + if [ "$GIT_DELETED" -ne "0" ]; then + STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_DELETED$GIT_DELETED%{${reset_color}%}" + fi if [ "$GIT_UNTRACKED" -ne "0" ]; then STATUS="$STATUS$ZSH_THEME_GIT_PROMPT_UNTRACKED$GIT_UNTRACKED%{${reset_color}%}" fi @@ -91,11 +101,13 @@ ZSH_THEME_GIT_PROMPT_BRANCH="%{$fg_bold[magenta]%}" ZSH_THEME_GIT_PROMPT_STAGED="%{$fg[red]%}%{●%G%}" ZSH_THEME_GIT_PROMPT_CONFLICTS="%{$fg[red]%}%{✖%G%}" ZSH_THEME_GIT_PROMPT_CHANGED="%{$fg[blue]%}%{✚%G%}" +ZSH_THEME_GIT_PROMPT_DELETED="%{$fg[blue]%}%{-%G%}" ZSH_THEME_GIT_PROMPT_BEHIND="%{↓%G%}" ZSH_THEME_GIT_PROMPT_AHEAD="%{↑%G%}" ZSH_THEME_GIT_PROMPT_UNTRACKED="%{$fg[cyan]%}%{…%G%}" ZSH_THEME_GIT_PROMPT_STASHED="%{$fg_bold[blue]%}%{⚑%G%}" ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg_bold[green]%}%{✔%G%}" +ZSH_THEME_GIT_PROMPT_UPSTREAM_SEPARATOR="->" # Set the prompt. RPROMPT='$(git_super_status)' diff --git a/zsh/plugins/git-prompt/gitstatus.py b/zsh/plugins/git-prompt/gitstatus.py index b5c3c9a..7cd8f54 100644 --- a/zsh/plugins/git-prompt/gitstatus.py +++ b/zsh/plugins/git-prompt/gitstatus.py @@ -23,9 +23,10 @@ def get_tagname_or_hash(): return hash_ return None -# Re-use method from https://github.com/magicmonty/bash-git-prompt to get stashs count +# Re-use method from https://github.com/magicmonty/bash-git-prompt to get stash count +# Use `--git-common-dir` to avoid problems with git worktrees, which don't have individual stashes def get_stash(): - cmd = Popen(['git', 'rev-parse', '--git-dir'], stdout=PIPE, stderr=PIPE) + cmd = Popen(['git', 'rev-parse', '--git-common-dir'], stdout=PIPE, stderr=PIPE) so, se = cmd.communicate() stash_file = '%s%s' % (so.decode('utf-8').rstrip(), '/logs/refs/stash') @@ -35,7 +36,6 @@ def get_stash(): except IOError: return 0 - # `git status --porcelain --branch` can collect all information # branch, remote_branch, untracked, staged, changed, conflicts, ahead, behind po = Popen(['git', 'status', '--porcelain', '--branch'], env=dict(os.environ, LANG="C"), stdout=PIPE, stderr=PIPE) @@ -44,7 +44,7 @@ if po.returncode != 0: sys.exit(0) # Not a git repository # collect git status information -untracked, staged, changed, conflicts = [], [], [], [] +untracked, staged, changed, deleted, conflicts = [], [], [], [], [] ahead, behind = 0, 0 status = [(line[0], line[1], line[2:]) for line in stdout.decode('utf-8').splitlines()] for st in status: @@ -75,13 +75,15 @@ for st in status: else: if st[1] == 'M': changed.append(st) + if st[1] == 'D': + deleted.append(st) if st[0] == 'U': conflicts.append(st) elif st[0] != ' ': staged.append(st) stashed = get_stash() -if not changed and not staged and not conflicts and not untracked: +if not changed and not deleted and not staged and not conflicts and not untracked: clean = 1 else: clean = 0 @@ -95,6 +97,7 @@ out = ' '.join([ str(len(changed)), str(len(untracked)), str(stashed), - str(clean) + str(clean), + str(len(deleted)) ]) print(out, end='') diff --git a/zsh/plugins/git/README.md b/zsh/plugins/git/README.md index 050c13d..0090fa6 100644 --- a/zsh/plugins/git/README.md +++ b/zsh/plugins/git/README.md @@ -10,239 +10,266 @@ plugins=(... git) ## Aliases -| Alias | Command | -|:---------------------|:---------------------------------------------------------------------------------------------------------------------------------| -| g | git | -| ga | git add | -| gaa | git add --all | -| gapa | git add --patch | -| gau | git add --update | -| gav | git add --verbose | -| gap | git apply | -| gapt | git apply --3way | -| gb | git branch | -| gba | git branch -a | -| gbd | git branch -d | -| gbda | git branch --no-color --merged \| grep -vE "^([+*]\|\s*($(git_main_branch)\|$(git_develop_branch))\s*$)" \| xargs git branch -d 2>/dev/null | -| gbD | git branch -D | -| gbl | git blame -b -w | -| gbnm | git branch --no-merged | -| gbr | git branch --remote | -| gbs | git bisect | -| gbsb | git bisect bad | -| gbsg | git bisect good | -| gbsr | git bisect reset | -| gbss | git bisect start | -| gc | git commit -v | -| gc! | git commit -v --amend | -| gcn! | git commit -v --no-edit --amend | -| gca | git commit -v -a | -| gca! | git commit -v -a --amend | -| gcan! | git commit -v -a --no-edit --amend | -| gcans! | git commit -v -a -s --no-edit --amend | -| gcam | git commit -a -m | -| gcas | git commit -a -s | -| gcasm | git commit -a -s -m | -| gcsm | git commit -s -m | -| gcb | git checkout -b | -| gcf | git config --list | -| gcl | git clone --recurse-submodules | -| gccd | git clone --recurse-submodules "$@" && cd "$(basename $_ .git)" | -| gclean | git clean -id | -| gpristine | git reset --hard && git clean -dffx | -| gcm | git checkout $(git_main_branch) | -| gcd | git checkout $(git_develop_branch) | -| gcmsg | git commit -m | -| gco | git checkout | -| gcor | git checkout --recurse-submodules | -| gcount | git shortlog -sn | -| gcp | git cherry-pick | -| gcpa | git cherry-pick --abort | -| gcpc | git cherry-pick --continue | -| gcs | git commit -S | -| gd | git diff | -| gdca | git diff --cached | -| gdcw | git diff --cached --word-diff | -| gdct | git describe --tags $(git rev-list --tags --max-count=1) | -| gds | git diff --staged | -| gdt | git diff-tree --no-commit-id --name-only -r | -| gdnolock | git diff $@ ":(exclude)package-lock.json" ":(exclude)*.lock" | -| gdup | git diff @{upstream} | -| gdv | git diff -w $@ \| view - | -| gdw | git diff --word-diff | -| gf | git fetch | -| gfa | git fetch --all --prune | -| gfg | git ls-files \| grep | -| gfo | git fetch origin | -| gg | git gui citool | -| gga | git gui citool --amend | -| ggf | git push --force origin $(current_branch) | -| ggfl | git push --force-with-lease origin $(current_branch) | -| ggl | git pull origin $(current_branch) | -| ggp | git push origin $(current_branch) | -| ggpnp | ggl && ggp | -| ggpull | git pull origin "$(git_current_branch)" | -| ggpur | ggu | -| ggpush | git push origin "$(git_current_branch)" | -| ggsup | git branch --set-upstream-to=origin/$(git_current_branch) | -| ggu | git pull --rebase origin $(current_branch) | -| gpsup | git push --set-upstream origin $(git_current_branch) | -| ghh | git help | -| gignore | git update-index --assume-unchanged | -| gignored | git ls-files -v \| grep "^[[:lower:]]" | -| git-svn-dcommit-push | git svn dcommit && git push github $(git_main_branch):svntrunk | -| gk | gitk --all --branches &! | -| gke | gitk --all $(git log -g --pretty=%h) &! | -| gl | git pull | -| glg | git log --stat | -| glgp | git log --stat -p | -| glgg | git log --graph | -| glgga | git log --graph --decorate --all | -| glgm | git log --graph --max-count=10 | -| glo | git log --oneline --decorate | -| glol | git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' | -| glols | git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --stat | -| glod | git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset' | -| glods | git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset' --date=short | -| glola | git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --all | -| glog | git log --oneline --decorate --graph | -| gloga | git log --oneline --decorate --graph --all | -| glp | git log --pretty=\ | -| gm | git merge | -| gmom | git merge origin/$(git_main_branch) | -| gmtl | git mergetool --no-prompt | -| gmtlvim | git mergetool --no-prompt --tool=vimdiff | -| gmum | git merge upstream/$(git_main_branch) | -| gma | git merge --abort | -| gp | git push | -| gpd | git push --dry-run | -| gpf | git push --force-with-lease | -| gpf! | git push --force | -| gpoat | git push origin --all && git push origin --tags | -| gpr | git pull --rebase | -| gpu | git push upstream | -| gpv | git push -v | -| gr | git remote | -| gra | git remote add | -| grb | git rebase | -| grba | git rebase --abort | -| grbc | git rebase --continue | -| grbd | git rebase $(git_develop_branch) | -| grbi | git rebase -i | -| grbm | git rebase $(git_main_branch) | -| grbom | git rebase origin/$(git_main_branch) | -| grbo | git rebase --onto | -| grbs | git rebase --skip | -| grev | git revert | -| grh | git reset | -| grhh | git reset --hard | -| groh | git reset origin/$(git_current_branch) --hard | -| grm | git rm | -| grmc | git rm --cached | -| grmv | git remote rename | -| grrm | git remote remove | -| grs | git restore | -| grset | git remote set-url | -| grss | git restore --source | -| grst | git restore --staged | -| grt | cd "$(git rev-parse --show-toplevel \|\| echo .)" | -| gru | git reset -- | -| grup | git remote update | -| grv | git remote -v | -| gsb | git status -sb | -| gsd | git svn dcommit | -| gsh | git show | -| gsi | git submodule init | -| gsps | git show --pretty=short --show-signature | -| gsr | git svn rebase | -| gss | git status -s | -| gst | git status | -| gsta | git stash push | -| gsta | git stash save | -| gstaa | git stash apply | -| gstc | git stash clear | -| gstd | git stash drop | -| gstl | git stash list | -| gstp | git stash pop | -| gsts | git stash show --text | -| gstu | git stash --include-untracked | -| gstall | git stash --all | -| gsu | git submodule update | -| gsw | git switch | -| gswc | git switch -c | -| gswm | git switch $(git_main_branch) | -| gswd | git switch $(git_develop_branch) | -| gts | git tag -s | -| gtv | git tag \| sort -V | -| gtl | gtl(){ git tag --sort=-v:refname -n -l ${1}* }; noglob gtl | -| gunignore | git update-index --no-assume-unchanged | -| gunwip | git log -n 1 \| grep -q -c "\-\-wip\-\-" && git reset HEAD~1 | -| gup | git pull --rebase | -| gupv | git pull --rebase -v | -| gupa | git pull --rebase --autostash | -| gupav | git pull --rebase --autostash -v | -| gupom | git pull --rebase origin $(git_main_branch) | -| gupomi | git pull --rebase=interactive origin $(git_main_branch) | -| glum | git pull upstream $(git_main_branch) | -| gluc | git pull upstream $(git_current_branch) | -| gwch | git whatchanged -p --abbrev-commit --pretty=medium | -| gwip | git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign -m "--wip-- [skip ci]" | -| gam | git am | -| gamc | git am --continue | -| gams | git am --skip | -| gama | git am --abort | -| gamscp | git am --show-current-patch | +| Alias | Command | +| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------ | +| `grt` | `cd "$(git rev-parse --show-toplevel \|\| echo .)"` | +| `ggpnp` | `ggl && ggp` | +| `ggpur` | `ggu` | +| `g` | `git` | +| `ga` | `git add` | +| `gaa` | `git add --all` | +| `gapa` | `git add --patch` | +| `gau` | `git add --update` | +| `gav` | `git add --verbose` | +| `gwip` | `git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign --message "--wip-- [skip ci]"` | +| `gam` | `git am` | +| `gama` | `git am --abort` | +| `gamc` | `git am --continue` | +| `gamscp` | `git am --show-current-patch` | +| `gams` | `git am --skip` | +| `gap` | `git apply` | +| `gapt` | `git apply --3way` | +| `gbs` | `git bisect` | +| `gbsb` | `git bisect bad` | +| `gbsg` | `git bisect good` | +| `gbsn` | `git bisect new` | +| `gbso` | `git bisect old` | +| `gbsr` | `git bisect reset` | +| `gbss` | `git bisect start` | +| `gbl` | `git blame -w` | +| `gb` | `git branch` | +| `gba` | `git branch --all` | +| `gbd` | `git branch --delete` | +| `gbD` | `git branch --delete --force` | +| `gbgd` | `LANG=C git branch --no-color -vv \| grep ": gone\]" \| cut -c 3- \| awk '"'"'{print $1}'"'"' \| xargs git branch -d` | +| `gbgD` | `LANG=C git branch --no-color -vv \| grep ": gone\]" \| cut -c 3- \| awk '"'"'{print $1}'"'"' \| xargs git branch -D` | +| `gbm` | `git branch --move` | +| `gbnm` | `git branch --no-merged` | +| `gbr` | `git branch --remote` | +| `ggsup` | `git branch --set-upstream-to=origin/$(git_current_branch)` | +| `gbg` | `LANG=C git branch -vv \| grep ": gone\]"` | +| `gco` | `git checkout` | +| `gcor` | `git checkout --recurse-submodules` | +| `gcb` | `git checkout -b` | +| `gcB` | `git checkout -B` | +| `gcd` | `git checkout $(git_develop_branch)` | +| `gcm` | `git checkout $(git_main_branch)` | +| `gcp` | `git cherry-pick` | +| `gcpa` | `git cherry-pick --abort` | +| `gcpc` | `git cherry-pick --continue` | +| `gclean` | `git clean --interactive -d` | +| `gcl` | `git clone --recurse-submodules` | +| `gclf` | `git clone --recursive --shallow-submodules --filter=blob:none --also-filter-submodules` | +| `gccd` | `git clone --recurse-submodules "$@" && cd "$(basename $\_ .git)"` | +| `gcam` | `git commit --all --message` | +| `gcas` | `git commit --all --signoff` | +| `gcasm` | `git commit --all --signoff --message` | +| `gcmsg` | `git commit --message` | +| `gcsm` | `git commit --signoff --message` | +| `gc` | `git commit --verbose` | +| `gca` | `git commit --verbose --all` | +| `gca!` | `git commit --verbose --all --amend` | +| `gcan!` | `git commit --verbose --all --no-edit --amend` | +| `gcans!` | `git commit --verbose --all --signoff --no-edit --amend` | +| `gcann!` | `git commit --verbose --all --date=now --no-edit --amend` | +| `gc!` | `git commit --verbose --amend` | +| `gcn` | `git commit --verbose --no-edit` | +| `gcn!` | `git commit --verbose --no-edit --amend` | +| `gcs` | `git commit -S` | +| `gcss` | `git commit -S -s` | +| `gcssm` | `git commit -S -s -m` | +| `gcf` | `git config --list` | +| `gcfu` | `git commit --fixup` | +| `gdct` | `git describe --tags $(git rev-list --tags --max-count=1)` | +| `gd` | `git diff` | +| `gdca` | `git diff --cached` | +| `gdcw` | `git diff --cached --word-diff` | +| `gds` | `git diff --staged` | +| `gdw` | `git diff --word-diff` | +| `gdv` | `git diff -w "$@" \| view -` | +| `gdup` | `git diff @{upstream}` | +| `gdnolock` | `git diff $@ ":(exclude)package-lock.json" ":(exclude)\*.lock"` | +| `gdt` | `git diff-tree --no-commit-id --name-only -r` | +| `gf` | `git fetch` | +| `gfa` | `git fetch --all --tags --prune` | +| `gfo` | `git fetch origin` | +| `gg` | `git gui citool` | +| `gga` | `git gui citool --amend` | +| `ghh` | `git help` | +| `glgg` | `git log --graph` | +| `glgga` | `git log --graph --decorate --all` | +| `glgm` | `git log --graph --max-count=10` | +| `glod` | `git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset'` | +| `glods` | `git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset' --date=short` | +| `glol` | `git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset'` | +| `glola` | `git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --all` | +| `glols` | `git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --stat` | +| `glo` | `git log --oneline --decorate` | +| `glog` | `git log --oneline --decorate --graph` | +| `gloga` | `git log --oneline --decorate --graph --all` | +| `glp` | `git log --pretty=` | +| `glg` | `git log --stat` | +| `glgp` | `git log --stat --patch` | +| `gignored` | `git ls-files -v \| grep "^[[:lower:]]"` | +| `gfg` | `git ls-files \| grep` | +| `gm` | `git merge` | +| `gma` | `git merge --abort` | +| `gmc` | `git merge --continue` | +| `gms` | `git merge --squash` | +| `gmff` | `git merge --ff-only` | +| `gmom` | `git merge origin/$(git_main_branch)` | +| `gmum` | `git merge upstream/$(git_main_branch)` | +| `gmtl` | `git mergetool --no-prompt` | +| `gmtlvim` | `git mergetool --no-prompt --tool=vimdiff` | +| `gl` | `git pull` | +| `gpr` | `git pull --rebase` | +| `gprv` | `git pull --rebase -v` | +| `gpra` | `git pull --rebase --autostash` | +| `gprav` | `git pull --rebase --autostash -v` | +| `gprom` | `git pull --rebase origin $(git_main_branch)` | +| `gpromi` | `git pull --rebase=interactive origin $(git_main_branch)` | +| `gprum` | `git pull --rebase upstream $(git_main_branch)` | +| `gprumi` | `git pull --rebase=interactive upstream $(git_main_branch)` | +| `ggpull` | `git pull origin "$(git_current_branch)"` | +| `ggl` | `git pull origin $(current_branch)` | +| `gluc` | `git pull upstream $(git_current_branch)` | +| `glum` | `git pull upstream $(git_main_branch)` | +| `gp` | `git push` | +| `gpd` | `git push --dry-run` | +| `gpf!` | `git push --force` | +| `ggf` | `git push --force origin $(current_branch)` | +| `gpf` | On Git >= 2.30: `git push --force-with-lease --force-if-includes` | +| `gpf` | On Git < 2.30: `git push --force-with-lease` | +| `ggfl` | `git push --force-with-lease origin $(current_branch)` | +| `gpsup` | `git push --set-upstream origin $(git_current_branch)` | +| `gpsupf` | On Git >= 2.30: `git push --set-upstream origin $(git_current_branch) --force-with-lease --force-if-includes` | +| `gpsupf` | On Git < 2.30: `git push --set-upstream origin $(git_current_branch) --force-with-lease` | +| `gpv` | `git push --verbose` | +| `gpoat` | `git push origin --all && git push origin --tags` | +| `gpod` | `git push origin --delete` | +| `ggpush` | `git push origin "$(git_current_branch)"` | +| `ggp` | `git push origin $(current_branch)` | +| `gpu` | `git push upstream` | +| `grb` | `git rebase` | +| `grba` | `git rebase --abort` | +| `grbc` | `git rebase --continue` | +| `grbi` | `git rebase --interactive` | +| `grbo` | `git rebase --onto` | +| `grbs` | `git rebase --skip` | +| `grbd` | `git rebase $(git_develop_branch)` | +| `grbm` | `git rebase $(git_main_branch)` | +| `grbom` | `git rebase origin/$(git_main_branch)` | +| `grbum` | `git rebase upstream/$(git_main_branch)` | +| `grf` | `git reflog` | +| `gr` | `git remote` | +| `grv` | `git remote --verbose` | +| `gra` | `git remote add` | +| `grrm` | `git remote remove` | +| `grmv` | `git remote rename` | +| `grset` | `git remote set-url` | +| `grup` | `git remote update` | +| `grh` | `git reset` | +| `gru` | `git reset --` | +| `grhh` | `git reset --hard` | +| `grhk` | `git reset --keep` | +| `grhs` | `git reset --soft` | +| `gpristine` | `git reset --hard && git clean --force -dfx` | +| `gwipe` | `git reset --hard && git clean --force -df` | +| `groh` | `git reset origin/$(git_current_branch) --hard` | +| `grs` | `git restore` | +| `grss` | `git restore --source` | +| `grst` | `git restore --staged` | +| `gunwip` | `git rev-list --max-count=1 --format="%s" HEAD \| grep -q "--wip--" && git reset HEAD~1` | +| `grev` | `git revert` | +| `grm` | `git rm` | +| `grmc` | `git rm --cached` | +| `gcount` | `git shortlog --summary -n` | +| `gsh` | `git show` | +| `gsps` | `git show --pretty=short --show-signature` | +| `gstall` | `git stash --all` | +| `gstu` | `git stash --include-untracked` | +| `gstaa` | `git stash apply` | +| `gstc` | `git stash clear` | +| `gstd` | `git stash drop` | +| `gstl` | `git stash list` | +| `gstp` | `git stash pop` | +| `gsta` | On Git >= 2.13: `git stash push` | +| `gsta` | On Git < 2.13: `git stash save` | +| `gsts` | `git stash show --patch` | +| `gst` | `git status` | +| `gss` | `git status --short` | +| `gsb` | `git status --short -b` | +| `gsi` | `git submodule init` | +| `gsu` | `git submodule update` | +| `gsd` | `git svn dcommit` | +| `git-svn-dcommit-push` | `git svn dcommit && git push github $(git_main_branch):svntrunk` | +| `gsr` | `git svn rebase` | +| `gsw` | `git switch` | +| `gswc` | `git switch -c` | +| `gswd` | `git switch $(git_develop_branch)` | +| `gswm` | `git switch $(git_main_branch)` | +| `gta` | `git tag --annotate` | +| `gts` | `git tag -s` | +| `gtv` | `git tag \| sort -V` | +| `gignore` | `git update-index --assume-unchanged` | +| `gunignore` | `git update-index --no-assume-unchanged` | +| `gwch` | `git log --patch --abbrev-commit --pretty=medium --raw` | +| `gwt` | `git worktree` | +| `gwtls` | `git worktree list` | +| `gwtmv` | `git worktree move` | +| `gwtrm` | `git worktree remove` | +| `gk` | `gitk --all --branches &!` | +| `gke` | `gitk --all $(git log --walk-reflogs --pretty=%h) &!` | +| `gtl` | `gtl(){ git tag --sort=-v:refname -n --list ${1}\* }; noglob gtl` | ### Main branch preference -Following the recent push for removing racially-charged words from our technical vocabulary, the git plugin favors using -a branch name other than `master`. In this case, we favor the shorter, neutral and descriptive term `main`. This means -that any aliases and functions that previously used `master`, will use `main` if that branch exists. We do this via the -function `git_main_branch`. +Following the recent push for removing racially-charged words from our technical vocabulary, the git plugin +favors using a branch name other than `master`. In this case, we favor the shorter, neutral and descriptive +term `main`. This means that any aliases and functions that previously used `master`, will use `main` if that +branch exists. We do this via the function `git_main_branch`. ### Deprecated aliases -These are aliases that have been removed, renamed, or otherwise modified in a way that may, or may not, receive further support. +These are aliases that have been removed, renamed, or otherwise modified in a way that may, or may not, +receive further support. -| Alias | Command | Modification | -| :----- | :----------------------------------------------------- | :----------------------------------------------------- | -| gap | `git add --patch` | new alias `gapa` | -| gcl | `git config --list` | new alias `gcf` | -| gdc | `git diff --cached` | new alias `gdca` | -| gdt | `git difftool` | no replacement | -| ggpull | `git pull origin $(current_branch)` | new alias `ggl` (`ggpull` still exists for now though) | -| ggpur | `git pull --rebase origin $(current_branch)` | new alias `ggu` (`ggpur` still exists for now though) | -| ggpush | `git push origin $(current_branch)` | new alias `ggp` (`ggpush` still exists for now though) | -| gk | `gitk --all --branches` | now aliased to `gitk --all --branches` | -| glg | `git log --stat --max-count = 10` | now aliased to `git log --stat --color` | -| glgg | `git log --graph --max-count = 10` | now aliased to `git log --graph --color` | -| gwc | `git whatchanged -p --abbrev-commit --pretty = medium` | new alias `gwch` | +| Alias | Command | Modification | +| :------- | :-------------------------------------------------------- | :-----------------------------------------------------| +| `gap` | `git add --patch` | New alias: `gapa` | +| `gcl` | `git config --list` | New alias: `gcf` | +| `gdt` | `git difftool` | No replacement | ## Functions ### Current -| Command | Description | -|:-----------------------|:---------------------------------------------------------------------------------------------------------| -| `grename ` | Rename `old` branch to `new`, including in origin remote | -| current_branch | Return the name of the current branch | -| git_current_user_name | Returns the `user.name` config value | -| git_current_user_email | Returns the `user.email` config value | -| git_main_branch | Returns the name of the main branch: `main` if it exists, `master` otherwise | -| git_develop_branch | Returns the name of the develop branch: `dev`, `devel`, `development` if they exist, `develop` otherwise | +| Command | Description | +| :----------------------- | :------------------------------------------------------------------------------------------------------------- | +| `git_current_branch` | Returns the name of the current branch (Lives in `lib/git.zsh`) | +| `git_current_user_email` | Returns the `user.email` config value (Lives in `lib/git.zsh`) | +| `git_current_user_name` | Returns the `user.name` config value (Lives in `lib/git.zsh`) | +| `git_develop_branch` | Returns the name of the “development” branch: `dev`, `devel`, `development` if they exist, `develop` otherwise | +| `git_main_branch` | Returns the name of the main branch: `main` if it exists, `master` otherwise | +| `grename ` | Renames branch `` to ``, including on the origin remote | +| `gbda` | Deletes all merged branches | +| `gbds` | Deletes all squash-merged branches (**Note: performance degrades with number of branches**) | ### Work in Progress (WIP) -These features allow to pause a branch development and switch to another one (_"Work in Progress"_, or wip). When you want to go back to work, just unwip it. +These features allow you to pause developing one branch and switch to another one (_"Work in Progress"_, or +“wip”). When you want to go back to work, just “unwip” it. -| Command | Description | -|:-----------------|:------------------------------------------------| -| work_in_progress | Echoes a warning if the current branch is a wip | -| gwip | Commit wip branch | -| gunwip | Uncommit wip branch | +| Command | Description | +| :----------------- | :---------------------------------------------- | +| `gwip` | Commit wip branch | +| `gunwip` | Uncommit wip branch | +| `gunwipall` | Uncommit all recent `--wip--` commits | +| `work_in_progress` | Echoes a warning if the current branch is a wip | + +Note that `gwip` and `gunwip` are aliases, but are also documented here to group all related WIP features. ### Deprecated functions -| Command | Description | Reason | -|:-----------------------|:----------------------------------------|:----------------------------------------------------------------| -| current_repository | Return the names of the current remotes | Didn't work properly. Use `git remote -v` instead (`grv` alias) | +| Command | Description | Reason | +| :------------------- | :-------------------------------------- | :--------------------------------------------------------------- | diff --git a/zsh/plugins/git/git.plugin.zsh b/zsh/plugins/git/git.plugin.zsh index f25453b..9ef60d6 100644 --- a/zsh/plugins/git/git.plugin.zsh +++ b/zsh/plugins/git/git.plugin.zsh @@ -3,323 +3,51 @@ autoload -Uz is-at-least git_version="${${(As: :)$(git version 2>/dev/null)}[3]}" # -# Functions +# Functions Current +# (sorted alphabetically by function name) +# (order should follow README) # -# The name of the current branch -# Back-compatibility wrapper for when this function was defined here in -# the plugin, before being pulled in to core lib/git.zsh as git_current_branch() -# to fix the core -> git plugin dependency. -function current_branch() { - git_current_branch -} - -# Pretty log messages -function _git_log_prettily(){ - if ! [ -z $1 ]; then - git log --pretty=$1 - fi -} -compdef _git _git_log_prettily=git-log - -# Warn if the current branch is a WIP -function work_in_progress() { - command git -c log.showSignature=false log -n 1 2>/dev/null | grep -q -- "--wip--" && echo "WIP!!" -} - -# Check if main exists and use instead of master -function git_main_branch() { - command git rev-parse --git-dir &>/dev/null || return - local ref - for ref in refs/{heads,remotes/{origin,upstream}}/{main,trunk}; do - if command git show-ref -q --verify $ref; then - echo ${ref:t} - return - fi - done - echo master -} - # Check for develop and similarly named branches function git_develop_branch() { command git rev-parse --git-dir &>/dev/null || return local branch - for branch in dev devel development; do + for branch in dev devel develop development; do if command git show-ref -q --verify refs/heads/$branch; then echo $branch - return + return 0 fi done + echo develop + return 1 } -# -# Aliases -# (sorted alphabetically) -# +# Get the default branch name from common branch names or fallback to remote HEAD +function git_main_branch() { + command git rev-parse --git-dir &>/dev/null || return + + local remote ref + + for ref in refs/{heads,remotes/{origin,upstream}}/{main,trunk,mainline,default,stable,master}; do + if command git show-ref -q --verify $ref; then + echo ${ref:t} + return 0 + fi + done + + # Fallback: try to get the default branch from remote HEAD symbolic refs + for remote in origin upstream; do + ref=$(command git rev-parse --abbrev-ref $remote/HEAD 2>/dev/null) + if [[ $ref == $remote/* ]]; then + echo ${ref#"$remote/"}; return 0 + fi + done -alias g='git' - -alias ga='git add' -alias gaa='git add --all' -alias gapa='git add --patch' -alias gau='git add --update' -alias gav='git add --verbose' -alias gap='git apply' -alias gapt='git apply --3way' - -alias gb='git branch' -alias gba='git branch -a' -alias gbd='git branch -d' -alias gbda='git branch --no-color --merged | command grep -vE "^([+*]|\s*($(git_main_branch)|$(git_develop_branch))\s*$)" | command xargs git branch -d 2>/dev/null' -alias gbD='git branch -D' -alias gbl='git blame -b -w' -alias gbnm='git branch --no-merged' -alias gbr='git branch --remote' -alias gbs='git bisect' -alias gbsb='git bisect bad' -alias gbsg='git bisect good' -alias gbsr='git bisect reset' -alias gbss='git bisect start' - -alias gc='git commit -v' -alias gc!='git commit -v --amend' -alias gcn!='git commit -v --no-edit --amend' -alias gca='git commit -v -a' -alias gca!='git commit -v -a --amend' -alias gcan!='git commit -v -a --no-edit --amend' -alias gcans!='git commit -v -a -s --no-edit --amend' -alias gcam='git commit -a -m' -alias gcsm='git commit -s -m' -alias gcas='git commit -a -s' -alias gcasm='git commit -a -s -m' -alias gcb='git checkout -b' -alias gcf='git config --list' - -function gccd() { - command git clone --recurse-submodules "$@" - [[ -d "$_" ]] && cd "$_" || cd "${${_:t}%.git}" + # If no main branch was found, fall back to master but return error + echo master + return 1 } -compdef _git gccd=git-clone - -alias gcl='git clone --recurse-submodules' -alias gclean='git clean -id' -alias gpristine='git reset --hard && git clean -dffx' -alias gcm='git checkout $(git_main_branch)' -alias gcd='git checkout $(git_develop_branch)' -alias gcmsg='git commit -m' -alias gco='git checkout' -alias gcor='git checkout --recurse-submodules' -alias gcount='git shortlog -sn' -alias gcp='git cherry-pick' -alias gcpa='git cherry-pick --abort' -alias gcpc='git cherry-pick --continue' -alias gcs='git commit -S' -alias gcss='git commit -S -s' -alias gcssm='git commit -S -s -m' - -alias gd='git diff' -alias gdca='git diff --cached' -alias gdcw='git diff --cached --word-diff' -alias gdct='git describe --tags $(git rev-list --tags --max-count=1)' -alias gds='git diff --staged' -alias gdt='git diff-tree --no-commit-id --name-only -r' -alias gdup='git diff @{upstream}' -alias gdw='git diff --word-diff' - -function gdnolock() { - git diff "$@" ":(exclude)package-lock.json" ":(exclude)*.lock" -} -compdef _git gdnolock=git-diff - -function gdv() { git diff -w "$@" | view - } -compdef _git gdv=git-diff - -alias gf='git fetch' -# --jobs= was added in git 2.8 -is-at-least 2.8 "$git_version" \ - && alias gfa='git fetch --all --prune --jobs=10' \ - || alias gfa='git fetch --all --prune' -alias gfo='git fetch origin' - -alias gfg='git ls-files | grep' - -alias gg='git gui citool' -alias gga='git gui citool --amend' - -function ggf() { - [[ "$#" != 1 ]] && local b="$(git_current_branch)" - git push --force origin "${b:=$1}" -} -compdef _git ggf=git-checkout -function ggfl() { - [[ "$#" != 1 ]] && local b="$(git_current_branch)" - git push --force-with-lease origin "${b:=$1}" -} -compdef _git ggfl=git-checkout - -function ggl() { - if [[ "$#" != 0 ]] && [[ "$#" != 1 ]]; then - git pull origin "${*}" - else - [[ "$#" == 0 ]] && local b="$(git_current_branch)" - git pull origin "${b:=$1}" - fi -} -compdef _git ggl=git-checkout - -function ggp() { - if [[ "$#" != 0 ]] && [[ "$#" != 1 ]]; then - git push origin "${*}" - else - [[ "$#" == 0 ]] && local b="$(git_current_branch)" - git push origin "${b:=$1}" - fi -} -compdef _git ggp=git-checkout - -function ggpnp() { - if [[ "$#" == 0 ]]; then - ggl && ggp - else - ggl "${*}" && ggp "${*}" - fi -} -compdef _git ggpnp=git-checkout - -function ggu() { - [[ "$#" != 1 ]] && local b="$(git_current_branch)" - git pull --rebase origin "${b:=$1}" -} -compdef _git ggu=git-checkout - -alias ggpur='ggu' -alias ggpull='git pull origin "$(git_current_branch)"' -alias ggpush='git push origin "$(git_current_branch)"' - -alias ggsup='git branch --set-upstream-to=origin/$(git_current_branch)' -alias gpsup='git push --set-upstream origin $(git_current_branch)' - -alias ghh='git help' - -alias gignore='git update-index --assume-unchanged' -alias gignored='git ls-files -v | grep "^[[:lower:]]"' -alias git-svn-dcommit-push='git svn dcommit && git push github $(git_main_branch):svntrunk' - -alias gk='\gitk --all --branches &!' -alias gke='\gitk --all $(git log -g --pretty=%h) &!' - -alias gl='git pull' -alias glg='git log --stat' -alias glgp='git log --stat -p' -alias glgg='git log --graph' -alias glgga='git log --graph --decorate --all' -alias glgm='git log --graph --max-count=10' -alias glo='git log --oneline --decorate' -alias glol="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset'" -alias glols="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --stat" -alias glod="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset'" -alias glods="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset' --date=short" -alias glola="git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset' --all" -alias glog='git log --oneline --decorate --graph' -alias gloga='git log --oneline --decorate --graph --all' -alias glp="_git_log_prettily" - -alias gm='git merge' -alias gmom='git merge origin/$(git_main_branch)' -alias gmtl='git mergetool --no-prompt' -alias gmtlvim='git mergetool --no-prompt --tool=vimdiff' -alias gmum='git merge upstream/$(git_main_branch)' -alias gma='git merge --abort' - -alias gp='git push' -alias gpd='git push --dry-run' -alias gpf='git push --force-with-lease' -alias gpf!='git push --force' -alias gpoat='git push origin --all && git push origin --tags' -alias gpr='git pull --rebase' -alias gpu='git push upstream' -alias gpv='git push -v' - -alias gr='git remote' -alias gra='git remote add' -alias grb='git rebase' -alias grba='git rebase --abort' -alias grbc='git rebase --continue' -alias grbd='git rebase $(git_develop_branch)' -alias grbi='git rebase -i' -alias grbm='git rebase $(git_main_branch)' -alias grbom='git rebase origin/$(git_main_branch)' -alias grbo='git rebase --onto' -alias grbs='git rebase --skip' -alias grev='git revert' -alias grh='git reset' -alias grhh='git reset --hard' -alias groh='git reset origin/$(git_current_branch) --hard' -alias grm='git rm' -alias grmc='git rm --cached' -alias grmv='git remote rename' -alias grrm='git remote remove' -alias grs='git restore' -alias grset='git remote set-url' -alias grss='git restore --source' -alias grst='git restore --staged' -alias grt='cd "$(git rev-parse --show-toplevel || echo .)"' -alias gru='git reset --' -alias grup='git remote update' -alias grv='git remote -v' - -alias gsb='git status -sb' -alias gsd='git svn dcommit' -alias gsh='git show' -alias gsi='git submodule init' -alias gsps='git show --pretty=short --show-signature' -alias gsr='git svn rebase' -alias gss='git status -s' -alias gst='git status' - -# use the default stash push on git 2.13 and newer -is-at-least 2.13 "$git_version" \ - && alias gsta='git stash push' \ - || alias gsta='git stash save' - -alias gstaa='git stash apply' -alias gstc='git stash clear' -alias gstd='git stash drop' -alias gstl='git stash list' -alias gstp='git stash pop' -alias gsts='git stash show --text' -alias gstu='gsta --include-untracked' -alias gstall='git stash --all' -alias gsu='git submodule update' -alias gsw='git switch' -alias gswc='git switch -c' -alias gswm='git switch $(git_main_branch)' -alias gswd='git switch $(git_develop_branch)' - -alias gts='git tag -s' -alias gtv='git tag | sort -V' -alias gtl='gtl(){ git tag --sort=-v:refname -n -l "${1}*" }; noglob gtl' - -alias gunignore='git update-index --no-assume-unchanged' -alias gunwip='git log -n 1 | grep -q -c "\-\-wip\-\-" && git reset HEAD~1' -alias gup='git pull --rebase' -alias gupv='git pull --rebase -v' -alias gupa='git pull --rebase --autostash' -alias gupav='git pull --rebase --autostash -v' -alias gupom='git pull --rebase origin $(git_main_branch)' -alias gupomi='git pull --rebase=interactive origin $(git_main_branch)' -alias glum='git pull upstream $(git_main_branch)' -alias gluc='git pull upstream $(git_current_branch)' - -alias gwch='git whatchanged -p --abbrev-commit --pretty=medium' -alias gwip='git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign -m "--wip-- [skip ci]"' - -alias gam='git am' -alias gamc='git am --continue' -alias gams='git am --skip' -alias gama='git am --abort' -alias gamscp='git am --show-current-patch' function grename() { if [[ -z "$1" || -z "$2" ]]; then @@ -335,4 +63,369 @@ function grename() { fi } +# +# Functions Work in Progress (WIP) +# (sorted alphabetically by function name) +# (order should follow README) +# + +# Similar to `gunwip` but recursive "Unwips" all recent `--wip--` commits not just the last one +function gunwipall() { + local _commit=$(git log --grep='--wip--' --invert-grep --max-count=1 --format=format:%H) + + # Check if a commit without "--wip--" was found and it's not the same as HEAD + if [[ "$_commit" != "$(git rev-parse HEAD)" ]]; then + git reset $_commit || return 1 + fi +} + +# Warn if the current branch is a WIP +function work_in_progress() { + command git -c log.showSignature=false log -n 1 2>/dev/null | grep -q -- "--wip--" && echo "WIP!!" +} + +# +# Aliases +# (sorted alphabetically by command) +# (order should follow README) +# (in some cases force the alias order to match README, like for example gke and gk) +# + +alias grt='cd "$(git rev-parse --show-toplevel || echo .)"' + +function ggpnp() { + if [[ $# == 0 ]]; then + ggl && ggp + else + ggl "${*}" && ggp "${*}" + fi +} +compdef _git ggpnp=git-checkout + +alias ggpur='ggu' +alias g='git' +alias ga='git add' +alias gaa='git add --all' +alias gapa='git add --patch' +alias gau='git add --update' +alias gav='git add --verbose' +alias gwip='git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify --no-gpg-sign --message "--wip-- [skip ci]"' +alias gam='git am' +alias gama='git am --abort' +alias gamc='git am --continue' +alias gamscp='git am --show-current-patch' +alias gams='git am --skip' +alias gap='git apply' +alias gapt='git apply --3way' +alias gbs='git bisect' +alias gbsb='git bisect bad' +alias gbsg='git bisect good' +alias gbsn='git bisect new' +alias gbso='git bisect old' +alias gbsr='git bisect reset' +alias gbss='git bisect start' +alias gbl='git blame -w' +alias gb='git branch' +alias gba='git branch --all' +alias gbd='git branch --delete' +alias gbD='git branch --delete --force' + +function gbda() { + git branch --no-color --merged | command grep -vE "^([+*]|\s*($(git_main_branch)|$(git_develop_branch))\s*$)" | command xargs git branch --delete 2>/dev/null +} + +# Copied and modified from James Roeder (jmaroeder) under MIT License +# https://github.com/jmaroeder/plugin-git/blob/216723ef4f9e8dde399661c39c80bdf73f4076c4/functions/gbda.fish +function gbds() { + local default_branch=$(git_main_branch) + (( ! $? )) || default_branch=$(git_develop_branch) + + git for-each-ref refs/heads/ "--format=%(refname:short)" | \ + while read branch; do + local merge_base=$(git merge-base $default_branch $branch) + if [[ $(git cherry $default_branch $(git commit-tree $(git rev-parse $branch\^{tree}) -p $merge_base -m _)) = -* ]]; then + git branch -D $branch + fi + done +} + +alias gbgd='LANG=C git branch --no-color -vv | grep ": gone\]" | cut -c 3- | awk '"'"'{print $1}'"'"' | xargs git branch -d' +alias gbgD='LANG=C git branch --no-color -vv | grep ": gone\]" | cut -c 3- | awk '"'"'{print $1}'"'"' | xargs git branch -D' +alias gbm='git branch --move' +alias gbnm='git branch --no-merged' +alias gbr='git branch --remote' +alias ggsup='git branch --set-upstream-to=origin/$(git_current_branch)' +alias gbg='LANG=C git branch -vv | grep ": gone\]"' +alias gco='git checkout' +alias gcor='git checkout --recurse-submodules' +alias gcb='git checkout -b' +alias gcB='git checkout -B' +alias gcd='git checkout $(git_develop_branch)' +alias gcm='git checkout $(git_main_branch)' +alias gcp='git cherry-pick' +alias gcpa='git cherry-pick --abort' +alias gcpc='git cherry-pick --continue' +alias gclean='git clean --interactive -d' +alias gcl='git clone --recurse-submodules' +alias gclf='git clone --recursive --shallow-submodules --filter=blob:none --also-filter-submodules' + +function gccd() { + setopt localoptions extendedglob + + # get repo URI from args based on valid formats: https://git-scm.com/docs/git-clone#URLS + local repo="${${@[(r)(ssh://*|git://*|ftp(s)#://*|http(s)#://*|*@*)(.git/#)#]}:-$_}" + + # clone repository and exit if it fails + command git clone --recurse-submodules "$@" || return + + # if last arg passed was a directory, that's where the repo was cloned + # otherwise parse the repo URI and use the last part as the directory + [[ -d "$_" ]] && cd "$_" || cd "${${repo:t}%.git/#}" +} +compdef _git gccd=git-clone + +alias gcam='git commit --all --message' +alias gcas='git commit --all --signoff' +alias gcasm='git commit --all --signoff --message' +alias gcs='git commit --gpg-sign' +alias gcss='git commit --gpg-sign --signoff' +alias gcssm='git commit --gpg-sign --signoff --message' +alias gcmsg='git commit --message' +alias gcsm='git commit --signoff --message' +alias gc='git commit --verbose' +alias gca='git commit --verbose --all' +alias gca!='git commit --verbose --all --amend' +alias gcan!='git commit --verbose --all --no-edit --amend' +alias gcans!='git commit --verbose --all --signoff --no-edit --amend' +alias gcann!='git commit --verbose --all --date=now --no-edit --amend' +alias gc!='git commit --verbose --amend' +alias gcn='git commit --verbose --no-edit' +alias gcn!='git commit --verbose --no-edit --amend' +alias gcf='git config --list' +alias gcfu='git commit --fixup' +alias gdct='git describe --tags $(git rev-list --tags --max-count=1)' +alias gd='git diff' +alias gdca='git diff --cached' +alias gdcw='git diff --cached --word-diff' +alias gds='git diff --staged' +alias gdw='git diff --word-diff' + +function gdv() { git diff -w "$@" | view - } +compdef _git gdv=git-diff + +alias gdup='git diff @{upstream}' + +function gdnolock() { + git diff "$@" ":(exclude)package-lock.json" ":(exclude)*.lock" +} +compdef _git gdnolock=git-diff + +alias gdt='git diff-tree --no-commit-id --name-only -r' +alias gf='git fetch' +# --jobs= was added in git 2.8 +is-at-least 2.8 "$git_version" \ + && alias gfa='git fetch --all --tags --prune --jobs=10' \ + || alias gfa='git fetch --all --tags --prune' +alias gfo='git fetch origin' +alias gg='git gui citool' +alias gga='git gui citool --amend' +alias ghh='git help' +alias glgg='git log --graph' +alias glgga='git log --graph --decorate --all' +alias glgm='git log --graph --max-count=10' +alias glods='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset" --date=short' +alias glod='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset"' +alias glola='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset" --all' +alias glols='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset" --stat' +alias glol='git log --graph --pretty="%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset"' +alias glo='git log --oneline --decorate' +alias glog='git log --oneline --decorate --graph' +alias gloga='git log --oneline --decorate --graph --all' + +# Pretty log messages +function _git_log_prettily(){ + if ! [ -z $1 ]; then + git log --pretty=$1 + fi +} +compdef _git _git_log_prettily=git-log + +alias glp='_git_log_prettily' +alias glg='git log --stat' +alias glgp='git log --stat --patch' +alias gignored='git ls-files -v | grep "^[[:lower:]]"' +alias gfg='git ls-files | grep' +alias gm='git merge' +alias gma='git merge --abort' +alias gmc='git merge --continue' +alias gms="git merge --squash" +alias gmff="git merge --ff-only" +alias gmom='git merge origin/$(git_main_branch)' +alias gmum='git merge upstream/$(git_main_branch)' +alias gmtl='git mergetool --no-prompt' +alias gmtlvim='git mergetool --no-prompt --tool=vimdiff' + +alias gl='git pull' +alias gpr='git pull --rebase' +alias gprv='git pull --rebase -v' +alias gpra='git pull --rebase --autostash' +alias gprav='git pull --rebase --autostash -v' + +function ggu() { + local b + [[ $# != 1 ]] && b="$(git_current_branch)" + git pull --rebase origin "${b:-$1}" +} +compdef _git ggu=git-pull + +alias gprom='git pull --rebase origin $(git_main_branch)' +alias gpromi='git pull --rebase=interactive origin $(git_main_branch)' +alias gprum='git pull --rebase upstream $(git_main_branch)' +alias gprumi='git pull --rebase=interactive upstream $(git_main_branch)' +alias ggpull='git pull origin "$(git_current_branch)"' + +function ggl() { + if [[ $# != 0 ]] && [[ $# != 1 ]]; then + git pull origin "${*}" + else + local b + [[ $# == 0 ]] && b="$(git_current_branch)" + git pull origin "${b:-$1}" + fi +} +compdef _git ggl=git-pull + +alias gluc='git pull upstream $(git_current_branch)' +alias glum='git pull upstream $(git_main_branch)' +alias gp='git push' +alias gpd='git push --dry-run' + +function ggf() { + local b + [[ $# != 1 ]] && b="$(git_current_branch)" + git push --force origin "${b:-$1}" +} +compdef _git ggf=git-push + +alias gpf!='git push --force' +is-at-least 2.30 "$git_version" \ + && alias gpf='git push --force-with-lease --force-if-includes' \ + || alias gpf='git push --force-with-lease' + +function ggfl() { + local b + [[ $# != 1 ]] && b="$(git_current_branch)" + git push --force-with-lease origin "${b:-$1}" +} +compdef _git ggfl=git-push + +alias gpsup='git push --set-upstream origin $(git_current_branch)' +is-at-least 2.30 "$git_version" \ + && alias gpsupf='git push --set-upstream origin $(git_current_branch) --force-with-lease --force-if-includes' \ + || alias gpsupf='git push --set-upstream origin $(git_current_branch) --force-with-lease' +alias gpv='git push --verbose' +alias gpoat='git push origin --all && git push origin --tags' +alias gpod='git push origin --delete' +alias ggpush='git push origin "$(git_current_branch)"' + +function ggp() { + if [[ $# != 0 ]] && [[ $# != 1 ]]; then + git push origin "${*}" + else + local b + [[ $# == 0 ]] && b="$(git_current_branch)" + git push origin "${b:-$1}" + fi +} +compdef _git ggp=git-push + +alias gpu='git push upstream' +alias grb='git rebase' +alias grba='git rebase --abort' +alias grbc='git rebase --continue' +alias grbi='git rebase --interactive' +alias grbo='git rebase --onto' +alias grbs='git rebase --skip' +alias grbd='git rebase $(git_develop_branch)' +alias grbm='git rebase $(git_main_branch)' +alias grbom='git rebase origin/$(git_main_branch)' +alias grbum='git rebase upstream/$(git_main_branch)' +alias grf='git reflog' +alias gr='git remote' +alias grv='git remote --verbose' +alias gra='git remote add' +alias grrm='git remote remove' +alias grmv='git remote rename' +alias grset='git remote set-url' +alias grup='git remote update' +alias grh='git reset' +alias gru='git reset --' +alias grhh='git reset --hard' +alias grhk='git reset --keep' +alias grhs='git reset --soft' +alias gpristine='git reset --hard && git clean --force -dfx' +alias gwipe='git reset --hard && git clean --force -df' +alias groh='git reset origin/$(git_current_branch) --hard' +alias grs='git restore' +alias grss='git restore --source' +alias grst='git restore --staged' +alias gunwip='git rev-list --max-count=1 --format="%s" HEAD | grep -q "\--wip--" && git reset HEAD~1' +alias grev='git revert' +alias greva='git revert --abort' +alias grevc='git revert --continue' +alias grm='git rm' +alias grmc='git rm --cached' +alias gcount='git shortlog --summary --numbered' +alias gsh='git show' +alias gsps='git show --pretty=short --show-signature' +alias gstall='git stash --all' +alias gstaa='git stash apply' +alias gstc='git stash clear' +alias gstd='git stash drop' +alias gstl='git stash list' +alias gstp='git stash pop' +# use the default stash push on git 2.13 and newer +is-at-least 2.13 "$git_version" \ + && alias gsta='git stash push' \ + || alias gsta='git stash save' +alias gsts='git stash show --patch' +alias gst='git status' +alias gss='git status --short' +alias gsb='git status --short --branch' +alias gsi='git submodule init' +alias gsu='git submodule update' +alias gsd='git svn dcommit' +alias git-svn-dcommit-push='git svn dcommit && git push github $(git_main_branch):svntrunk' +alias gsr='git svn rebase' +alias gsw='git switch' +alias gswc='git switch --create' +alias gswd='git switch $(git_develop_branch)' +alias gswm='git switch $(git_main_branch)' +alias gta='git tag --annotate' +alias gts='git tag --sign' +alias gtv='git tag | sort -V' +alias gignore='git update-index --assume-unchanged' +alias gunignore='git update-index --no-assume-unchanged' +alias gwch='git log --patch --abbrev-commit --pretty=medium --raw' +alias gwt='git worktree' +alias gwta='git worktree add' +alias gwtls='git worktree list' +alias gwtmv='git worktree move' +alias gwtrm='git worktree remove' +alias gstu='gsta --include-untracked' +alias gtl='gtl(){ git tag --sort=-v:refname -n --list "${1}*" }; noglob gtl' +alias gk='\gitk --all --branches &!' +alias gke='\gitk --all $(git log --walk-reflogs --pretty=%h) &!' + unset git_version + +# Logic for adding warnings on deprecated aliases or functions +local old_name new_name +for old_name new_name ( + current_branch git_current_branch +); do + aliases[$old_name]=" + print -Pu2 \"%F{yellow}[oh-my-zsh] '%F{red}${old_name}%F{yellow}' is deprecated, using '%F{green}${new_name}%F{yellow}' instead.%f\" + $new_name" +done +unset old_name new_name diff --git a/zsh/plugins/gitfast/MANUAL.adoc b/zsh/plugins/gitfast/MANUAL.adoc new file mode 100644 index 0000000..5333f5a --- /dev/null +++ b/zsh/plugins/gitfast/MANUAL.adoc @@ -0,0 +1,40 @@ +This project is a friendly fork of the official Git completion +(`contrib/completion`) and prompt scripts for Bash, Zsh, and possibly other +shells. + +Most Git developers use the Bash shell, for which the completion scripts work +rather well, however, Zsh is typically neglected. I've sent many patches to fix +the issues, many have been merged, but many have been ignored, thus the need for +a canonical location of a good, working Zsh completion. + +There are advantages for Bash users too. Currently the scripts under `contrib` are tied to the +specific Git version, for example the completion scripts of version v2.40 +(https://git.kernel.org/pub/scm/git/git.git/plain/contrib/completion/git-completion.bash?h=v2.40.0[git-completion.bash]) +have issues with older versions of Git (e.g. v2.33); the ones in +this project don't. + +With `git-completion` you can be sure you are using the latest completion that +works in both shells, and any Git version. + +This is a sister project of the +https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/gitfast[Oh My Zsh +gitfast] plugin (that I also maintain), which has similar needs. + +== Installation == + +* https://github.com/felipec/git-completion/wiki/Bash[Bash instructions] +* https://github.com/felipec/git-completion/wiki/Zsh[Zsh instructions] + +== Improvements from upstream == + +This is a short list of the benefits you get: + +* Easier installation +* Tons of bug fixes +* Works with older versions of git +* Zsh: much more options +* Zsh: quoting works properly +* Zsh: automatic suffix removal + +For a full list of all the patches on top of upstream git check +https://github.com/felipec/git-completion/wiki/Patches[Patches]. diff --git a/zsh/plugins/gitfast/README.md b/zsh/plugins/gitfast/README.md index fed4b12..60b84a2 100644 --- a/zsh/plugins/gitfast/README.md +++ b/zsh/plugins/gitfast/README.md @@ -7,9 +7,3 @@ To use it, add `gitfast` to the plugins array in your zshrc file: ```zsh plugins=(... gitfast) ``` - -## Aliases - -An earlier version of the plugin also loaded the git plugin. If you want to keep those -aliases enable the [git plugin](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/git) -as well. diff --git a/zsh/plugins/gitfast/_git b/zsh/plugins/gitfast/_git index 31bf88c..1283c71 100644 --- a/zsh/plugins/gitfast/_git +++ b/zsh/plugins/gitfast/_git @@ -2,23 +2,11 @@ # zsh completion wrapper for git # -# Copyright (c) 2012-2020 Felipe Contreras +# Copyright (c) 2012-2024 Felipe Contreras # -# The recommended way to install this script is to make a copy of it as a -# file named '_git' inside any directory in your fpath. +# The recommended way to use this script is to prepend its location to your $fpath: # -# For example, create a directory '~/.zsh/', copy this file to '~/.zsh/_git', -# and then add the following to your ~/.zshrc file: -# -# fpath=(~/.zsh $fpath) -# -# You need git's bash completion script installed. By default bash-completion's -# location will be used (e.g. pkg-config --variable=completionsdir bash-completion). -# -# If your bash completion script is somewhere else, you can specify the -# location in your ~/.zshrc: -# -# zstyle ':completion:*:*:git:*' script ~/.git-completion.bash +# fpath=($git_completion_srcdir $fpath) # zstyle -T ':completion:*:*:git:*' tag-order && \ diff --git a/zsh/plugins/gitfast/git-completion.bash b/zsh/plugins/gitfast/git-completion.bash index dd06b50..8a790ca 100644 --- a/zsh/plugins/gitfast/git-completion.bash +++ b/zsh/plugins/gitfast/git-completion.bash @@ -1,6 +1,8 @@ # bash/zsh completion support for core Git. # # Copyright (C) 2006,2007 Shawn O. Pearce +# Copyright (c) 2012-2024 Felipe Contreras +# # Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/). # Distributed under the GNU General Public License, version 2.0. # @@ -58,6 +60,12 @@ # # When set to "1" suggest all options, including options which are # typically hidden (e.g. '--allow-empty' for 'git commit'). +# +# GIT_COMPLETION_IGNORE_CASE +# +# When set, uses for-each-ref '--ignore-case' to find refs that match +# case insensitively, even on systems with case sensitive file systems +# (e.g., completing tag name "FOO" on "git checkout f"). # The following functions are meant to modify COMPREPLY, which should not be # modified directly. The purpose is to localize the modifications so it's @@ -320,116 +328,6 @@ else unset $(compgen -v __gitcomp_builtin_) fi -__gitcomp_builtin_add_default=" --dry-run --verbose --interactive --patch --edit --force --update --renormalize --intent-to-add --all --ignore-removal --refresh --ignore-errors --ignore-missing --sparse --chmod= --pathspec-from-file= --pathspec-file-nul --no-dry-run -- --no-verbose --no-interactive --no-patch --no-edit --no-force --no-update --no-renormalize --no-intent-to-add --no-all --no-ignore-removal --no-refresh --no-ignore-errors --no-ignore-missing --no-sparse --no-chmod --no-pathspec-from-file --no-pathspec-file-nul" -__gitcomp_builtin_am_default=" --interactive --3way --quiet --signoff --utf8 --keep --keep-non-patch --message-id --keep-cr --no-keep-cr --scissors --quoted-cr= --whitespace= --ignore-space-change --ignore-whitespace --directory= --exclude= --include= --patch-format= --reject --resolvemsg= --continue --resolved --skip --abort --quit --show-current-patch --allow-empty --committer-date-is-author-date --ignore-date --rerere-autoupdate --gpg-sign --empty= -- --no-interactive --no-3way --no-quiet --no-signoff --no-utf8 --no-keep --no-keep-non-patch --no-message-id --no-scissors --no-whitespace --no-ignore-space-change --no-ignore-whitespace --no-directory --no-exclude --no-include --no-patch-format --no-reject --no-resolvemsg --no-committer-date-is-author-date --no-ignore-date --no-rerere-autoupdate --no-gpg-sign" -__gitcomp_builtin_apply_default=" --exclude= --include= --no-add --stat --numstat --summary --check --index --intent-to-add --cached --apply --3way --build-fake-ancestor= --whitespace= --ignore-space-change --ignore-whitespace --reverse --unidiff-zero --reject --allow-overlap --verbose --quiet --inaccurate-eof --recount --directory= --allow-empty --add -- --no-stat --no-numstat --no-summary --no-check --no-index --no-intent-to-add --no-cached --no-apply --no-3way --no-build-fake-ancestor --no-whitespace --no-ignore-space-change --no-ignore-whitespace --no-reverse --no-unidiff-zero --no-reject --no-allow-overlap --no-verbose --no-quiet --no-inaccurate-eof --no-recount --no-directory --no-allow-empty" -__gitcomp_builtin_archive_default=" --output= --remote= --exec= --no-output -- --no-remote --no-exec" -__gitcomp_builtin_bisect__helper_default=" --bisect-reset --bisect-next-check --bisect-terms --bisect-start --bisect-next --bisect-state --bisect-log --bisect-replay --bisect-skip --bisect-visualize --bisect-run --no-log --log" -__gitcomp_builtin_blame_default=" --incremental --root --show-stats --progress --score-debug --show-name --show-number --porcelain --line-porcelain --show-email --ignore-rev= --ignore-revs-file= --color-lines --color-by-age --minimal --contents= --abbrev --no-incremental -- --no-root --no-show-stats --no-progress --no-score-debug --no-show-name --no-show-number --no-porcelain --no-line-porcelain --no-show-email --no-ignore-rev --no-ignore-revs-file --no-color-lines --no-color-by-age --no-minimal --no-contents --no-abbrev" -__gitcomp_builtin_branch_default=" --verbose --quiet --track --set-upstream-to= --unset-upstream --color --remotes --contains --no-contains --abbrev --all --delete --move --copy --list --show-current --create-reflog --edit-description --merged --no-merged --column --sort= --points-at= --ignore-case --recurse-submodules --format= -- --no-verbose --no-quiet --no-track --no-set-upstream-to --no-unset-upstream --no-color --no-remotes --no-abbrev --no-all --no-delete --no-move --no-copy --no-list --no-show-current --no-create-reflog --no-edit-description --no-column --no-sort --no-points-at --no-ignore-case --no-recurse-submodules --no-format" -__gitcomp_builtin_bugreport_default=" --output-directory= --suffix= --no-output-directory -- --no-suffix" -__gitcomp_builtin_cat_file_default=" --allow-unknown-type --batch --batch-check --batch-command --batch-all-objects --buffer --follow-symlinks --unordered --textconv --filters --path= --no-allow-unknown-type -- --no-buffer --no-follow-symlinks --no-unordered --no-path" -__gitcomp_builtin_check_attr_default=" --all --cached --stdin --no-all -- --no-cached --no-stdin" -__gitcomp_builtin_check_ignore_default=" --quiet --verbose --stdin --non-matching --no-index --index -- --no-quiet --no-verbose --no-stdin --no-non-matching" -__gitcomp_builtin_check_mailmap_default=" --stdin --no-stdin" -__gitcomp_builtin_checkout_default=" --guess --overlay --quiet --recurse-submodules --progress --merge --conflict= --detach --track --orphan= --ignore-other-worktrees --ours --theirs --patch --ignore-skip-worktree-bits --pathspec-from-file= --pathspec-file-nul --no-guess -- --no-overlay --no-quiet --no-recurse-submodules --no-progress --no-merge --no-conflict --no-detach --no-track --no-orphan --no-ignore-other-worktrees --no-patch --no-ignore-skip-worktree-bits --no-pathspec-from-file --no-pathspec-file-nul" -__gitcomp_builtin_checkout__worker_default=" --prefix= --no-prefix" -__gitcomp_builtin_checkout_index_default=" --all --ignore-skip-worktree-bits --force --quiet --no-create --index --stdin --temp --prefix= --stage= --create -- --no-all --no-ignore-skip-worktree-bits --no-force --no-quiet --no-index --no-stdin --no-temp --no-prefix" -__gitcomp_builtin_cherry_default=" --abbrev --verbose --no-abbrev -- --no-verbose" -__gitcomp_builtin_cherry_pick_default=" --quit --continue --abort --skip --cleanup= --no-commit --edit --signoff --mainline= --rerere-autoupdate --strategy= --strategy-option= --gpg-sign --ff --allow-empty --allow-empty-message --keep-redundant-commits --commit -- --no-cleanup --no-edit --no-signoff --no-mainline --no-rerere-autoupdate --no-strategy --no-strategy-option --no-gpg-sign --no-ff --no-allow-empty --no-allow-empty-message --no-keep-redundant-commits" -__gitcomp_builtin_clean_default=" --quiet --dry-run --interactive --exclude= --no-quiet -- --no-dry-run --no-interactive" -__gitcomp_builtin_clone_default=" --verbose --quiet --progress --reject-shallow --no-checkout --bare --mirror --local --no-hardlinks --shared --recurse-submodules --jobs= --template= --reference= --reference-if-able= --dissociate --origin= --branch= --upload-pack= --depth= --shallow-since= --shallow-exclude= --single-branch --no-tags --shallow-submodules --separate-git-dir= --config= --server-option= --ipv4 --ipv6 --filter= --also-filter-submodules --remote-submodules --sparse --checkout --hardlinks --tags -- --no-verbose --no-quiet --no-progress --no-reject-shallow --no-bare --no-mirror --no-local --no-shared --no-recurse-submodules --no-recursive --no-jobs --no-template --no-reference --no-reference-if-able --no-dissociate --no-origin --no-branch --no-upload-pack --no-depth --no-shallow-since --no-shallow-exclude --no-single-branch --no-shallow-submodules --no-separate-git-dir --no-config --no-server-option --no-ipv4 --no-ipv6 --no-filter --no-also-filter-submodules --no-remote-submodules --no-sparse" -__gitcomp_builtin_column_default=" --command= --mode --raw-mode= --width= --indent= --nl= --padding= --no-command -- --no-mode --no-raw-mode --no-width --no-indent --no-nl --no-padding" -__gitcomp_builtin_commit_default=" --quiet --verbose --file= --author= --date= --message= --reedit-message= --reuse-message= --fixup= --squash= --reset-author --trailer= --signoff --template= --edit --cleanup= --status --gpg-sign --all --include --interactive --patch --only --no-verify --dry-run --short --branch --ahead-behind --porcelain --long --null --amend --no-post-rewrite --untracked-files --pathspec-from-file= --pathspec-file-nul --verify --post-rewrite -- --no-quiet --no-verbose --no-file --no-author --no-date --no-message --no-reedit-message --no-reuse-message --no-fixup --no-squash --no-reset-author --no-signoff --no-template --no-edit --no-cleanup --no-status --no-gpg-sign --no-all --no-include --no-interactive --no-patch --no-only --no-dry-run --no-short --no-branch --no-ahead-behind --no-porcelain --no-long --no-null --no-amend --no-untracked-files --no-pathspec-from-file --no-pathspec-file-nul" -__gitcomp_builtin_commit_graph_default=" --object-dir= --no-object-dir" -__gitcomp_builtin_config_default=" --global --system --local --worktree --file= --blob= --get --get-all --get-regexp --get-urlmatch --replace-all --add --unset --unset-all --rename-section --remove-section --list --fixed-value --edit --get-color --get-colorbool --type= --bool --int --bool-or-int --bool-or-str --path --expiry-date --null --name-only --includes --show-origin --show-scope --default= --no-global -- --no-system --no-local --no-worktree --no-file --no-blob --no-get --no-get-all --no-get-regexp --no-get-urlmatch --no-replace-all --no-add --no-unset --no-unset-all --no-rename-section --no-remove-section --no-list --no-fixed-value --no-edit --no-get-color --no-get-colorbool --no-type --no-null --no-name-only --no-includes --no-show-origin --no-show-scope --no-default" -__gitcomp_builtin_count_objects_default=" --verbose --human-readable --no-verbose -- --no-human-readable" -__gitcomp_builtin_credential_cache_default=" --timeout= --socket= --no-timeout -- --no-socket" -__gitcomp_builtin_credential_cache__daemon_default=" --debug --no-debug" -__gitcomp_builtin_credential_store_default=" --file= --no-file" -__gitcomp_builtin_describe_default=" --contains --debug --all --tags --long --first-parent --abbrev --exact-match --candidates= --match= --exclude= --always --dirty --broken --no-contains -- --no-debug --no-all --no-tags --no-long --no-first-parent --no-abbrev --no-exact-match --no-candidates --no-match --no-exclude --no-always --no-dirty --no-broken" -__gitcomp_builtin_difftool_default=" --gui --dir-diff --no-prompt --symlinks --tool= --tool-help --trust-exit-code --extcmd= --no-index --index -- --no-gui --no-dir-diff --no-symlinks --no-tool --no-tool-help --no-trust-exit-code --no-extcmd" -__gitcomp_builtin_env__helper_default=" --type= --default= --exit-code --no-default -- --no-exit-code" -__gitcomp_builtin_fast_export_default=" --progress= --signed-tags= --tag-of-filtered-object= --reencode= --export-marks= --import-marks= --import-marks-if-exists= --fake-missing-tagger --full-tree --use-done-feature --no-data --refspec= --anonymize --anonymize-map= --reference-excluded-parents --show-original-ids --mark-tags --data -- --no-progress --no-signed-tags --no-tag-of-filtered-object --no-reencode --no-export-marks --no-import-marks --no-import-marks-if-exists --no-fake-missing-tagger --no-full-tree --no-use-done-feature --no-refspec --no-anonymize --no-reference-excluded-parents --no-show-original-ids --no-mark-tags" -__gitcomp_builtin_fetch_default=" --verbose --quiet --all --set-upstream --append --atomic --upload-pack= --force --multiple --tags --jobs= --prefetch --prune --prune-tags --recurse-submodules --dry-run --write-fetch-head --keep --update-head-ok --progress --depth= --shallow-since= --shallow-exclude= --deepen= --unshallow --refetch --update-shallow --refmap= --server-option= --ipv4 --ipv6 --negotiation-tip= --negotiate-only --filter= --auto-maintenance --auto-gc --show-forced-updates --write-commit-graph --stdin --no-verbose -- --no-quiet --no-all --no-set-upstream --no-append --no-atomic --no-upload-pack --no-force --no-multiple --no-tags --no-jobs --no-prefetch --no-prune --no-prune-tags --no-recurse-submodules --no-dry-run --no-write-fetch-head --no-keep --no-update-head-ok --no-progress --no-depth --no-shallow-since --no-shallow-exclude --no-deepen --no-update-shallow --no-server-option --no-ipv4 --no-ipv6 --no-negotiation-tip --no-negotiate-only --no-filter --no-auto-maintenance --no-auto-gc --no-show-forced-updates --no-write-commit-graph --no-stdin" -__gitcomp_builtin_fmt_merge_msg_default=" --log --message= --into-name= --file= --no-log -- --no-message --no-into-name --no-file" -__gitcomp_builtin_for_each_ref_default=" --shell --perl --python --tcl --count= --format= --color --sort= --points-at= --merged --no-merged --contains --no-contains --ignore-case -- --no-shell --no-perl --no-python --no-tcl --no-count --no-format --no-color --no-sort --no-points-at --no-ignore-case" -__gitcomp_builtin_for_each_repo_default=" --config= --no-config" -__gitcomp_builtin_format_patch_default=" --numbered --no-numbered --signoff --stdout --cover-letter --numbered-files --suffix= --start-number= --reroll-count= --filename-max-length= --rfc --cover-from-description= --subject-prefix= --output-directory= --keep-subject --no-binary --zero-commit --ignore-if-in-upstream --no-stat --add-header= --to= --cc= --from --in-reply-to= --attach --inline --thread --signature= --base= --signature-file= --quiet --progress --interdiff= --range-diff= --creation-factor= --binary -- --no-numbered --no-signoff --no-stdout --no-cover-letter --no-numbered-files --no-suffix --no-start-number --no-reroll-count --no-filename-max-length --no-cover-from-description --no-zero-commit --no-ignore-if-in-upstream --no-add-header --no-to --no-cc --no-from --no-in-reply-to --no-attach --no-thread --no-signature --no-base --no-signature-file --no-quiet --no-progress --no-interdiff --no-range-diff --no-creation-factor" -__gitcomp_builtin_fsck_default=" --verbose --unreachable --dangling --tags --root --cache --reflogs --full --connectivity-only --strict --lost-found --progress --name-objects --no-verbose -- --no-unreachable --no-dangling --no-tags --no-root --no-cache --no-reflogs --no-full --no-connectivity-only --no-strict --no-lost-found --no-progress --no-name-objects" -__gitcomp_builtin_fsck_objects_default=" --verbose --unreachable --dangling --tags --root --cache --reflogs --full --connectivity-only --strict --lost-found --progress --name-objects --no-verbose -- --no-unreachable --no-dangling --no-tags --no-root --no-cache --no-reflogs --no-full --no-connectivity-only --no-strict --no-lost-found --no-progress --no-name-objects" -__gitcomp_builtin_fsmonitor__daemon_default="" -__gitcomp_builtin_gc_default=" --quiet --prune --aggressive --keep-largest-pack --no-quiet -- --no-prune --no-aggressive --no-keep-largest-pack" -__gitcomp_builtin_grep_default=" --cached --no-index --untracked --exclude-standard --recurse-submodules --invert-match --ignore-case --word-regexp --text --textconv --recursive --max-depth= --extended-regexp --basic-regexp --fixed-strings --perl-regexp --line-number --column --full-name --files-with-matches --name-only --files-without-match --only-matching --count --color --break --heading --context= --before-context= --after-context= --threads= --show-function --function-context --and --or --not --quiet --all-match --index -- --no-cached --no-untracked --no-exclude-standard --no-recurse-submodules --no-invert-match --no-ignore-case --no-word-regexp --no-text --no-textconv --no-recursive --no-extended-regexp --no-basic-regexp --no-fixed-strings --no-perl-regexp --no-line-number --no-column --no-full-name --no-files-with-matches --no-name-only --no-files-without-match --no-only-matching --no-count --no-color --no-break --no-heading --no-context --no-before-context --no-after-context --no-threads --no-show-function --no-function-context --no-or --no-quiet --no-all-match" -__gitcomp_builtin_hash_object_default=" --stdin --stdin-paths --no-filters --literally --path= --filters -- --no-stdin --no-stdin-paths --no-literally --no-path" -__gitcomp_builtin_help_default=" --all --external-commands --aliases --man --web --info --verbose --guides --config --no-external-commands -- --no-aliases --no-man --no-web --no-info --no-verbose" -__gitcomp_builtin_hook_default="" -__gitcomp_builtin_init_default=" --template= --bare --shared --quiet --separate-git-dir= --initial-branch= --object-format= --no-template -- --no-bare --no-quiet --no-separate-git-dir --no-initial-branch --no-object-format" -__gitcomp_builtin_init_db_default=" --template= --bare --shared --quiet --separate-git-dir= --initial-branch= --object-format= --no-template -- --no-bare --no-quiet --no-separate-git-dir --no-initial-branch --no-object-format" -__gitcomp_builtin_interpret_trailers_default=" --in-place --trim-empty --where= --if-exists= --if-missing= --only-trailers --only-input --unfold --parse --no-divider --trailer= --divider -- --no-in-place --no-trim-empty --no-where --no-if-exists --no-if-missing --no-only-trailers --no-only-input --no-unfold --no-trailer" -__gitcomp_builtin_log_default=" --quiet --source --use-mailmap --decorate-refs= --decorate-refs-exclude= --decorate --no-quiet -- --no-source --no-use-mailmap --no-mailmap --no-decorate-refs --no-decorate-refs-exclude --no-decorate" -__gitcomp_builtin_ls_files_default=" --cached --deleted --modified --others --ignored --stage --killed --directory --eol --empty-directory --unmerged --resolve-undo --exclude= --exclude-from= --exclude-per-directory= --exclude-standard --full-name --recurse-submodules --error-unmatch --with-tree= --abbrev --debug --deduplicate --sparse --no-cached -- --no-deleted --no-modified --no-others --no-ignored --no-stage --no-killed --no-directory --no-eol --no-empty-directory --no-unmerged --no-resolve-undo --no-exclude-per-directory --no-recurse-submodules --no-error-unmatch --no-with-tree --no-abbrev --no-debug --no-deduplicate --no-sparse" -__gitcomp_builtin_ls_remote_default=" --quiet --upload-pack= --tags --heads --refs --get-url --sort= --symref --server-option= --no-quiet -- --no-upload-pack --no-tags --no-heads --no-refs --no-get-url --no-sort --no-symref --no-server-option" -__gitcomp_builtin_ls_tree_default=" --long --name-only --name-status --object-only --full-name --full-tree --format= --abbrev --no-full-name -- --no-full-tree --no-abbrev" -__gitcomp_builtin_merge_default=" --stat --summary --log --squash --commit --edit --cleanup= --ff --ff-only --rerere-autoupdate --verify-signatures --strategy= --strategy-option= --message= --file --into-name= --verbose --quiet --abort --quit --continue --allow-unrelated-histories --progress --gpg-sign --autostash --overwrite-ignore --signoff --no-verify --verify -- --no-stat --no-summary --no-log --no-squash --no-commit --no-edit --no-cleanup --no-ff --no-rerere-autoupdate --no-verify-signatures --no-strategy --no-strategy-option --no-message --no-into-name --no-verbose --no-quiet --no-abort --no-quit --no-continue --no-allow-unrelated-histories --no-progress --no-gpg-sign --no-autostash --no-overwrite-ignore --no-signoff" -__gitcomp_builtin_merge_base_default=" --all --octopus --independent --is-ancestor --fork-point --no-all" -__gitcomp_builtin_merge_file_default=" --stdout --diff3 --zdiff3 --ours --theirs --union --marker-size= --quiet --no-stdout -- --no-diff3 --no-zdiff3 --no-ours --no-theirs --no-union --no-marker-size --no-quiet" -__gitcomp_builtin_mktree_default=" --missing --batch --no-missing -- --no-batch" -__gitcomp_builtin_multi_pack_index_default=" --object-dir= --no-object-dir" -__gitcomp_builtin_mv_default=" --verbose --dry-run --sparse --no-verbose -- --no-dry-run --no-sparse" -__gitcomp_builtin_name_rev_default=" --name-only --tags --refs= --exclude= --all --stdin --annotate-stdin --undefined --always --no-name-only -- --no-tags --no-refs --no-exclude --no-all --no-stdin --no-annotate-stdin --no-undefined --no-always" -__gitcomp_builtin_notes_default=" --ref= --no-ref" -__gitcomp_builtin_pack_objects_default=" --quiet --progress --all-progress --all-progress-implied --index-version= --max-pack-size= --local --incremental --window= --window-memory= --depth= --reuse-delta --reuse-object --delta-base-offset --threads= --non-empty --revs --unpacked --all --reflog --indexed-objects --stdin-packs --stdout --include-tag --keep-unreachable --pack-loose-unreachable --unpack-unreachable --sparse --thin --shallow --honor-pack-keep --keep-pack= --compression= --keep-true-parents --use-bitmap-index --write-bitmap-index --filter= --missing= --exclude-promisor-objects --delta-islands --uri-protocol= --no-quiet -- --no-progress --no-all-progress --no-all-progress-implied --no-local --no-incremental --no-window --no-depth --no-reuse-delta --no-reuse-object --no-delta-base-offset --no-threads --no-non-empty --no-revs --no-stdin-packs --no-stdout --no-include-tag --no-keep-unreachable --no-pack-loose-unreachable --no-unpack-unreachable --no-sparse --no-thin --no-shallow --no-honor-pack-keep --no-keep-pack --no-compression --no-keep-true-parents --no-use-bitmap-index --no-write-bitmap-index --no-filter --no-exclude-promisor-objects --no-delta-islands --no-uri-protocol" -__gitcomp_builtin_pack_refs_default=" --all --prune --no-all -- --no-prune" -__gitcomp_builtin_pickaxe_default=" --incremental --root --show-stats --progress --score-debug --show-name --show-number --porcelain --line-porcelain --show-email --ignore-rev= --ignore-revs-file= --color-lines --color-by-age --minimal --contents= --abbrev --no-incremental -- --no-root --no-show-stats --no-progress --no-score-debug --no-show-name --no-show-number --no-porcelain --no-line-porcelain --no-show-email --no-ignore-rev --no-ignore-revs-file --no-color-lines --no-color-by-age --no-minimal --no-contents --no-abbrev" -__gitcomp_builtin_prune_default=" --dry-run --verbose --progress --expire= --exclude-promisor-objects --no-dry-run -- --no-verbose --no-progress --no-expire --no-exclude-promisor-objects" -__gitcomp_builtin_prune_packed_default=" --dry-run --quiet --no-dry-run -- --no-quiet" -__gitcomp_builtin_pull_default=" --verbose --quiet --progress --recurse-submodules --rebase --stat --log --signoff --squash --commit --edit --cleanup= --ff --ff-only --verify --verify-signatures --autostash --strategy= --strategy-option= --gpg-sign --allow-unrelated-histories --all --append --upload-pack= --force --tags --prune --jobs --dry-run --keep --depth= --shallow-since= --shallow-exclude= --deepen= --unshallow --update-shallow --refmap= --server-option= --ipv4 --ipv6 --negotiation-tip= --show-forced-updates --set-upstream --no-verbose -- --no-quiet --no-progress --no-recurse-submodules --no-rebase --no-stat --no-log --no-signoff --no-squash --no-commit --no-edit --no-cleanup --no-ff --no-verify --no-verify-signatures --no-autostash --no-strategy --no-strategy-option --no-gpg-sign --no-allow-unrelated-histories --no-all --no-append --no-upload-pack --no-force --no-tags --no-prune --no-jobs --no-dry-run --no-keep --no-depth --no-shallow-since --no-shallow-exclude --no-deepen --no-update-shallow --no-server-option --no-ipv4 --no-ipv6 --no-negotiation-tip --no-show-forced-updates --no-set-upstream" -__gitcomp_builtin_push_default=" --verbose --quiet --repo= --all --mirror --delete --tags --dry-run --porcelain --force --force-with-lease --force-if-includes --recurse-submodules= --receive-pack= --exec= --set-upstream --progress --prune --no-verify --follow-tags --signed --atomic --push-option= --ipv4 --ipv6 --verify -- --no-verbose --no-quiet --no-repo --no-all --no-mirror --no-delete --no-tags --no-dry-run --no-porcelain --no-force --no-force-with-lease --no-force-if-includes --no-recurse-submodules --no-receive-pack --no-exec --no-set-upstream --no-progress --no-prune --no-follow-tags --no-signed --no-atomic --no-push-option --no-ipv4 --no-ipv6" -__gitcomp_builtin_range_diff_default=" --creation-factor= --no-dual-color --notes --left-only --right-only --patch --no-patch --unified --function-context --raw --patch-with-raw --patch-with-stat --numstat --shortstat --dirstat --cumulative --dirstat-by-file --check --summary --name-only --name-status --stat --stat-width= --stat-name-width= --stat-graph-width= --stat-count= --compact-summary --binary --full-index --color --ws-error-highlight= --abbrev --src-prefix= --dst-prefix= --line-prefix= --no-prefix --inter-hunk-context= --output-indicator-new= --output-indicator-old= --output-indicator-context= --break-rewrites --find-renames --irreversible-delete --find-copies --find-copies-harder --no-renames --rename-empty --follow --minimal --ignore-all-space --ignore-space-change --ignore-space-at-eol --ignore-cr-at-eol --ignore-blank-lines --ignore-matching-lines= --indent-heuristic --patience --histogram --diff-algorithm= --anchored= --word-diff --word-diff-regex= --color-words --color-moved --color-moved-ws= --relative --text --exit-code --quiet --ext-diff --textconv --ignore-submodules --submodule --ita-invisible-in-index --ita-visible-in-index --pickaxe-all --pickaxe-regex --rotate-to= --skip-to= --find-object= --diff-filter= --output= --dual-color -- --no-creation-factor --no-notes --no-left-only --no-right-only --no-function-context --no-compact-summary --no-full-index --no-color --no-abbrev --no-find-copies-harder --no-rename-empty --no-follow --no-minimal --no-ignore-matching-lines --no-indent-heuristic --no-color-moved --no-color-moved-ws --no-relative --no-text --no-exit-code --no-quiet --no-ext-diff --no-textconv" -__gitcomp_builtin_read_tree_default=" --index-output= --empty --verbose --trivial --aggressive --reset --prefix= --exclude-per-directory= --dry-run --no-sparse-checkout --debug-unpack --recurse-submodules --quiet --sparse-checkout -- --no-empty --no-verbose --no-trivial --no-aggressive --no-reset --no-dry-run --no-debug-unpack --no-recurse-submodules --no-quiet" -__gitcomp_builtin_rebase_default=" --onto= --keep-base --no-verify --quiet --verbose --no-stat --signoff --committer-date-is-author-date --reset-author-date --ignore-whitespace --whitespace= --force-rebase --no-ff --continue --skip --abort --quit --edit-todo --show-current-patch --apply --merge --interactive --rerere-autoupdate --empty= --autosquash --gpg-sign --autostash --exec= --rebase-merges --fork-point --strategy= --strategy-option= --root --reschedule-failed-exec --reapply-cherry-picks --verify --stat --ff -- --no-onto --no-keep-base --no-quiet --no-verbose --no-signoff --no-committer-date-is-author-date --no-reset-author-date --no-ignore-whitespace --no-whitespace --no-force-rebase --no-rerere-autoupdate --no-autosquash --no-gpg-sign --no-autostash --no-exec --no-rebase-merges --no-fork-point --no-strategy --no-strategy-option --no-root --no-reschedule-failed-exec --no-reapply-cherry-picks" -__gitcomp_builtin_receive_pack_default=" --quiet --no-quiet" -__gitcomp_builtin_reflog_default="" -__gitcomp_builtin_remote_default=" --verbose --no-verbose" -__gitcomp_builtin_repack_default=" --quiet --local --write-bitmap-index --delta-islands --unpack-unreachable= --keep-unreachable --window= --window-memory= --depth= --threads= --max-pack-size= --pack-kept-objects --keep-pack= --geometric= --write-midx --no-quiet -- --no-local --no-write-bitmap-index --no-delta-islands --no-unpack-unreachable --no-keep-unreachable --no-window --no-window-memory --no-depth --no-threads --no-max-pack-size --no-pack-kept-objects --no-keep-pack --no-geometric --no-write-midx" -__gitcomp_builtin_replace_default=" --list --delete --edit --graft --convert-graft-file --raw --format= --no-raw -- --no-format" -__gitcomp_builtin_rerere_default=" --rerere-autoupdate --no-rerere-autoupdate" -__gitcomp_builtin_reset_default=" --quiet --no-refresh --mixed --soft --hard --merge --keep --recurse-submodules --patch --intent-to-add --pathspec-from-file= --pathspec-file-nul --refresh -- --no-quiet --no-mixed --no-soft --no-hard --no-merge --no-keep --no-recurse-submodules --no-patch --no-intent-to-add --no-pathspec-from-file --no-pathspec-file-nul" -__gitcomp_builtin_restore_default=" --source= --staged --worktree --ignore-unmerged --overlay --quiet --recurse-submodules --progress --merge --conflict= --ours --theirs --patch --ignore-skip-worktree-bits --pathspec-from-file= --pathspec-file-nul --no-source -- --no-staged --no-worktree --no-ignore-unmerged --no-overlay --no-quiet --no-recurse-submodules --no-progress --no-merge --no-conflict --no-patch --no-ignore-skip-worktree-bits --no-pathspec-from-file --no-pathspec-file-nul" -__gitcomp_builtin_revert_default=" --quit --continue --abort --skip --cleanup= --no-commit --edit --signoff --mainline= --rerere-autoupdate --strategy= --strategy-option= --gpg-sign --commit -- --no-cleanup --no-edit --no-signoff --no-mainline --no-rerere-autoupdate --no-strategy --no-strategy-option --no-gpg-sign" -__gitcomp_builtin_rm_default=" --dry-run --quiet --cached --ignore-unmatch --sparse --pathspec-from-file= --pathspec-file-nul --no-dry-run -- --no-quiet --no-cached --no-ignore-unmatch --no-sparse --no-pathspec-from-file --no-pathspec-file-nul" -__gitcomp_builtin_send_pack_default=" --verbose --quiet --receive-pack= --exec= --remote= --all --dry-run --mirror --force --signed --push-option= --progress --thin --atomic --stateless-rpc --stdin --helper-status --force-with-lease --force-if-includes --no-verbose -- --no-quiet --no-receive-pack --no-exec --no-remote --no-all --no-dry-run --no-mirror --no-force --no-signed --no-push-option --no-progress --no-thin --no-atomic --no-stateless-rpc --no-stdin --no-helper-status --no-force-with-lease --no-force-if-includes" -__gitcomp_builtin_shortlog_default=" --committer --numbered --summary --email --group= --no-committer -- --no-numbered --no-summary --no-email --no-group" -__gitcomp_builtin_show_default=" --quiet --source --use-mailmap --decorate-refs= --decorate-refs-exclude= --decorate --no-quiet -- --no-source --no-use-mailmap --no-mailmap --no-decorate-refs --no-decorate-refs-exclude --no-decorate" -__gitcomp_builtin_show_branch_default=" --all --remotes --color --more --list --no-name --current --sha1-name --merge-base --independent --topo-order --topics --sparse --date-order --reflog --name -- --no-all --no-remotes --no-color --no-more --no-list --no-current --no-sha1-name --no-merge-base --no-independent --no-topo-order --no-topics --no-sparse --no-date-order" -__gitcomp_builtin_show_index_default=" --object-format= --no-object-format" -__gitcomp_builtin_show_ref_default=" --tags --heads --verify --head --dereference --hash --abbrev --quiet --exclude-existing --no-tags -- --no-heads --no-verify --no-head --no-dereference --no-hash --no-abbrev --no-quiet" -__gitcomp_builtin_sparse_checkout_default="" -__gitcomp_builtin_stage_default=" --dry-run --verbose --interactive --patch --edit --force --update --renormalize --intent-to-add --all --ignore-removal --refresh --ignore-errors --ignore-missing --sparse --chmod= --pathspec-from-file= --pathspec-file-nul --no-dry-run -- --no-verbose --no-interactive --no-patch --no-edit --no-force --no-update --no-renormalize --no-intent-to-add --no-all --no-ignore-removal --no-refresh --no-ignore-errors --no-ignore-missing --no-sparse --no-chmod --no-pathspec-from-file --no-pathspec-file-nul" -__gitcomp_builtin_stash_default="" -__gitcomp_builtin_status_default=" --verbose --short --branch --show-stash --ahead-behind --porcelain --long --null --untracked-files --ignored --ignore-submodules --column --no-renames --find-renames --renames -- --no-verbose --no-short --no-branch --no-show-stash --no-ahead-behind --no-porcelain --no-long --no-null --no-untracked-files --no-ignored --no-ignore-submodules --no-column" -__gitcomp_builtin_stripspace_default=" --strip-comments --comment-lines" -__gitcomp_builtin_switch_default=" --create= --force-create= --guess --discard-changes --quiet --recurse-submodules --progress --merge --conflict= --detach --track --orphan= --ignore-other-worktrees --no-create -- --no-force-create --no-guess --no-discard-changes --no-quiet --no-recurse-submodules --no-progress --no-merge --no-conflict --no-detach --no-track --no-orphan --no-ignore-other-worktrees" -__gitcomp_builtin_symbolic_ref_default=" --quiet --delete --short --no-quiet -- --no-delete --no-short" -__gitcomp_builtin_tag_default=" --list --delete --verify --annotate --message= --file= --edit --sign --cleanup= --local-user= --force --create-reflog --column --contains --no-contains --merged --no-merged --sort= --points-at --format= --color --ignore-case -- --no-annotate --no-file --no-edit --no-sign --no-cleanup --no-local-user --no-force --no-create-reflog --no-column --no-sort --no-points-at --no-format --no-color --no-ignore-case" -__gitcomp_builtin_update_index_default=" --ignore-submodules --add --replace --remove --unmerged --refresh --really-refresh --cacheinfo --chmod= --assume-unchanged --no-assume-unchanged --skip-worktree --no-skip-worktree --ignore-skip-worktree-entries --info-only --force-remove --stdin --index-info --unresolve --again --ignore-missing --verbose --clear-resolve-undo --index-version= --split-index --untracked-cache --test-untracked-cache --force-untracked-cache --force-write-index --fsmonitor --fsmonitor-valid --no-fsmonitor-valid -- --no-ignore-submodules --no-add --no-replace --no-remove --no-unmerged --no-ignore-skip-worktree-entries --no-info-only --no-force-remove --no-ignore-missing --no-verbose --no-index-version --no-split-index --no-untracked-cache --no-test-untracked-cache --no-force-untracked-cache --no-force-write-index --no-fsmonitor" -__gitcomp_builtin_update_ref_default=" --no-deref --stdin --create-reflog --deref -- --no-stdin --no-create-reflog" -__gitcomp_builtin_update_server_info_default=" --force --no-force" -__gitcomp_builtin_upload_pack_default=" --stateless-rpc --strict --timeout= --no-stateless-rpc -- --no-strict --no-timeout" -__gitcomp_builtin_verify_commit_default=" --verbose --raw --no-verbose -- --no-raw" -__gitcomp_builtin_verify_pack_default=" --verbose --stat-only --object-format= --no-verbose -- --no-stat-only --no-object-format" -__gitcomp_builtin_verify_tag_default=" --verbose --raw --format= --no-verbose -- --no-raw --no-format" -__gitcomp_builtin_version_default=" --build-options --no-build-options" -__gitcomp_builtin_whatchanged_default=" --quiet --source --use-mailmap --decorate-refs= --decorate-refs-exclude= --decorate --no-quiet -- --no-source --no-use-mailmap --no-mailmap --no-decorate-refs --no-decorate-refs-exclude --no-decorate" -__gitcomp_builtin_write_tree_default=" --missing-ok --prefix= --no-missing-ok -- --no-prefix" -__gitcomp_builtin_send_email_default="--sender= --from= --smtp-auth= --8bit-encoding= --no-format-patch --no-bcc --no-suppress-from --no-annotate --relogin-delay= --no-cc --no-signed-off-cc --no-signed-off-by-cc --no-chain-reply-to --smtp-debug= --smtp-domain= --chain-reply-to --dry-run --compose --bcc= --smtp-user= --thread --cc-cover --identity= --to= --reply-to= --no-cc-cover --suppress-cc= --to-cmd= --smtp-server= --smtp-ssl-cert-path= --no-thread --smtp-server-option= --quiet --batch-size= --envelope-sender= --smtp-ssl --no-to --validate --format-patch --suppress-from --cc= --compose-encoding= --to-cover --in-reply-to= --annotate --smtp-encryption= --cc-cmd= --smtp-server-port= --smtp-pass= --signed-off-cc --signed-off-by-cc --no-xmailer --subject= --no-to-cover --confirm= --transfer-encoding= --no-smtp-auth --sendmail-cmd= --no-validate --no-identity --dump-aliases --xmailer --force --numbered --no-numbered --signoff --stdout --cover-letter --numbered-files --suffix= --start-number= --reroll-count= --filename-max-length= --rfc --cover-from-description= --subject-prefix= --output-directory= --keep-subject --no-binary --zero-commit --ignore-if-in-upstream --no-stat --add-header= --from --attach --inline --signature= --base= --signature-file= --progress --interdiff= --range-diff= --creation-factor= --binary -- --no-signoff --no-stdout --no-cover-letter --no-numbered-files --no-suffix --no-start-number --no-reroll-count --no-filename-max-length --no-cover-from-description --no-zero-commit --no-ignore-if-in-upstream --no-add-header --no-from --no-in-reply-to --no-attach --no-signature --no-base --no-signature-file --no-quiet --no-progress --no-interdiff --no-range-diff --no-creation-factor" - -__gitcomp_builtin_get_default () -{ - eval "test -n \"\$${1}_default\" && echo \"\$${1}_default\"" -} - # This function is equivalent to # # __gitcomp_opts "$(git xxx --git-completion-helper) ..." @@ -457,11 +355,9 @@ __gitcomp_builtin () else completion_helper="--git-completion-helper" fi - completion="$(__git ${cmd/_/ } $completion_helper || - __gitcomp_builtin_get_default $var)" || return # leading and trailing spaces are significant to make # option removal work correctly. - options=" $incl $completion " + options=" $incl $(__git ${cmd/_/ } $completion_helper) " || return for i in $excl; do options="${options/ $i / }" @@ -604,6 +500,7 @@ __git_heads () local pfx="${1-}" cur_="${2-}" sfx="${3-}" __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ "refs/heads/$cur_*" "refs/heads/$cur_*/**" } @@ -617,6 +514,7 @@ __git_remote_heads () local pfx="${1-}" cur_="${2-}" sfx="${3-}" __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ "refs/remotes/$cur_*" "refs/remotes/$cur_*/**" } @@ -627,6 +525,7 @@ __git_tags () local pfx="${1-}" cur_="${2-}" sfx="${3-}" __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ "refs/tags/$cur_*" "refs/tags/$cur_*/**" } @@ -646,6 +545,7 @@ __git_dwim_remote_heads () # but only output if the branch name is unique __git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \ --sort="refname:strip=3" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ "refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \ uniq -u } @@ -670,6 +570,7 @@ __git_refs () local format refs local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}" local match="${4-}" + local umatch="${4-}" local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers __git_find_repo_path @@ -693,12 +594,19 @@ __git_refs () fi fi + if test "${GIT_COMPLETION_IGNORE_CASE:+1}" = "1" + then + # uppercase with tr instead of ${match,^^} for bash 3.2 compatibility + umatch=$(echo "$match" | tr a-z A-Z 2>/dev/null || echo "$match") + fi + if [ "$list_refs_from" = path ]; then if [[ "$cur_" == ^* ]]; then pfx="$pfx^" fer_pfx="$fer_pfx^" cur_=${cur_#^} match=${match#^} + umatch=${umatch#^} fi case "$cur_" in refs|refs/*) @@ -709,7 +617,7 @@ __git_refs () *) for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do case "$i" in - $match*) + $match*|$umatch*) if [ -e "$dir/$i" ]; then echo "$pfx$i$sfx" fi @@ -723,6 +631,7 @@ __git_refs () ;; esac __git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ "${refs[@]}" if [ -n "$track" ]; then __git_dwim_remote_heads "$pfx" "$match" "$sfx" @@ -742,15 +651,16 @@ __git_refs () *) if [ "$list_refs_from" = remote ]; then case "HEAD" in - $match*) echo "${pfx}HEAD$sfx" ;; + $match*|$umatch*) echo "${pfx}HEAD$sfx" ;; esac __git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ "refs/remotes/$remote/$match*" \ "refs/remotes/$remote/$match*/**" else local query_symref case "HEAD" in - $match*) query_symref="HEAD" ;; + $match*|$umatch*) query_symref="HEAD" ;; esac __git ls-remote "$remote" $query_symref \ "refs/tags/$match*" "refs/heads/$match*" \ @@ -888,7 +798,6 @@ __git_list_merge_strategies () }' } -__git_merge_strategies_default='octopus ours recursive resolve subtree' __git_merge_strategies= # 'git merge -s help' (and thus detection of the merge strategy # list) fails, unfortunately, if run outside of any git working @@ -898,8 +807,7 @@ __git_merge_strategies= __git_compute_merge_strategies () { test -n "$__git_merge_strategies" || - { __git_merge_strategies=$(__git_list_merge_strategies); - __git_merge_strategies="${__git_merge_strategies:-__git_merge_strategies_default}"; } + __git_merge_strategies=$(__git_list_merge_strategies) } __git_merge_strategy_options="ours theirs subtree subtree= patience @@ -2281,7 +2189,7 @@ _git_reflog () fi } -__git_send_email_options="--no-cc-cover --cc= --no-bcc --force --relogin-delay= --to= --suppress-cc= --no-annotate --no-chain-reply-to --sendmail-cmd= --no-identity --transfer-encoding= --validate --no-smtp-auth --confirm= --no-format-patch --reply-to= --smtp-pass= --smtp-server= --annotate --envelope-sender= --no-validate --dry-run --no-thread --smtp-debug= --no-to --thread --no-xmailer --identity= --no-signed-off-cc --no-signed-off-by-cc --smtp-domain= --to-cover --8bit-encoding= --bcc= --smtp-ssl-cert-path= --smtp-user= --cc-cmd= --to-cmd= --no-cc --smtp-server-option= --in-reply-to= --subject= --batch-size= --smtp-auth= --compose --smtp-server-port= --xmailer --no-to-cover --chain-reply-to --smtp-encryption= --dump-aliases --quiet --smtp-ssl --signed-off-cc --signed-off-by-cc --suppress-from --compose-encoding= --no-suppress-from --sender= --from= --format-patch --cc-cover --numbered --no-numbered --signoff --stdout --cover-letter --numbered-files --suffix= --start-number= --reroll-count= --filename-max-length= --rfc --cover-from-description= --subject-prefix= --output-directory= --keep-subject --no-binary --zero-commit --ignore-if-in-upstream --no-stat --add-header= --from --attach --inline --signature= --base= --signature-file= --progress --interdiff= --range-diff= --creation-factor= --binary -- --no-signoff --no-stdout --no-cover-letter --no-numbered-files --no-suffix --no-start-number --no-reroll-count --no-filename-max-length --no-cover-from-description --no-zero-commit --no-ignore-if-in-upstream --no-add-header --no-from --no-in-reply-to --no-attach --no-signature --no-base --no-signature-file --no-quiet --no-progress --no-interdiff --no-range-diff --no-creation-factor" +__gitcomp_builtin_send_email_default="--8bit-encoding= --add-header= --annotate --attach --base= --batch-size= --bcc= --binary --cc-cmd= --cc-cover --cc= --chain-reply-to --compose --compose-encoding= --confirm= --cover-from-description= --cover-letter --creation-factor= --dry-run --dump-aliases --envelope-sender= --filename-max-length= --force --force-in-body-from --format-patch --from --from= --identity= --ignore-if-in-upstream --in-reply-to= --inline --interdiff= --keep-subject --numbered --numbered-files --output-directory= --progress --quiet --range-diff= --relogin-delay= --reply-to= --reroll-count= --rfc --sender= --sendmail-cmd= --signature-file= --signature= --signed-off-by-cc --signed-off-cc --signoff --smtp-auth= --smtp-debug= --smtp-domain= --smtp-encryption= --smtp-pass= --smtp-server-option= --smtp-server-port= --smtp-server= --smtp-ssl --smtp-ssl-cert-path= --smtp-user= --start-number= --stdout --subject-prefix= --subject= --suffix= --suppress-cc= --suppress-from --thread --to-cmd= --to-cover --to= --transfer-encoding= --v= --validate --xmailer --zero-commit -- --no-add-header --no-annotate --no-attach --no-base --no-bcc --no-binary --no-cc --no-cc-cover --no-chain-reply-to --no-cover-from-description --no-cover-letter --no-creation-factor --no-filename-max-length --no-force-in-body-from --no-format-patch --no-from --no-identity --no-ignore-if-in-upstream --no-in-reply-to --no-interdiff --no-numbered --no-numbered-files --no-progress --no-quiet --no-range-diff --no-reroll-count --no-signature --no-signature-file --no-signed-off-by-cc --no-signed-off-cc --no-signoff --no-smtp-auth --no-start-number --no-stat --no-stdout --no-suffix --no-suppress-from --no-thread --no-to --no-to-cover --no-validate --no-xmailer --no-zero-commit" __git_send_email_confirm_options="always never auto cc compose" __git_send_email_suppresscc_options="author self cc bodycc sob cccmd body all" @@ -2321,7 +2229,11 @@ _git_send_email () return ;; --*) - __gitcomp_builtin send-email "$__git_send_email_options $__git_format_patch_extra_options" + # Older versions of git send-email don't have all the options + git send-email --git-completion-helper | grep -q annotate || + __gitcomp_builtin_send_email=$__gitcomp_builtin_send_email_default + + __gitcomp_builtin send-email "$__git_format_patch_extra_options" return ;; esac @@ -2456,7 +2368,25 @@ __git_config_vars= __git_compute_config_vars () { test -n "$__git_config_vars" || - __git_config_vars="$(git help --config-for-completion | sort -u)" + __git_config_vars="$(git help --config-for-completion)" +} + +__git_compute_config_sections_old () +{ + __git_compute_config_vars + echo "$__git_config_vars" | + awk -F . '{ dict[$1] = 1 } END { for (e in dict) print e }' +} + +__git_config_sections= +__git_compute_config_sections () +{ + test -n "$__git_config_sections" || + __git_config_sections="$( + git help --config-sections-for-completion > /dev/null 2>&1 && + git help --config-sections-for-completion || + __git_compute_config_sections_old + )" } # Completes possible values of various configuration variables. @@ -2670,16 +2600,8 @@ __git_complete_config_variable_name () __gitcomp "$__git_config_vars" "" "$cur_" "$sfx" ;; *) - __git_compute_config_vars - __gitcomp_nl "$(echo "$__git_config_vars" | - awk -F . '{ - sections[$1] = 1 - } - END { - for (s in sections) - print s "." - } - ')" "" "$cur_" "" + __git_compute_config_sections + __gitcomp_nl "$__git_config_sections" "" "$cur_" "." ;; esac } @@ -3628,43 +3550,6 @@ __git_complete () ___git_complete $1 $func } -if ! git --list-cmds=main >/dev/null 2>&1; then - - declare -A __git_cmds - __git_cmds[list-complete]="apply blame cherry config difftool fsck help instaweb mergetool prune reflog remote repack replace request-pull send-email show-branch stage whatchanged" - __git_cmds[list-guide]="attributes cli core-tutorial credentials cvs-migration diffcore everyday faq glossary hooks ignore mailmap modules namespaces remote-helpers repository-layout revisions submodules tutorial tutorial-2 workflows" - __git_cmds[list-mainporcelain]="add am archive bisect branch bundle checkout cherry-pick citool clean clone commit describe diff fetch format-patch gc grep gui init log maintenance merge mv notes pull push range-diff rebase reset restore revert rm shortlog show sparse-checkout stash status submodule switch tag worktree gitk" - __git_cmds[main]="add add--interactive am annotate apply archimport archive bisect bisect--helper blame branch bugreport bundle cat-file check-attr check-ignore check-mailmap check-ref-format checkout checkout--worker checkout-index cherry cherry-pick citool clean clone column commit commit-graph commit-tree config count-objects credential credential-cache credential-cache--daemon credential-store cvsexportcommit cvsimport cvsserver daemon describe diff diff-files diff-index diff-tree difftool difftool--helper env--helper fast-export fast-import fetch fetch-pack filter-branch fmt-merge-msg for-each-ref for-each-repo format-patch fsck fsck-objects fsmonitor--daemon gc get-tar-commit-id grep gui gui--askpass hash-object help hook http-backend http-fetch http-push imap-send index-pack init init-db instaweb interpret-trailers legacy-rebase legacy-stash log ls-files ls-remote ls-tree mailinfo mailsplit maintenance merge merge-base merge-file merge-index merge-octopus merge-one-file merge-ours merge-recursive merge-recursive-ours merge-recursive-theirs merge-resolve merge-subtree merge-tree mergetool mktag mktree multi-pack-index mv name-rev notes p4 pack-objects pack-redundant pack-refs patch-id pickaxe prune prune-packed pull push quiltimport range-diff read-tree rebase rebase--helper receive-pack reflog relink remote remote-ext remote-fd remote-ftp remote-ftps remote-http remote-https remote-testsvn repack replace request-pull rerere reset restore rev-list rev-parse revert rm send-email send-pack serve sh-i18n--envsubst shell shortlog show show-branch show-index show-ref sparse-checkout stage stash status stripspace submodule submodule--helper svn switch symbolic-ref tag unpack-file unpack-objects update-index update-ref update-server-info upload-archive upload-archive--writer upload-pack var verify-commit verify-pack verify-tag version web--browse whatchanged worktree write-tree" - __git_cmds[others]="" - __git_cmds[parseopt]="add am apply archive bisect--helper blame branch bugreport cat-file check-attr check-ignore check-mailmap checkout checkout--worker checkout-index cherry cherry-pick clean clone column commit commit-graph config count-objects credential-cache credential-cache--daemon credential-store describe difftool env--helper fast-export fetch fmt-merge-msg for-each-ref for-each-repo format-patch fsck fsck-objects fsmonitor--daemon gc grep hash-object help hook init init-db interpret-trailers log ls-files ls-remote ls-tree merge merge-base merge-file mktree multi-pack-index mv name-rev notes pack-objects pack-refs pickaxe prune prune-packed pull push range-diff read-tree rebase receive-pack reflog remote repack replace rerere reset restore revert rm send-pack shortlog show show-branch show-index show-ref sparse-checkout stage stash status stripspace switch symbolic-ref tag update-index update-ref update-server-info upload-pack verify-commit verify-pack verify-tag version whatchanged write-tree " - - # Override __git - __git () - { - case "$1" in - --list-cmds=*) - while read -r -d ',' x; do - case "$x" in - nohelpers) - ;; - alias) - ;; - config) - ;; - *) - echo ${__git_cmds[$x]} - ;; - esac - done <<< "${1##--list-cmds=}," - return - ;; - esac - git ${__git_C_args:+"${__git_C_args[@]}"} \ - ${__git_dir:+--git-dir="$__git_dir"} "$@" 2>/dev/null - } - -fi - ___git_complete git __git_main ___git_complete gitk __gitk_main diff --git a/zsh/plugins/gitfast/git-prompt.sh b/zsh/plugins/gitfast/git-prompt.sh index 1435548..76ee4ab 100644 --- a/zsh/plugins/gitfast/git-prompt.sh +++ b/zsh/plugins/gitfast/git-prompt.sh @@ -84,6 +84,10 @@ # single '?' character by setting GIT_PS1_COMPRESSSPARSESTATE, or omitted # by setting GIT_PS1_OMITSPARSESTATE. # +# If you would like to see a notification on the prompt when there are +# unresolved conflicts, set GIT_PS1_SHOWCONFLICTSTATE to "yes". The +# prompt will include "|CONFLICT". +# # If you would like to see more information about the identity of # commits checked out as a detached HEAD, set GIT_PS1_DESCRIBE_STYLE # to one of these values: @@ -96,9 +100,7 @@ # # If you would like a colored hint about the current dirty state, set # GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on -# the colored output of "git status -sb" and are available only when -# using __git_ps1 for PROMPT_COMMAND or precmd in Bash, -# but always available in Zsh. +# the colored output of "git status -sb". # # If you would like __git_ps1 to do nothing in the case when the current # directory is set up to be ignored by git, then set @@ -255,12 +257,12 @@ __git_ps1_colorize_gitstring () local c_lblue='%F{blue}' local c_clear='%f' else - # Using \[ and \] around colors is necessary to prevent + # Using \001 and \002 around colors is necessary to prevent # issues with command line editing/browsing/completion! - local c_red='\[\e[31m\]' - local c_green='\[\e[32m\]' - local c_lblue='\[\e[1;34m\]' - local c_clear='\[\e[0m\]' + local c_red=$'\001\e[31m\002' + local c_green=$'\001\e[32m\002' + local c_lblue=$'\001\e[1;34m\002' + local c_clear=$'\001\e[0m\002' fi local bad_color=$c_red local ok_color=$c_green @@ -508,6 +510,12 @@ __git_ps1 () r="$r $step/$total" fi + local conflict="" # state indicator for unresolved conflicts + if [[ "${GIT_PS1_SHOWCONFLICTSTATE}" == "yes" ]] && + [[ $(git ls-files --unmerged 2>/dev/null) ]]; then + conflict="|CONFLICT" + fi + local w="" local i="" local s="" @@ -564,15 +572,12 @@ __git_ps1 () b="\${__git_ps1_branch_name}" fi - # NO color option unless in PROMPT_COMMAND mode or it's Zsh if [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then - if [ $pcmode = yes ] || [ -n "${ZSH_VERSION-}" ]; then - __git_ps1_colorize_gitstring - fi + __git_ps1_colorize_gitstring fi local f="$h$w$i$s$u$p" - local gitstring="$c$b${f:+$z$f}${sparse}$r${upstream}" + local gitstring="$c$b${f:+$z$f}${sparse}$r${upstream}${conflict}" if [ $pcmode = yes ]; then if [ "${__git_printf_supports_v-}" != yes ]; then diff --git a/zsh/plugins/gitfast/gitfast.plugin.zsh b/zsh/plugins/gitfast/gitfast.plugin.zsh index a6db0c6..c456eff 100644 --- a/zsh/plugins/gitfast/gitfast.plugin.zsh +++ b/zsh/plugins/gitfast/gitfast.plugin.zsh @@ -1,6 +1,6 @@ # Handle $0 according to the standard: # https://zdharma-continuum.github.io/Zsh-100-Commits-Club/Zsh-Plugin-Standard.html -0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" +0="${ZERO:-${${0:#$ZSH_ARGZERO}:-${(%):-%N}}}" 0="${${(M)0:#/*}:-$PWD/$0}" source "${0:A:h}/git-prompt.sh" diff --git a/zsh/plugins/gitfast/update b/zsh/plugins/gitfast/update deleted file mode 100755 index feb13ff..0000000 --- a/zsh/plugins/gitfast/update +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -url="https://raw.githubusercontent.com/felipec/git-completion" -version="1.3.7" - -curl -s -o _git "${url}/v${version}/git-completion.zsh" && -curl -s -o git-completion.bash "${url}/v${version}/git-completion.bash" && -curl -s -o git-prompt.sh "${url}/v${version}/git-prompt.sh" diff --git a/zsh/plugins/gitignore/README.md b/zsh/plugins/gitignore/README.md index 753dd31..ea991a9 100644 --- a/zsh/plugins/gitignore/README.md +++ b/zsh/plugins/gitignore/README.md @@ -1,6 +1,6 @@ # gitignore -This plugin enables you the use of [gitignore.io](https://www.gitignore.io/) from the command line. You need an active internet connection. +This plugin enables you to use [gitignore.io](https://www.gitignore.io) from the command line. You need an active internet connection to fetch templates. The plugin uses the gitignore.io CDN endpoint to simplify access and improve reliability. To use it, add `gitignore` to the plugins array in your zshrc file: @@ -14,4 +14,4 @@ plugins=(... gitignore) * `gi [TEMPLATENAME]`: Show git-ignore output on the command line, e.g. `gi java` to exclude class and package files. -* `gi [TEMPLATENAME] >> .gitignore`: Appending programming language settings to your projects .gitignore. +* `gi [TEMPLATENAME] >> .gitignore`: Append the template rules to your project's `.gitignore` file. diff --git a/zsh/plugins/gitignore/gitignore.plugin.zsh b/zsh/plugins/gitignore/gitignore.plugin.zsh index a687f5c..a9f3f64 100644 --- a/zsh/plugins/gitignore/gitignore.plugin.zsh +++ b/zsh/plugins/gitignore/gitignore.plugin.zsh @@ -1,12 +1,21 @@ -function gi() { curl -fLw '\n' https://www.gitignore.io/api/"${(j:,:)@}" } +# gitignore plugin for oh-my-zsh +# Uses gitignore.io CDN endpoint +function _gi_curl() { + curl -sfL "https://www.gitignore.io/api/$1" +} + +function gi() { + local query="${(j:,:)@}" + _gi_curl "$query" || return 1 +} _gitignoreio_get_command_list() { - curl -sfL https://www.gitignore.io/api/list | tr "," "\n" + _gi_curl "list" | tr "," "\n" } _gitignoreio () { compset -P '*,' - compadd -S '' `_gitignoreio_get_command_list` + compadd -S '' $(_gitignoreio_get_command_list) } -compdef _gitignoreio gi +compdef _gitignoreio gi \ No newline at end of file diff --git a/zsh/plugins/gnu-utils/gnu-utils.plugin.zsh b/zsh/plugins/gnu-utils/gnu-utils.plugin.zsh index 9419127..adc2bd3 100644 --- a/zsh/plugins/gnu-utils/gnu-utils.plugin.zsh +++ b/zsh/plugins/gnu-utils/gnu-utils.plugin.zsh @@ -14,12 +14,12 @@ __gnu_utils() { local -a gcmds local gcmd - # coreutils + # coreutils gcmds=('g[' 'gbase64' 'gbasename' 'gcat' 'gchcon' 'gchgrp' 'gchmod' 'gchown' 'gchroot' 'gcksum' 'gcomm' 'gcp' 'gcsplit' 'gcut' 'gdate' 'gdd' 'gdf' 'gdir' 'gdircolors' 'gdirname' 'gdu' 'gecho' 'genv' 'gexpand' 'gexpr' 'gfactor' 'gfalse' 'gfmt' 'gfold' 'ggroups' 'ghead' 'ghostid' - 'gid' 'ginstall' 'gjoin' 'gkill' 'glink' 'gln' 'glogname' 'gls' 'gmd5sum' + 'gid' 'gindent' 'ginstall' 'gjoin' 'gkill' 'glink' 'gln' 'glogname' 'gls' 'gmd5sum' 'gmkdir' 'gmkfifo' 'gmknod' 'gmktemp' 'gmv' 'gnice' 'gnl' 'gnohup' 'gnproc' 'god' 'gpaste' 'gpathchk' 'gpinky' 'gpr' 'gprintenv' 'gprintf' 'gptx' 'gpwd' 'greadlink' 'grm' 'grmdir' 'gruncon' 'gseq' 'gsha1sum' 'gsha224sum' @@ -41,7 +41,7 @@ __gnu_utils() { for gcmd in "${gcmds[@]}"; do # Do nothing if the command isn't found (( ${+commands[$gcmd]} )) || continue - + # This method allows for builtin commands to be primary but it's # lost if hash -r or rehash is executed, or if $PATH is updated. # Thus, a preexec hook is needed, which will only run if whoami @@ -61,3 +61,14 @@ __gnu_utils_preexec() { autoload -Uz add-zsh-hook add-zsh-hook preexec __gnu_utils_preexec + +# lib/theme-and-appearance.zsh sets the alias for ls not knowing that +# we'll be using GNU ls. We'll reset this to use GNU ls --color. +# See https://github.com/ohmyzsh/ohmyzsh/issues/11503 +# +# The ls alias might look like: +# - ls='ls -G' +# - ls='gls --color=tty' +if [[ -x "${commands[gls]}" && "${aliases[ls]}" = (*-G*|gls*) ]]; then + alias ls='ls --color=tty' +fi diff --git a/zsh/plugins/golang/README.md b/zsh/plugins/golang/README.md index 3b7d1e1..80f8cf3 100644 --- a/zsh/plugins/golang/README.md +++ b/zsh/plugins/golang/README.md @@ -16,14 +16,16 @@ plugins=(... golang) | gob | `go build` | Build your code | | goc | `go clean` | Removes object files from package source directories | | god | `go doc` | Prints documentation comments | +| goe | `go env` | Prints Go environment information | | gof | `go fmt` | Gofmt formats (aligns and indents) Go programs. | | gofa | `go fmt ./...` | Run go fmt for all packages in current directory, recursively | | gofx | `go fix` | Update packages to use a new API | | gog | `go get` | Downloads packages and then installs them to $GOPATH | -| gog | `go get ./...` | Installs all dependencies in current directory, recursively | +| goga | `go get ./...` | Installs all dependencies in current directory, recursively | | goi | `go install` | Compiles and installs packages to $GOPATH | | gol | `go list` | Lists Go packages | | gom | `go mod` | Access to operations on modules | +| gomt | `go mod tidy` | Tidies up the go.mod file | | gopa | `cd $GOPATH` | Takes you to `$GOPATH` | | gopb | `cd $GOPATH/bin` | Takes you to `$GOPATH/bin` | | gops | `cd $GOPATH/src` | Takes you to `$GOPATH/src` | @@ -35,4 +37,5 @@ plugins=(... golang) | gotod | `go tool dist` | Utility to bootstrap, build and test go runtime | | gotofx | `go tool fix` | Fixes an application to use newer features | | gov | `go vet` | Vet examines Go source code and reports suspicious constructs | +| gove | `go version` | Prints Go version | | gow | `go work` | Work provides access to operations on workspaces | diff --git a/zsh/plugins/golang/golang.plugin.zsh b/zsh/plugins/golang/golang.plugin.zsh index 0dbaab0..dc4d918 100644 --- a/zsh/plugins/golang/golang.plugin.zsh +++ b/zsh/plugins/golang/golang.plugin.zsh @@ -13,6 +13,7 @@ unset p alias gob='go build' alias goc='go clean' alias god='go doc' +alias goe='go env' alias gof='go fmt' alias gofa='go fmt ./...' alias gofx='go fix' @@ -21,6 +22,7 @@ alias goga='go get ./...' alias goi='go install' alias gol='go list' alias gom='go mod' +alias gomt='go mod tidy' alias gopa='cd $GOPATH' alias gopb='cd $GOPATH/bin' alias gops='cd $GOPATH/src' @@ -32,4 +34,5 @@ alias gotoc='go tool compile' alias gotod='go tool dist' alias gotofx='go tool fix' alias gov='go vet' +alias gove='go version' alias gow='go work' diff --git a/zsh/plugins/gpg-agent/README.md b/zsh/plugins/gpg-agent/README.md index 8eeb94f..d66c37a 100644 --- a/zsh/plugins/gpg-agent/README.md +++ b/zsh/plugins/gpg-agent/README.md @@ -1,6 +1,11 @@ # gpg-agent -Enables [GPG's gpg-agent](https://www.gnupg.org/documentation/manuals/gnupg/) if it is not running. +Applies some fixes for some common issues encountered with [GPG's gpg-agent](https://www.gnupg.org/documentation/manuals/gnupg/). + +More specifically, this plugin: + +- Updates the `GPG_TTY` environment variable before each shell execution. +- Updates the `SSH_AUTH_SOCK` environment variable if `enable-ssh-support` is turned on. To use it, add `gpg-agent` to the plugins array of your zshrc file: diff --git a/tmux/plugins/tmux-prefix-highlight/LICENSE b/zsh/plugins/gradle/LICENSE similarity index 60% rename from tmux/plugins/tmux-prefix-highlight/LICENSE rename to zsh/plugins/gradle/LICENSE index 98da78e..06edf4a 100644 --- a/tmux/plugins/tmux-prefix-highlight/LICENSE +++ b/zsh/plugins/gradle/LICENSE @@ -1,13 +1,11 @@ -The MIT License (MIT) +Copyright (c) 2017 Eric Wendelin -Copyright (c) 2015 Erick Pintor - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. @@ -19,4 +17,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/zsh/plugins/gradle/_gradle b/zsh/plugins/gradle/_gradle index 770723d..588f330 100644 --- a/zsh/plugins/gradle/_gradle +++ b/zsh/plugins/gradle/_gradle @@ -1,26 +1,4 @@ #compdef gradle gradlew gw -# -# Taken from https://github.com/gradle/gradle-completion -# Copyright (c) 2017 Eric Wendelin -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -# of the Software, and to permit persons to whom the Software is furnished to do -# so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# Terms __gradle-set-project-root-dir() { local dir=`pwd` @@ -36,23 +14,23 @@ __gradle-set-project-root-dir() { } __gradle-init-cache-dir() { - cache_dir="$HOME/.gradle/completion" + cache_dir="${GRADLE_USER_HOME:-$HOME/.gradle}/completion" mkdir -p $cache_dir } __gradle-set-settings-file() { - # In order of precedence: --settings-file=filename, settings.gradle, settings.gradle.kts + # In order of precedence: settings.gradle, settings.gradle.kts local default_gradle_settings_file="$project_root_dir/settings.gradle" if [[ ! -f $default_gradle_settings_file ]]; then default_gradle_settings_file="$project_root_dir/settings.gradle.kts" fi - gradle_settings_file=${${(v)opt_args[(i)-c|--settings-file]}:-$default_gradle_settings_file} + gradle_settings_file=$default_gradle_settings_file } __gradle-set-build-file() { __gradle-set-settings-file - # In order of precedence: --build-file=filename, rootProject.buildFileName, build.gradle, build.gradle.kts + # In order of precedence: rootProject.buildFileName, build.gradle, build.gradle.kts local default_gradle_build_file_name="build.gradle" if [[ -r $gradle_settings_file ]]; then @@ -67,8 +45,7 @@ __gradle-set-build-file() { default_gradle_build_file="$project_root_dir/build.gradle.kts" fi - # If a build file is specified after '-b' or '--build-file', use this file. - gradle_build_file=${${(v)opt_args[(i)-b|--build-file]}:-$default_gradle_build_file} + gradle_build_file=$default_gradle_build_file } __gradle-set-cache-name() { @@ -116,14 +93,15 @@ __gradle-generate-tasks-cache() { # Reuse Gradle Daemon if IDLE but don't start a new one. local gradle_tasks_output if [[ ! -z "$($gradle_cmd --status 2>/dev/null | grep IDLE)" ]]; then - gradle_tasks_output="$($gradle_cmd --daemon --build-file $gradle_build_file --console plain -q tasks --all 2>/dev/null)" + gradle_tasks_output="$(cd "$project_root_dir" && "$gradle_cmd" --daemon --no-scan --console=plain -q tasks --all 2>/dev/null)" else - gradle_tasks_output="$($gradle_cmd --no-daemon --build-file $gradle_build_file --console plain -q tasks --all 2>/dev/null)" + gradle_tasks_output="$(cd "$project_root_dir" && "$gradle_cmd" --no-daemon --no-scan --console=plain -q tasks --all 2>/dev/null)" fi + local gradle_all_tasks="" root_tasks="" subproject_tasks="" output_line local -a match for output_line in ${(f)"$(printf "%s\n" "${gradle_tasks_output[@]}")"}; do - if [[ $output_line =~ ^([[:lower:]][[:alnum:][:punct:]]*)([[:space:]]-[[:space:]]([[:print:]]*))? ]]; then + if [[ $output_line =~ ^([[:alpha:]][[:alnum:][:punct:]]*)([[:space:]]-[[:space:]]([[:print:]]*))? ]]; then local task_name="${match[1]}" local task_description="${match[3]}" # Completion for subproject tasks with ':' prefix @@ -180,7 +158,7 @@ __gradle_tasks() { local cached_checksum="$(cat $cache_dir/$cache_name.md5)" local -a cached_tasks if [[ -z $cur ]]; then - cached_tasks=(${(f)"$(cat $cache_dir/$cached_checksum)"}) + cached_tasks=(${(f)"$(grep -v "^\\\:" $cache_dir/$cached_checksum)"}) else cached_tasks=(${(f)"$(grep "^${cur//:/\\\\:}" $cache_dir/$cached_checksum)"}) fi @@ -191,7 +169,7 @@ __gradle_tasks() { # Regenerate tasks cache in the background if [[ $gradle_files_checksum != "$(cat $cache_dir/$cache_name.md5)" || ! -f $cache_dir/$gradle_files_checksum || $(wc -c < $cache_dir/$gradle_files_checksum) -le 1 ]]; then - $(__gradle-generate-tasks-cache 1>&2 2>/dev/null &) + $(__gradle-generate-tasks-cache &> /dev/null &) fi else _describe 'built-in tasks' '( @@ -221,101 +199,161 @@ __gradle_subcommand() { ;; (dependencyInsight) _arguments \ + '--all-variants[Show all variants of each dependency]' \ + '--configuration=[Looks for the dependency in given configuration.]:dependency configuration:_gradle_dependency_configurations' \ '--dependency=[Shows the details of given dependency.]' \ - '--configuration=[Looks for the dependency in given configuration.]:dependency configuration:_gradle_dependency_configurations' && ret=0 + '--single-path[Show at most one path to each dependency]' && ret=0 ;; (help) _arguments \ - '--task[The task to show help for.]' && ret=0 + '--task=[The task to show help for.]' && ret=0 ;; (init) _arguments \ - '--dsl=[DSL to be used in generated scripts.]:dsl:(groovy kotlin)' \ - '--package=[Package for the generated source.]' \ - '--project-name=[Name of the generated project.]' \ - '--test-framework=[Test framework to be used.]:test framework:(junit kotlintest scalatest spock testng)' \ - '--type=[Project type to generate.]:project type:(basic cpp-application cpp-library groovy-application groovy-library java-application java-library kotlin-application kotlin-library pom scala-library)' && ret=0 + '--comments[Include clarifying comments in files.]' \ + '--dsl=[Set the build script DSL to be used in generated scripts.]' \ + '--incubating[Allow the generated build to use new features and APIs.]' \ + '--insecure-protocol=[How to handle insecure URLs used for Maven Repositories.]' \ + '--java-version=[Provides java version to use in the project.]' \ + '--overwrite[Allow existing files in the build directory to be overwritten?]' \ + '--package=[Set the package for source files.]' \ + '--project-name=[Set the project name.]' \ + '--split-project[Split functionality across multiple subprojects?]' \ + '--test-framework=[Set the test framework to be used.]' \ + '--type=[Set the type of project to generate.]' \ + '--use-defaults[Use default values for options not configured explicitly]' && ret=0 ;; (tasks) _arguments \ - '--all[List all tasks, including subproject tasks.]' \ - '--group=[Show tasks only from given task group.]' && ret=0 + '--all[Show additional tasks and detail.]' \ + '--group=[Show tasks for a specific group.]' \ + '--groups=[Show tasks for specific groups (can be used multiple times to specify multiple groups).]' \ + '--types[Show task class types]' && ret=0 ;; (test) _arguments -C \ - '--debug-jvm[Enable debugging for the test process. The process is started suspended and listening on port 5005. Requires the "java" plugin.]' \ - '--fail-fast[Stops test execution after the first failed test. Requires the "java" plugin.]' \ - '--tests=[Sets test class or method name to be included, * is supported. Requires the "java" plugin.]' \ + '--debug-jvm[Enable debugging for the test process. The process is started suspended and listening on port 5005.]' \ + '--fail-fast[Stops test execution after the first failed test.]' \ + '--test-dry-run[Simulate test execution.]' \ + '--tests=[Sets test class or method name to be included (in addition to the test task filters), '*' is supported.]' \ '(-)*:: :->task-or-option' && ret=0 ;; (wrapper) _arguments \ - '--distribution-type=[Binary-only or all with docs and sources]:*:distribution type:(bin all)' \ - '--gradle-version=[Set Gradle version for wrapper]' \ - '--gradle-distribution-sha256-sum=[SHA-256 checksum]' \ - '--gradle-distribution-url=[Set Gradle distribution URL]' && ret=0 + '--distribution-type=[The type of the Gradle distribution to be used by the wrapper.]:*:distribution type:(bin all)' \ + '--gradle-distribution-sha256-sum=[The SHA-256 hash sum of the gradle distribution.]' \ + '--gradle-distribution-url=[The URL to download the Gradle distribution from.]' \ + '--gradle-version=[The version of the Gradle distribution required by the wrapper. The following labels are allowed: latest, release-candidate, release-milestone, release-nightly, and nightly.]' \ + '--network-timeout=[Timeout in ms to use when the wrapper is performing network operations.]' \ + '--validate-url[Sets task to validate the configured distribution url.]' && ret=0 ;; (*) _arguments -C \ - {-a,--no-rebuild}'[Do not rebuild project dependencies.]' \ - '(--no-build-cache)--build-cache[Enable the Gradle build cache.]' \ - {-b,--build-file}'[Specifies the build file.]:build script:_files -g \*.gradle' \ - {-C,--cache}'[Specifies how compiled build scripts should be cached.]:cache policy:(on rebuild)' \ - {-c,--settings-file}'[Specifies the settings file.]:settings file:_files -g \*.gradle' \ - '(--no-configure-on-demand)--configure-on-demand[Only relevant projects are configured in this build run.]' \ - '--console=[Specifies which type of console output to generate.]:console output type:(plain auto rich verbose)' \ - '--continue[Continues task execution after a task failure.]' \ - '-Dorg.gradle.cache.reserved.mb=[Reserve Gradle Daemon memory for operations.]' \ - '-Dorg.gradle.caching=[Set true to enable Gradle build cache.]:enable build cache:(true false)' \ - '-Dorg.gradle.console=[Set type of console output to generate.]:console output type:(plain auto rich verbose)' \ - '-Dorg.gradle.daemon.debug=[Set true to debug Gradle Daemon.]:enable daemon debug:(true false)' \ - '-Dorg.gradle.daemon.idletimeout=[Kill Gradle Daemon after # idle millis.]' \ - '-Dorg.gradle.debug=[Set true to debug Gradle Client.]' \ - '-Dorg.gradle.jvmargs=[Set JVM arguments.]' \ - '-Dorg.gradle.java.home=[Set JDK home dir.]' \ - '-Dorg.gradle.logging.level=[Set default Gradle log level.]:log level:(quiet warn lifecycle info debug)' \ - '-Dorg.gradle.parallel=[Set true to enable parallel project builds.]:enable parallel build:(true false)' \ - '-Dorg.gradle.priority=[Set priority for Gradle worker processes.]:priority:(low normal)' \ - '-Dorg.gradle.warning.mode=[Set types of warnings to log.]:warning level:(all summary none)' \ - '-Dorg.gradle.workers.max=[Set the number of workers Gradle is allowed to use.]' \ - '(-i --info -w --warn -q --quiet)'{-d,--debug}'[Log in debug mode (includes normal stacktrace).]' \ - '(--no-daemon)--daemon[Uses the Gradle daemon to run the build. Starts the daemon if not running.]' \ - '--foreground[Starts the Gradle daemon in the foreground.]' \ - {-g,--gradle-user-home}'[Specifies the gradle user home directory.]:file:_directories' \ - \*--include-build'[Includes the specified build in the composite.]:file:_directories' \ - \*{-I,--init-script}'[Specifies an initialization script.]:init script:_files -g \*.gradle' \ - '(-d --debug -w --warn -q --quiet)'{-i,--info}'[Set log level to info.]' \ - '--max-workers[Set the maximum number of concurrent workers that Gradle may use.]:number workers' \ - {-m,--dry-run}'[Runs the builds with all task actions disabled.]' \ - '--no-color[Do not use color in the console output. (Removed in Gradle 3.0)]' \ - '(--build-cache)--no-build-cache[Do not use the Gradle build cache.]' \ - '(--configure-on-demand)--no-configure-on-demand[Disables configuration on demand.]' \ - '(--daemon)--no-daemon[Do not use the Gradle daemon to run the build.]' \ - '(--parallel)--no-parallel[Disables parallel execution to build projects.]' \ - '(--scan)--no-scan[Do not create a build scan.]' \ - '--offline[The build should operate without accessing network resources.]' \ - \*{-P+,--project-prop}'[Set project property for the build script (e.g. -Pmyprop=myvalue).]:project property (prop=val):' \ - {-p,--project-dir}'[Specifies the start directory for Gradle.]:start directory:_directories' \ - '(--no-parallel)--parallel[Build projects in parallel. Gradle will attempt to determine the optimal number of executor threads to use.]' \ - '--profile[Profiles build execution time and generates a report in the /reports/profile directory.]' \ - '--priority[Set priority for Gradle worker processes.]:priority:(low normal)' \ - '--project-cache-dir[Specifies the project-specific cache directory.]:cache directory:_directories' \ - '(-d --debug -w --warn -i --info)'{-q,--quiet}'[Log errors only.]' \ - '--recompile-scripts[Force build script recompiling.]' \ - '--refresh[Refresh the state of resources of the type(s) specified.]:refresh policy:(dependencies)' \ - '--refresh-dependencies[Refresh the state of dependencies.]' \ - '--rerun-tasks[Ignore previously cached task results.]' \ - '(--no-scan)--scan[Create a build scan.]' \ - '(-S --full-stacktrace)'{-s,--stacktrace}'[Print out the stacktrace for all exceptions.]' \ - '(-s --stacktrace)'{-S,--full-stacktrace}'[Print out the full (very verbose) stacktrace for all exceptions.]' \ - '--system-prop[system property (prop=val)]' \ + '-Dgradle.user.home=[Specifies the Gradle user home directory. Defaults to ~/.gradle]:gradle.user.home:_directories' \ + '-Dorg.gradle.caching.debug=[]' \ + '-Dorg.gradle.caching=[Enables the Gradle build cache. Gradle will try to reuse outputs from previous builds.]:org.gradle.caching:(true false)' \ + '-Dorg.gradle.configuration-cache.entries-per-key=[]' \ + '-Dorg.gradle.configuration-cache.fine-grained-property-tracking=[]' \ + '-Dorg.gradle.configuration-cache.heap-dump-dir=[]:org.gradle.configuration cache.heap dump dir:_directories' \ + '-Dorg.gradle.configuration-cache.inputs.unsafe.ignore.file-system-checks=[]' \ + '-Dorg.gradle.configuration-cache.inputs.unsafe.ignore.in-serialization=[]' \ + '-Dorg.gradle.configuration-cache.integrity-check=[]' \ + '-Dorg.gradle.configuration-cache.max-problems=[]' \ + '-Dorg.gradle.configuration-cache.parallel=[]' \ + '-Dorg.gradle.configuration-cache.problems=[Configures how the configuration cache handles problems (fail or warn). Defaults to fail.]:org.gradle.configuration cache.problems:(fail warn)' \ + '-Dorg.gradle.configuration-cache.read-only=[]' \ + '-Dorg.gradle.configuration-cache.unsafe.ignore.unsupported-build-events-listeners=[]' \ + '-Dorg.gradle.configuration-cache=[Enables the configuration cache. Gradle will try to reuse the build configuration from previous builds.]' \ + '-Dorg.gradle.configureondemand=[Configure necessary projects only. Gradle will attempt to reduce configuration time for large multi-project builds.]' \ + '-Dorg.gradle.console.unicode=[Specifies which character types are allowed in console output to generate. Values are 'auto' (default), 'disable' or 'enable'.]' \ + '-Dorg.gradle.console=[Specifies which type of console output to generate. Values are 'plain', 'colored', 'auto' (default), 'rich' or 'verbose'.]:org.gradle.console:(plain auto rich verbose)' \ + '-Dorg.gradle.continue=[Continue task execution after a task failure.]' \ + '-Dorg.gradle.continuous.quietperiod=[]' \ + '-Dorg.gradle.daemon.healthcheckinterval=[]' \ + '-Dorg.gradle.daemon.idletimeout=[]' \ + '-Dorg.gradle.daemon.registry.base=[]:org.gradle.daemon.registry.base:_directories' \ + '-Dorg.gradle.daemon=[Uses the Gradle daemon to run the build. Starts the daemon if not running.]' \ + '-Dorg.gradle.debug.host=[]' \ + '-Dorg.gradle.debug.port=[]' \ + '-Dorg.gradle.debug.server=[]' \ + '-Dorg.gradle.debug.suspend=[]' \ + '-Dorg.gradle.debug=[]:org.gradle.debug:(true false)' \ + '-Dorg.gradle.dependency.verification=[Configures the dependency verification mode. Values are 'strict', 'lenient' or 'off'.]:org.gradle.dependency.verification:(strict lenient off)' \ + '-Dorg.gradle.java.home=[]:org.gradle.java.home:_directories' \ + '-Dorg.gradle.java.installations.auto-detect=[]' \ + '-Dorg.gradle.java.installations.auto-download=[]' \ + '-Dorg.gradle.java.installations.fromEnv=[]' \ + '-Dorg.gradle.java.installations.idea-jdks-directory=[]:org.gradle.java.installations.idea jdks directory:_directories' \ + '-Dorg.gradle.java.installations.paths=[]:org.gradle.java.installations.paths:_directories' \ + '-Dorg.gradle.jvmargs=[]' \ + '-Dorg.gradle.logging.level=[]:org.gradle.logging.level:(quiet warn info debug)' \ + '-Dorg.gradle.logging.stacktrace=[]' \ + '-Dorg.gradle.native=[]' \ + '-Dorg.gradle.parallel=[Build projects in parallel. Gradle will attempt to determine the optimal number of executor threads to use.]:org.gradle.parallel:(true false)' \ + '-Dorg.gradle.priority=[Specifies the scheduling priority for the Gradle daemon and all processes launched by it. Values are 'normal' (default) or 'low']:org.gradle.priority:(normal low)' \ + '-Dorg.gradle.problems.report=[(Experimental) enables HTML problems report]' \ + '-Dorg.gradle.projectcachedir=[Specify the project-specific cache directory. Defaults to .gradle in the root project directory.]:org.gradle.projectcachedir:_directories' \ + '-Dorg.gradle.tooling.parallel=[]' \ + '-Dorg.gradle.unsafe.isolated-projects=[]' \ + '-Dorg.gradle.vfs.verbose=[]' \ + '-Dorg.gradle.vfs.watch=[Enables watching the file system for changes, allowing data about the file system to be re-used for the next build.]:org.gradle.vfs.watch:(true false)' \ + '-Dorg.gradle.warning.mode=[Specifies which mode of warnings to generate. Values are 'all', 'fail', 'summary'(default) or 'none']' \ + '-Dorg.gradle.welcome=[]:org.gradle.welcome:(once never)' \ + '-Dorg.gradle.workers.max=[Configure the number of concurrent workers Gradle is allowed to use.]' \ + (--no-build-cache)'--build-cache[Enables the Gradle build cache. Gradle will try to reuse outputs from previous builds.]' \ + (--no-configuration-cache)'--configuration-cache[Enables the configuration cache. Gradle will try to reuse the build configuration from previous builds.]' \ + '--configuration-cache-problems[Configures how the configuration cache handles problems (fail or warn). Defaults to fail.]:configuration cache problems:(fail warn)' \ + (--no-configure-on-demand)'--configure-on-demand[Configure necessary projects only. Gradle will attempt to reduce configuration time for large multi-project builds. (incubating)]' \ + '--console[Specifies which type of console output to generate. Values are 'plain', 'colored', 'auto' (default), 'rich' or 'verbose'.]:console:(plain auto rich verbose)' \ + '--console-unicode[Specifies which character types are allowed in console output to generate. Values are 'auto' (default), 'disable' or 'enable'.]' \ + (--no-continue)'--continue[Continue task execution after a task failure.]' \ {-t,--continuous}'[Enables continuous build. Gradle does not exit and will re-execute tasks when task file inputs change.]' \ - {-u,--no-search-upward}"[Don't search in parent folders for a settings.gradle file.]" \ - '(--write-locks)--update-locks[Perform a partial update of the dependency lock.]' \ - '(-d --debug -q --quiet -i --info)'{-w,--warn}'[Log warnings and errors only.]' \ - '--warning-mode=[Set types of warnings to log.]:warning mode:(all summary none)' \ - '(--update-locks)--write-locks[Persists dependency resolution for locked configurations.]' \ - {-x,--exclude-task}'[Specify a task to be excluded from execution.]' && ret=0 + (--no-daemon)'--daemon[Uses the Gradle daemon to run the build. Starts the daemon if not running.]' \ + (--quiet,-q,--warn,-w,--info,-i){-d,--debug}'[Log in debug mode (includes normal stacktrace).]' \ + {-F,--dependency-verification}'[Configures the dependency verification mode. Values are 'strict', 'lenient' or 'off'.]:dependency verification:(strict lenient off)' \ + {-m,--dry-run}'[Run the builds with all task actions disabled.]' \ + \*{-x,--exclude-task}'[Specify a task to be excluded from execution.]' \ + '--export-keys[Exports the public keys used for dependency verification.]' \ + '--foreground[Starts the Gradle daemon in the foreground.]' \ + (--stacktrace,-s){-S,--full-stacktrace}'[Print out the full (very verbose) stacktrace for all exceptions.]' \ + {-g,--gradle-user-home}'[Specifies the Gradle user home directory. Defaults to ~/.gradle]:gradle user home:_directories' \ + \*'--include-build[Include the specified build in the composite.]:include build:_directories' \ + (--quiet,-q,--warn,-w,--debug,-d){-i,--info}'[Set log level to info.]' \ + \*{-I,--init-script}'[Specify an initialization script.]:init script:_files -g \*.gradle(|.kts)' \ + '--max-workers[Configure the number of concurrent workers Gradle is allowed to use.]' \ + (--build-cache)'--no-build-cache[Disables the Gradle build cache.]' \ + (--configuration-cache)'--no-configuration-cache[Disables the configuration cache.]' \ + (--configure-on-demand)'--no-configure-on-demand[Disables the use of configuration on demand. (incubating)]' \ + (--continue)'--no-continue[Stop task execution after a task failure.]' \ + (--daemon)'--no-daemon[Do not use the Gradle daemon to run the build. Useful occasionally if you have configured Gradle to always run with the daemon by default.]' \ + (--parallel)'--no-parallel[Disables parallel execution to build projects.]' \ + (--problems-report)'--no-problems-report[(Experimental) disables HTML problems report]' \ + {-a,--no-rebuild}'[Do not rebuild project dependencies.]' \ + (--scan)'--no-scan[Disables the creation of a Build Scan.]' \ + (--watch-fs)'--no-watch-fs[Disables watching the file system.]' \ + '--offline[Execute the build without accessing network resources.]' \ + (--no-parallel)'--parallel[Build projects in parallel. Gradle will attempt to determine the optimal number of executor threads to use.]' \ + '--priority[Specifies the scheduling priority for the Gradle daemon and all processes launched by it. Values are 'normal' (default) or 'low']' \ + (--no-problems-report)'--problems-report[(Experimental) enables HTML problems report]' \ + '--profile[Profile build execution time and generates a report in the /reports/profile directory.]' \ + '--project-cache-dir[Specify the project-specific cache directory. Defaults to .gradle in the root project directory.]:project cache dir:_directories' \ + {-p,--project-dir}'[Specifies the start directory for Gradle. Defaults to current directory.]:project dir:_directories' \ + '--property-upgrade-report[(Experimental) Runs build with experimental property upgrade report.]' \ + (--warn,-w,--info,-i,--debug,-d){-q,--quiet}'[Log errors only.]' \ + {-U,--refresh-dependencies}'[Refresh the state of dependencies.]' \ + '--refresh-keys[Refresh the public keys used for dependency verification.]' \ + '--rerun[Causes the task to be re-run even if up-to-date.]' \ + '--rerun-tasks[Ignore previously cached task results.]' \ + (--no-scan)'--scan[Generate a Build Scan (powered by Develocity).]' \ + {-V,--show-version}'[Print version info and continue.]' \ + (--full-stacktrace,-S){-s,--stacktrace}'[Print out the stacktrace for all exceptions.]' \ + '--task-graph[Print task graph instead of executing tasks.]' \ + \*'--update-locks[Perform a partial update of the dependency lock, letting passed in module notations change version. (incubating)]' \ + (--quiet,-q,--info,-i,--debug,-d){-w,--warn}'[Set log level to warn.]' \ + '--warning-mode[Specifies which mode of warnings to generate. Values are 'all', 'fail', 'summary'(default) or 'none']:warning mode:(all summary none)' \ + (--no-watch-fs)'--watch-fs[Enables watching the file system for changes, allowing data about the file system to be re-used for the next build.]' \ + '--write-locks[Persists dependency resolution for locked configurations, ignoring existing locking information if it exists]' \ + {-M,--write-verification-metadata}'[Generates checksums for dependencies used in the project (comma-separated list)]' && ret=0 ;; esac @@ -341,71 +379,116 @@ _gradle() { typeset -A opt_args _arguments -C \ - '(-)'{-\?,-h,--help}'[Shows a help message.]' \ - {-a,--no-rebuild}'[Do not rebuild project dependencies.]' \ - '(--no-build-cache)--build-cache[Enable the Gradle build cache.]' \ - {-b,--build-file}'[Specifies the build file.]:build script:_files -g \*.gradle' \ - {-C,--cache}'[Specifies how compiled build scripts should be cached.]:cache policy:(on rebuild)' \ - {-c,--settings-file}'[Specifies the settings file.]:settings file:_files -g \*.gradle:->argument-expected' \ - '(--no-configure-on-demand)--configure-on-demand[Only relevant projects are configured in this build run.]' \ - '--console=[Specifies which type of console output to generate.]:console output type:(plain auto rich verbose)' \ - '--continue[Continues task execution after a task failure.]' \ - '-Dorg.gradle.cache.reserved.mb=[Reserve Gradle Daemon memory for operations.]' \ - '-Dorg.gradle.caching=[Set true to enable Gradle build cache.]' \ - '-Dorg.gradle.console=[Set type of console output to generate.]:console output type:(plain auto rich verbose)' \ - '-Dorg.gradle.daemon.debug=[Set true to debug Gradle Daemon.]' \ - '-Dorg.gradle.daemon.idletimeout=[Kill Gradle Daemon after # idle millis.]' \ - '-Dorg.gradle.debug=[Set true to debug Gradle Client.]' \ - '-Dorg.gradle.jvmargs=[Set JVM arguments.]' \ - '-Dorg.gradle.java.home=[Set JDK home dir.]' \ - '-Dorg.gradle.logging.level=[Set default Gradle log level.]:log level:(quiet warn lifecycle info debug)' \ - '-Dorg.gradle.parallel=[Set true to enable parallel project builds.]:(true false)' \ - '-Dorg.gradle.priority=[Set priority for Gradle worker processes.]:priority:(low normal)' \ - '-Dorg.gradle.warning.mode=[Set types of warnings to log.]:warning level:(all summary none)' \ - '-Dorg.gradle.workers.max=[Set the number of workers Gradle is allowed to use.]' \ - '(-i --info -w --warn -q --quiet)'{-d,--debug}'[Log in debug mode (includes normal stacktrace).]' \ - '(--no-daemon)--daemon[Uses the Gradle daemon to run the build. Starts the daemon if not running.]' \ - '--foreground[Starts the Gradle daemon in the foreground.]' \ - {-g,--gradle-user-home}'[Specifies the gradle user home directory.]:home directory:_directories:->argument-expected' \ - '(-)--gui[Launches the Gradle GUI. (Removed in Gradle 4.0)]' \ - \*--include-build'[Includes the specified build in the composite.]:file:_directories:->argument-expected' \ - \*{-I,--init-script}'[Specifies an initialization script.]:init script:_files -g \*.gradle:->argument-expected' \ - '(-d --debug -w --warn -q --quiet)'{-i,--info}'[Set log level to info.]' \ - '--max-workers[Set the maximum number of concurrent workers that Gradle may use.]:number workers:->argument-expected' \ - {-m,--dry-run}'[Runs the builds with all task actions disabled.]' \ - '--no-color[Do not use color in the console output. (Removed in Gradle 3.0)]' \ - '(--build-cache)--no-build-cache[Do not use the Gradle build cache.]' \ - '(--configure-on-demand)--no-configure-on-demand[Disables configuration on demand.]' \ - '(--daemon)--no-daemon[Do not use the Gradle daemon to run the build.]' \ - '(--parallel)--no-parallel[Disables parallel execution to build projects.]' \ - '(--scan)--no-scan[Do not create a build scan.]' \ - '--offline[The build should operate without accessing network resources.]' \ - \*{-P+,--project-prop}'[Set project property for the build script (e.g. -Pmyprop=myvalue).]:project property (prop=val):->argument-expected' \ - {-p,--project-dir}'[Specifies the start directory for Gradle.]:start directory:_directories:->argument-expected' \ - '(--no-parallel)--parallel[Build projects in parallel. Gradle will attempt to determine the optimal number of executor threads to use.]' \ - '--priority=[Set priority for Gradle worker processes.]:priority:(low normal)' \ - '--profile[Profiles build execution time and generates a report in the /reports/profile directory.]' \ - '--project-cache-dir=[Specifies the project-specific cache directory.]:cache directory:_directories:->argument-expected' \ - '(-d --debug -w --warn -i --info)'{-q,--quiet}'[Log errors only.]' \ - '--recompile-scripts[Force build script recompiling.]' \ - '--refresh[Refresh the state of resources of the type(s) specified.]:refresh policy:(dependencies)' \ - '--refresh-dependencies[Refresh the state of dependencies.]' \ - '--rerun-tasks[Ignore previously cached task results.]' \ - '(--no-scan)--scan[Create a build scan.]' \ - '(-S --full-stacktrace)'{-s,--stacktrace}'[Print out the stacktrace for all exceptions.]' \ - '(-s --stacktrace)'{-S,--full-stacktrace}'[Print out the full (very verbose) stacktrace for all exceptions.]' \ - '(-)--status[Shows status of running and recently stopped Gradle Daemons.]' \ - '(-)--stop[Stops all Gradle daemons.]' \ - '--system-prop[system property (prop=val)]' \ +'-Dgradle.user.home=[Specifies the Gradle user home directory. Defaults to ~/.gradle]:gradle.user.home:_directories:->argument-expected' \ + '-Dorg.gradle.caching.debug=[]:->argument-expected' \ + '-Dorg.gradle.caching=[Enables the Gradle build cache. Gradle will try to reuse outputs from previous builds.]:org.gradle.caching:(true false):->argument-expected' \ + '-Dorg.gradle.configuration-cache.entries-per-key=[]:->argument-expected' \ + '-Dorg.gradle.configuration-cache.fine-grained-property-tracking=[]:->argument-expected' \ + '-Dorg.gradle.configuration-cache.heap-dump-dir=[]:org.gradle.configuration cache.heap dump dir:_directories:->argument-expected' \ + '-Dorg.gradle.configuration-cache.inputs.unsafe.ignore.file-system-checks=[]:->argument-expected' \ + '-Dorg.gradle.configuration-cache.inputs.unsafe.ignore.in-serialization=[]:->argument-expected' \ + '-Dorg.gradle.configuration-cache.integrity-check=[]:->argument-expected' \ + '-Dorg.gradle.configuration-cache.max-problems=[]:->argument-expected' \ + '-Dorg.gradle.configuration-cache.parallel=[]:->argument-expected' \ + '-Dorg.gradle.configuration-cache.problems=[Configures how the configuration cache handles problems (fail or warn). Defaults to fail.]:org.gradle.configuration cache.problems:(fail warn):->argument-expected' \ + '-Dorg.gradle.configuration-cache.read-only=[]:->argument-expected' \ + '-Dorg.gradle.configuration-cache.unsafe.ignore.unsupported-build-events-listeners=[]:->argument-expected' \ + '-Dorg.gradle.configuration-cache=[Enables the configuration cache. Gradle will try to reuse the build configuration from previous builds.]:->argument-expected' \ + '-Dorg.gradle.configureondemand=[Configure necessary projects only. Gradle will attempt to reduce configuration time for large multi-project builds.]:->argument-expected' \ + '-Dorg.gradle.console.unicode=[Specifies which character types are allowed in console output to generate. Values are 'auto' (default), 'disable' or 'enable'.]:->argument-expected' \ + '-Dorg.gradle.console=[Specifies which type of console output to generate. Values are 'plain', 'colored', 'auto' (default), 'rich' or 'verbose'.]:org.gradle.console:(plain auto rich verbose):->argument-expected' \ + '-Dorg.gradle.continue=[Continue task execution after a task failure.]:->argument-expected' \ + '-Dorg.gradle.continuous.quietperiod=[]:->argument-expected' \ + '-Dorg.gradle.daemon.healthcheckinterval=[]:->argument-expected' \ + '-Dorg.gradle.daemon.idletimeout=[]:->argument-expected' \ + '-Dorg.gradle.daemon.registry.base=[]:org.gradle.daemon.registry.base:_directories:->argument-expected' \ + '-Dorg.gradle.daemon=[Uses the Gradle daemon to run the build. Starts the daemon if not running.]:->argument-expected' \ + '-Dorg.gradle.debug.host=[]:->argument-expected' \ + '-Dorg.gradle.debug.port=[]:->argument-expected' \ + '-Dorg.gradle.debug.server=[]:->argument-expected' \ + '-Dorg.gradle.debug.suspend=[]:->argument-expected' \ + '-Dorg.gradle.debug=[]:org.gradle.debug:(true false):->argument-expected' \ + '-Dorg.gradle.dependency.verification=[Configures the dependency verification mode. Values are 'strict', 'lenient' or 'off'.]:org.gradle.dependency.verification:(strict lenient off):->argument-expected' \ + '-Dorg.gradle.java.home=[]:org.gradle.java.home:_directories:->argument-expected' \ + '-Dorg.gradle.java.installations.auto-detect=[]:->argument-expected' \ + '-Dorg.gradle.java.installations.auto-download=[]:->argument-expected' \ + '-Dorg.gradle.java.installations.fromEnv=[]:->argument-expected' \ + '-Dorg.gradle.java.installations.idea-jdks-directory=[]:org.gradle.java.installations.idea jdks directory:_directories:->argument-expected' \ + '-Dorg.gradle.java.installations.paths=[]:org.gradle.java.installations.paths:_directories:->argument-expected' \ + '-Dorg.gradle.jvmargs=[]:->argument-expected' \ + '-Dorg.gradle.logging.level=[]:org.gradle.logging.level:(quiet warn info debug):->argument-expected' \ + '-Dorg.gradle.logging.stacktrace=[]:->argument-expected' \ + '-Dorg.gradle.native=[]:->argument-expected' \ + '-Dorg.gradle.parallel=[Build projects in parallel. Gradle will attempt to determine the optimal number of executor threads to use.]:org.gradle.parallel:(true false):->argument-expected' \ + '-Dorg.gradle.priority=[Specifies the scheduling priority for the Gradle daemon and all processes launched by it. Values are 'normal' (default) or 'low']:org.gradle.priority:(normal low):->argument-expected' \ + '-Dorg.gradle.problems.report=[(Experimental) enables HTML problems report]:->argument-expected' \ + '-Dorg.gradle.projectcachedir=[Specify the project-specific cache directory. Defaults to .gradle in the root project directory.]:org.gradle.projectcachedir:_directories:->argument-expected' \ + '-Dorg.gradle.tooling.parallel=[]:->argument-expected' \ + '-Dorg.gradle.unsafe.isolated-projects=[]:->argument-expected' \ + '-Dorg.gradle.vfs.verbose=[]:->argument-expected' \ + '-Dorg.gradle.vfs.watch=[Enables watching the file system for changes, allowing data about the file system to be re-used for the next build.]:org.gradle.vfs.watch:(true false):->argument-expected' \ + '-Dorg.gradle.warning.mode=[Specifies which mode of warnings to generate. Values are 'all', 'fail', 'summary'(default) or 'none']:->argument-expected' \ + '-Dorg.gradle.welcome=[]:org.gradle.welcome:(once never):->argument-expected' \ + '-Dorg.gradle.workers.max=[Configure the number of concurrent workers Gradle is allowed to use.]:->argument-expected' \ + (--no-build-cache)'--build-cache[Enables the Gradle build cache. Gradle will try to reuse outputs from previous builds.]' \ + (--no-configuration-cache)'--configuration-cache[Enables the configuration cache. Gradle will try to reuse the build configuration from previous builds.]' \ + '--configuration-cache-problems[Configures how the configuration cache handles problems (fail or warn). Defaults to fail.]:configuration cache problems:(fail warn):->argument-expected' \ + (--no-configure-on-demand)'--configure-on-demand[Configure necessary projects only. Gradle will attempt to reduce configuration time for large multi-project builds. (incubating)]' \ + '--console[Specifies which type of console output to generate. Values are 'plain', 'colored', 'auto' (default), 'rich' or 'verbose'.]:console:(plain auto rich verbose):->argument-expected' \ + '--console-unicode[Specifies which character types are allowed in console output to generate. Values are 'auto' (default), 'disable' or 'enable'.]:->argument-expected' \ + (--no-continue)'--continue[Continue task execution after a task failure.]' \ {-t,--continuous}'[Enables continuous build. Gradle does not exit and will re-execute tasks when task file inputs change.]' \ - {-u,--no-search-upward}"[Don't search in parent folders for a settings.gradle file.]" \ - '(--write-locks)--update-locks[Perform a partial update of the dependency lock.]' \ - '(-)'{-v,--version}'[Print version info.]' \ - '(-d --debug -q --quiet -i --info)'{-w,--warn}'[Log warnings and errors only.]' \ - '--warning-mode=[Set types of warnings to log.]:warning mode:(all summary none)' \ - '(--update-locks)--write-locks[Persists dependency resolution for locked configurations.]' \ - {-x,--exclude-task}'[Specify a task to be excluded from execution.]' \ - '(-)*:: :->task-or-option' && ret=0 + (--no-daemon)'--daemon[Uses the Gradle daemon to run the build. Starts the daemon if not running.]' \ + (--quiet,-q,--warn,-w,--info,-i){-d,--debug}'[Log in debug mode (includes normal stacktrace).]' \ + {-F,--dependency-verification}'[Configures the dependency verification mode. Values are 'strict', 'lenient' or 'off'.]:dependency verification:(strict lenient off):->argument-expected' \ + {-m,--dry-run}'[Run the builds with all task actions disabled.]' \ + \*{-x,--exclude-task}'[Specify a task to be excluded from execution.]' \ + '--export-keys[Exports the public keys used for dependency verification.]' \ + '--foreground[Starts the Gradle daemon in the foreground.]' \ + (--stacktrace,-s){-S,--full-stacktrace}'[Print out the full (very verbose) stacktrace for all exceptions.]' \ + {-g,--gradle-user-home}'[Specifies the Gradle user home directory. Defaults to ~/.gradle]:gradle user home:_directories:->argument-expected' \ + {-h,--help}'[Shows a help message.]' \ + \*'--include-build[Include the specified build in the composite.]:include build:_directories:->argument-expected' \ + (--quiet,-q,--warn,-w,--debug,-d){-i,--info}'[Set log level to info.]' \ + \*{-I,--init-script}'[Specify an initialization script.]:init script:_files -g \*.gradle(|.kts):->argument-expected' \ + '--max-workers[Configure the number of concurrent workers Gradle is allowed to use.]:->argument-expected' \ + (--build-cache)'--no-build-cache[Disables the Gradle build cache.]' \ + (--configuration-cache)'--no-configuration-cache[Disables the configuration cache.]' \ + (--configure-on-demand)'--no-configure-on-demand[Disables the use of configuration on demand. (incubating)]' \ + (--continue)'--no-continue[Stop task execution after a task failure.]' \ + (--daemon)'--no-daemon[Do not use the Gradle daemon to run the build. Useful occasionally if you have configured Gradle to always run with the daemon by default.]' \ + (--parallel)'--no-parallel[Disables parallel execution to build projects.]' \ + (--problems-report)'--no-problems-report[(Experimental) disables HTML problems report]' \ + {-a,--no-rebuild}'[Do not rebuild project dependencies.]' \ + (--scan)'--no-scan[Disables the creation of a Build Scan.]' \ + (--watch-fs)'--no-watch-fs[Disables watching the file system.]' \ + '--offline[Execute the build without accessing network resources.]' \ + (--no-parallel)'--parallel[Build projects in parallel. Gradle will attempt to determine the optimal number of executor threads to use.]' \ + '--priority[Specifies the scheduling priority for the Gradle daemon and all processes launched by it. Values are 'normal' (default) or 'low']:->argument-expected' \ + (--no-problems-report)'--problems-report[(Experimental) enables HTML problems report]' \ + '--profile[Profile build execution time and generates a report in the /reports/profile directory.]' \ + '--project-cache-dir[Specify the project-specific cache directory. Defaults to .gradle in the root project directory.]:project cache dir:_directories:->argument-expected' \ + {-p,--project-dir}'[Specifies the start directory for Gradle. Defaults to current directory.]:project dir:_directories:->argument-expected' \ + '--property-upgrade-report[(Experimental) Runs build with experimental property upgrade report.]' \ + (--warn,-w,--info,-i,--debug,-d){-q,--quiet}'[Log errors only.]' \ + {-U,--refresh-dependencies}'[Refresh the state of dependencies.]' \ + '--refresh-keys[Refresh the public keys used for dependency verification.]' \ + '--rerun[Causes the task to be re-run even if up-to-date.]' \ + '--rerun-tasks[Ignore previously cached task results.]' \ + (--no-scan)'--scan[Generate a Build Scan (powered by Develocity).]' \ + {-V,--show-version}'[Print version info and continue.]' \ + (--full-stacktrace,-S){-s,--stacktrace}'[Print out the stacktrace for all exceptions.]' \ + '--status[Shows status of running and recently stopped Gradle daemon(s).]' \ + '--stop[Stops the Gradle daemon if it is running.]' \ + '--task-graph[Print task graph instead of executing tasks.]' \ + \*'--update-locks[Perform a partial update of the dependency lock, letting passed in module notations change version. (incubating)]' \ + {-v,--version}'[Print version info and exit.]' \ + (--quiet,-q,--info,-i,--debug,-d){-w,--warn}'[Set log level to warn.]' \ + '--warning-mode[Specifies which mode of warnings to generate. Values are 'all', 'fail', 'summary'(default) or 'none']:warning mode:(all summary none):->argument-expected' \ + (--no-watch-fs)'--watch-fs[Enables watching the file system for changes, allowing data about the file system to be re-used for the next build.]' \ + '--write-locks[Persists dependency resolution for locked configurations, ignoring existing locking information if it exists]' \ + {-M,--write-verification-metadata}'[Generates checksums for dependencies used in the project (comma-separated list)]:->argument-expected' \ +'(-)*:: :->task-or-option' && ret=0 if [[ $words[CURRENT] != -* && $state != "argument-expected" ]]; then __gradle_tasks && ret=0 diff --git a/zsh/plugins/gradle/gradle.plugin.zsh b/zsh/plugins/gradle/gradle.plugin.zsh index 5bca364..dacc464 100644 --- a/zsh/plugins/gradle/gradle.plugin.zsh +++ b/zsh/plugins/gradle/gradle.plugin.zsh @@ -6,7 +6,7 @@ function gradle-or-gradlew() { # taken from https://github.com/gradle/gradle-completion local dir="$PWD" project_root="$PWD" while [[ "$dir" != / ]]; do - if [[ -f "$dir/settings.gradle" || -f "$dir/settings.gradle.kts" || -f "$dir/gradlew" ]]; then + if [[ -x "$dir/gradlew" ]]; then project_root="$dir" break fi diff --git a/zsh/plugins/grails/grails.plugin.zsh b/zsh/plugins/grails/grails.plugin.zsh index ddc2574..e5dceb5 100644 --- a/zsh/plugins/grails/grails.plugin.zsh +++ b/zsh/plugins/grails/grails.plugin.zsh @@ -7,7 +7,7 @@ _enumerateGrailsScripts() { then directories+=(plugins/*/scripts) fi - + # Enumerate all of the Groovy files files=() for dir in $directories; @@ -17,13 +17,13 @@ _enumerateGrailsScripts() { files+=($dir/[^_]*.groovy) fi done - + # Don't try to basename () if [ ${#files} -eq 0 ]; then return fi - + scripts=() for file in $files do @@ -42,19 +42,19 @@ _enumerateGrailsScripts() { done echo $scripts } - + _grails() { if (( CURRENT == 2 )); then scripts=( $(_enumerateGrailsScripts) ) - + if [ ${#scripts} -ne 0 ]; then _multi_parts / scripts return fi fi - + _files } - + compdef _grails grails diff --git a/zsh/plugins/grc/grc.plugin.zsh b/zsh/plugins/grc/grc.plugin.zsh index b709b9e..fc6ecc8 100644 --- a/zsh/plugins/grc/grc.plugin.zsh +++ b/zsh/plugins/grc/grc.plugin.zsh @@ -2,8 +2,11 @@ # common grc.zsh paths files=( - /etc/grc.zsh # default - /usr/local/etc/grc.zsh # homebrew + /etc/grc.zsh # default + /usr/local/etc/grc.zsh # homebrew darwin-x64 + /opt/homebrew/etc/grc.zsh # homebrew darwin-arm64 + /home/linuxbrew/.linuxbrew/etc/grc.zsh # linuxbrew + /usr/share/grc/grc.zsh # Gentoo Linux (app-misc/grc) ) # verify the file is readable and source it diff --git a/zsh/plugins/hasura/README.md b/zsh/plugins/hasura/README.md new file mode 100644 index 0000000..d7db9ed --- /dev/null +++ b/zsh/plugins/hasura/README.md @@ -0,0 +1,9 @@ +# Hasura plugin + +This plugin adds completion for [the Hasura CLI](https://hasura.io/docs/latest/hasura-cli/index/). + +To use it, add `hasura` to the plugins array in your zshrc file: + +```zsh +plugins=(... hasura) +``` diff --git a/zsh/plugins/hasura/hasura.plugin.zsh b/zsh/plugins/hasura/hasura.plugin.zsh new file mode 100644 index 0000000..18254c4 --- /dev/null +++ b/zsh/plugins/hasura/hasura.plugin.zsh @@ -0,0 +1,13 @@ +if (( ! $+commands[hasura] )); then + return +fi + +# If the completion file does not exist, generate it and then source it +# Otherwise, source it and regenerate in the background +if [[ ! -f "$ZSH_CACHE_DIR/completions/_hasura" ]]; then + hasura completion zsh --file "$ZSH_CACHE_DIR/completions/_hasura" >/dev/null + source "$ZSH_CACHE_DIR/completions/_hasura" +else + source "$ZSH_CACHE_DIR/completions/_hasura" + hasura completion zsh --file "$ZSH_CACHE_DIR/completions/_hasura" >/dev/null &| +fi diff --git a/zsh/plugins/hcloud/README.md b/zsh/plugins/hcloud/README.md new file mode 100644 index 0000000..6cac675 --- /dev/null +++ b/zsh/plugins/hcloud/README.md @@ -0,0 +1,143 @@ +# hcloud plugin + +This plugin adds completion for the [Hetzner Cloud CLI](https://github.com/hetznercloud/cli), +as well as some aliases for common hcloud commands. + +To use it, add `hcloud` to the plugins array in your zshrc file: + +```zsh +plugins=(... hcloud) +``` + +## Aliases + +| Alias | Command | Description | +| :--------- | :---------------------------------------- | :------------------------------------------------------------ | +| hc | `hcloud` | The hcloud command | +| | | **Context Management** | +| hcctx | `hcloud context` | Manage contexts | +| hcctxls | `hcloud context list` | List all contexts | +| hcctxu | `hcloud context use` | Use a context | +| hcctxc | `hcloud context create` | Create a new context | +| hcctxd | `hcloud context delete` | Delete a context | +| hcctxa | `hcloud context active` | Show active context | +| | | **Server Management** | +| hcs | `hcloud server` | Manage servers | +| hcsl | `hcloud server list` | List all servers | +| hcsc | `hcloud server create` | Create a server | +| hcsd | `hcloud server delete` | Delete a server | +| hcsdesc | `hcloud server describe` | Describe a server | +| hcspoff | `hcloud server poweroff` | Power off a server | +| hcspon | `hcloud server poweron` | Power on a server | +| hcsr | `hcloud server reboot` | Reboot a server | +| hcsreset | `hcloud server reset` | Reset a server | +| hcssh | `hcloud server ssh` | SSH into a server | +| hcse | `hcloud server enable-rescue` | Enable rescue mode for a server | +| hcsdr | `hcloud server disable-rescue` | Disable rescue mode for a server | +| hcsip | `hcloud server ip` | Manage server IPs | +| hcsa | `hcloud server attach-iso` | Attach an ISO to a server | +| hcsda | `hcloud server detach-iso` | Detach an ISO from a server | +| hcscip | `hcloud server change-type` | Change server type | +| | | **Volume Management** | +| hcv | `hcloud volume` | Manage volumes | +| hcvl | `hcloud volume list` | List all volumes | +| hcvc | `hcloud volume create` | Create a volume | +| hcvd | `hcloud volume delete` | Delete a volume | +| hcvdesc | `hcloud volume describe` | Describe a volume | +| hcva | `hcloud volume attach` | Attach a volume to a server | +| hcvda | `hcloud volume detach` | Detach a volume from a server | +| hcvr | `hcloud volume resize` | Resize a volume | +| | | **Network Management** | +| hcn | `hcloud network` | Manage networks | +| hcnl | `hcloud network list` | List all networks | +| hcnc | `hcloud network create` | Create a network | +| hcnd | `hcloud network delete` | Delete a network | +| hcndesc | `hcloud network describe` | Describe a network | +| hcnas | `hcloud network add-subnet` | Add a subnet to a network | +| hcnds | `hcloud network delete-subnet` | Delete a subnet from a network | +| hcnar | `hcloud network add-route` | Add a route to a network | +| hcndr | `hcloud network delete-route` | Delete a route from a network | +| | | **Floating IP Management** | +| hcfip | `hcloud floating-ip` | Manage floating IPs | +| hcfipl | `hcloud floating-ip list` | List all floating IPs | +| hcfipc | `hcloud floating-ip create` | Create a floating IP | +| hcfipd | `hcloud floating-ip delete` | Delete a floating IP | +| hcfipdesc | `hcloud floating-ip describe` | Describe a floating IP | +| hcfipa | `hcloud floating-ip assign` | Assign a floating IP to a server | +| hcfipua | `hcloud floating-ip unassign` | Unassign a floating IP from a server | +| | | **SSH Key Management** | +| hcsk | `hcloud ssh-key` | Manage SSH keys | +| hcskl | `hcloud ssh-key list` | List all SSH keys | +| hcskc | `hcloud ssh-key create` | Create an SSH key | +| hcskd | `hcloud ssh-key delete` | Delete an SSH key | +| hcskdesc | `hcloud ssh-key describe` | Describe an SSH key | +| hcsku | `hcloud ssh-key update` | Update an SSH key | +| | | **Image Management** | +| hci | `hcloud image` | Manage images | +| hcil | `hcloud image list` | List all images | +| hcid | `hcloud image delete` | Delete an image | +| hcidesc | `hcloud image describe` | Describe an image | +| hciu | `hcloud image update` | Update an image | +| | | **Firewall Management** | +| hcfw | `hcloud firewall` | Manage firewalls | +| hcfwl | `hcloud firewall list` | List all firewalls | +| hcfwc | `hcloud firewall create` | Create a firewall | +| hcfwd | `hcloud firewall delete` | Delete a firewall | +| hcfwdesc | `hcloud firewall describe` | Describe a firewall | +| hcfwar | `hcloud firewall add-rule` | Add a rule to a firewall | +| hcfwdr | `hcloud firewall delete-rule` | Delete a rule from a firewall | +| hcfwas | `hcloud firewall apply-to-resource` | Apply a firewall to a resource | +| hcfwrs | `hcloud firewall remove-from-resource` | Remove a firewall from a resource | +| | | **Load Balancer Management** | +| hclb | `hcloud load-balancer` | Manage load balancers | +| hclbl | `hcloud load-balancer list` | List all load balancers | +| hclbc | `hcloud load-balancer create` | Create a load balancer | +| hclbd | `hcloud load-balancer delete` | Delete a load balancer | +| hclbdesc | `hcloud load-balancer describe` | Describe a load balancer | +| hclbu | `hcloud load-balancer update` | Update a load balancer | +| hclbas | `hcloud load-balancer add-service` | Add a service to a load balancer | +| hclbds | `hcloud load-balancer delete-service` | Delete a service from a load balancer | +| hclbat | `hcloud load-balancer add-target` | Add a target to a load balancer | +| hclbdt | `hcloud load-balancer delete-target` | Delete a target from a load balancer | +| | | **Certificate Management** | +| hccert | `hcloud certificate` | Manage certificates | +| hccertl | `hcloud certificate list` | List all certificates | +| hccertc | `hcloud certificate create` | Create a certificate | +| hccertd | `hcloud certificate delete` | Delete a certificate | +| hccertdesc | `hcloud certificate describe` | Describe a certificate | +| hccertu | `hcloud certificate update` | Update a certificate | +| | | **Datacenter and Location Info** | +| hcdc | `hcloud datacenter list` | List all datacenters | +| hcloc | `hcloud location list` | List all locations | +| hcst | `hcloud server-type list` | List all server types | +| hcit | `hcloud image list --type system` | List all system images | + +## Requirements + +This plugin requires the [Hetzner Cloud CLI](https://github.com/hetznercloud/cli) to be installed. + +### Installation + +Install the Hetzner Cloud CLI using one of the following methods: + +**macOS (Homebrew):** +```bash +brew install hcloud +``` + +**Linux (from source):** +```bash +go install github.com/hetznercloud/cli/cmd/hcloud@latest +``` + +**Or download a prebuilt binary from the [releases page](https://github.com/hetznercloud/cli/releases).** + +### Setup + +After installation, create a context and authenticate: + +```bash +hcloud context create my-project +``` + +You'll be prompted to enter your Hetzner Cloud API token, which you can generate in the [Hetzner Cloud Console](https://console.hetzner.cloud/). diff --git a/zsh/plugins/hcloud/hcloud.plugin.zsh b/zsh/plugins/hcloud/hcloud.plugin.zsh new file mode 100644 index 0000000..3b1d432 --- /dev/null +++ b/zsh/plugins/hcloud/hcloud.plugin.zsh @@ -0,0 +1,129 @@ +# hcloud plugin for oh-my-zsh +# Hetzner Cloud CLI: https://github.com/hetznercloud/cli + +if (( ! $+commands[hcloud] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `hcloud`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_hcloud" ]]; then + typeset -g -A _comps + autoload -Uz _hcloud + _comps[hcloud]=_hcloud +fi + +hcloud completion zsh 2> /dev/null >| "$ZSH_CACHE_DIR/completions/_hcloud" &| + +# Main alias +alias hc='hcloud' + +# Context management +alias hcctx='hcloud context' +alias hcctxls='hcloud context list' +alias hcctxu='hcloud context use' +alias hcctxc='hcloud context create' +alias hcctxd='hcloud context delete' +alias hcctxa='hcloud context active' + +# Server management +alias hcs='hcloud server' +alias hcsl='hcloud server list' +alias hcsc='hcloud server create' +alias hcsd='hcloud server delete' +alias hcsdesc='hcloud server describe' +alias hcspoff='hcloud server poweroff' +alias hcspon='hcloud server poweron' +alias hcsr='hcloud server reboot' +alias hcsreset='hcloud server reset' +alias hcssh='hcloud server ssh' +alias hcse='hcloud server enable-rescue' +alias hcsdr='hcloud server disable-rescue' +alias hcsip='hcloud server ip' + +# Server actions +alias hcsa='hcloud server attach-iso' +alias hcsda='hcloud server detach-iso' +alias hcscip='hcloud server change-type' + +# Volume management +alias hcv='hcloud volume' +alias hcvl='hcloud volume list' +alias hcvc='hcloud volume create' +alias hcvd='hcloud volume delete' +alias hcvdesc='hcloud volume describe' +alias hcva='hcloud volume attach' +alias hcvda='hcloud volume detach' +alias hcvr='hcloud volume resize' + +# Network management +alias hcn='hcloud network' +alias hcnl='hcloud network list' +alias hcnc='hcloud network create' +alias hcnd='hcloud network delete' +alias hcndesc='hcloud network describe' +alias hcnas='hcloud network add-subnet' +alias hcnds='hcloud network delete-subnet' +alias hcnar='hcloud network add-route' +alias hcndr='hcloud network delete-route' + +# Floating IP management +alias hcfip='hcloud floating-ip' +alias hcfipl='hcloud floating-ip list' +alias hcfipc='hcloud floating-ip create' +alias hcfipd='hcloud floating-ip delete' +alias hcfipdesc='hcloud floating-ip describe' +alias hcfipa='hcloud floating-ip assign' +alias hcfipua='hcloud floating-ip unassign' + +# SSH key management +alias hcsk='hcloud ssh-key' +alias hcskl='hcloud ssh-key list' +alias hcskc='hcloud ssh-key create' +alias hcskd='hcloud ssh-key delete' +alias hcskdesc='hcloud ssh-key describe' +alias hcsku='hcloud ssh-key update' + +# Image management +alias hci='hcloud image' +alias hcil='hcloud image list' +alias hcid='hcloud image delete' +alias hcidesc='hcloud image describe' +alias hciu='hcloud image update' + +# Firewall management +alias hcfw='hcloud firewall' +alias hcfwl='hcloud firewall list' +alias hcfwc='hcloud firewall create' +alias hcfwd='hcloud firewall delete' +alias hcfwdesc='hcloud firewall describe' +alias hcfwar='hcloud firewall add-rule' +alias hcfwdr='hcloud firewall delete-rule' +alias hcfwas='hcloud firewall apply-to-resource' +alias hcfwrs='hcloud firewall remove-from-resource' + +# Load balancer management +alias hclb='hcloud load-balancer' +alias hclbl='hcloud load-balancer list' +alias hclbc='hcloud load-balancer create' +alias hclbd='hcloud load-balancer delete' +alias hclbdesc='hcloud load-balancer describe' +alias hclbu='hcloud load-balancer update' +alias hclbas='hcloud load-balancer add-service' +alias hclbds='hcloud load-balancer delete-service' +alias hclbat='hcloud load-balancer add-target' +alias hclbdt='hcloud load-balancer delete-target' + +# Certificate management +alias hccert='hcloud certificate' +alias hccertl='hcloud certificate list' +alias hccertc='hcloud certificate create' +alias hccertd='hcloud certificate delete' +alias hccertdesc='hcloud certificate describe' +alias hccertu='hcloud certificate update' + +# Datacenter and location info +alias hcdc='hcloud datacenter list' +alias hcloc='hcloud location list' +alias hcst='hcloud server-type list' +alias hcit='hcloud image list --type system' diff --git a/zsh/plugins/helm/README.md b/zsh/plugins/helm/README.md index 49844c7..dcbb30b 100644 --- a/zsh/plugins/helm/README.md +++ b/zsh/plugins/helm/README.md @@ -1,9 +1,19 @@ # Helm plugin -This plugin adds completion for [Helm](https://helm.sh/), the Kubernetes package manager. +This plugin adds completion and aliases for [Helm](https://helm.sh/), the Kubernetes package manager. To use it, add `helm` to the plugins array in your zshrc file: ```zsh plugins=(... helm) ``` + +## Aliases + +| Alias | Full command | +| ----- | -------------- | +| h | helm | +| hin | helm install | +| hun | helm uninstall | +| hse | helm search | +| hup | helm upgrade | diff --git a/zsh/plugins/helm/helm.plugin.zsh b/zsh/plugins/helm/helm.plugin.zsh index 151c43d..e754a65 100644 --- a/zsh/plugins/helm/helm.plugin.zsh +++ b/zsh/plugins/helm/helm.plugin.zsh @@ -11,3 +11,9 @@ else source "$ZSH_CACHE_DIR/completions/_helm" helm completion zsh | tee "$ZSH_CACHE_DIR/completions/_helm" >/dev/null &| fi + +alias h='helm' +alias hin='helm install' +alias hun='helm uninstall' +alias hse='helm search' +alias hup='helm upgrade' diff --git a/zsh/plugins/heroku-alias/README.md b/zsh/plugins/heroku-alias/README.md new file mode 100644 index 0000000..4ecb07a --- /dev/null +++ b/zsh/plugins/heroku-alias/README.md @@ -0,0 +1,140 @@ +# heroku-alias + +Full alias list for Heroku CLI. + +To use it, add `heroku-alias` to the plugins array in your zshrc file: + +```zsh +plugins=(... heroku-alias) +``` + +## Requirements + +- [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli) + +| 🚀 last maj | 📡 source | +| ---------- | --------------------------------------------------------------------------- | +| 02/06/2020 | [heroku cli doc](https://devcenter.heroku.com/articles/heroku-cli-commands) | + +## Aliases + +### general + +| Alias | Command | +| ----- | ---------------------------------- | +| h | heroku | +| hauto | heroku autocomplete $(echo $SHELL) | +| hl | heroku local | + +### config + +| Alias | Command | +| ------ | ---------------------- | +| hc | heroku config | +| hca | heroku config -a | +| hcr | heroku config -r | +| hcs | heroku config:set | +| hcu | heroku config:unset | + +Also, you can use the `hcfile` function to set multiple config variables from a file, +which asks you for a platform and a config file to read the configuration from. + +### apps and favorites + +| Alias | Command | +| ----- | ---------------------------- | +| ha | heroku apps | +| hpop | heroku create | +| hkill | heroku apps:destroy | +| hlog | heroku apps:errors | +| hfav | heroku apps:favorites | +| hfava | heroku apps:favorites:add | +| hfavr | heroku apps:favorites:remove | +| hai | heroku apps:info | +| hair | heroku apps:info -r | +| haia | heroku apps:info -a | + +## auth + +| Alias | Command | +| ----- | ----------------------- | +| h2fa | heroku auth:2fa | +| h2far | heroku auth:2fa:disable | + +## access + +| Alias | Command | +| ----- | -------------------- | +| hac | heroku access | +| hacr | heroku access -r | +| haca | heroku access -a | +| hadd | heroku access:add | +| hdel | heroku access:remove | +| hup | heroku access:update | + +### addons + +| Alias | Command | +| ----- | --------------------- | +| hads | heroku addons -A | +| hada | heroku addons -a | +| hadr | heroku addons -r | +| hadat | heroku addons:attach | +| hadc | heroku addons:create | +| hadel | heroku addons:destroy | +| hadde | heroku addons:detach | +| hadoc | heroku addons:docs | + +### login + +| Alias | Command | +| ----- | ------------------ | +| hin | heroku login | +| hout | heroku logout | +| hi | heroku login -i | +| hwho | heroku auth:whoami | + +### authorizations + +| Alias | Command | +| ------ | ---------------------------- | +| hth | heroku authorizations | +| hthadd | heroku authorizations:create | +| hthif | heroku authorizations:info | +| hthdel | heroku authorizations:revoke | +| hthrot | heroku authorizations:rotate | +| hthup | heroku authorizations:update | + +### plugins + +| Alias | Command | +| ----- | -------------- | +| hp | heroku plugins | + +### log + +| Alias | Command | +| ----- | --------------- | +| hg | heroku logs | +| hgt | heroku log tail | + +### database + +| Alias | Command | +| ----- | -------------------------- | +| hpg | heroku pg | +| hpsql | heroku pg:psql | +| hpb | heroku pg:backups | +| hpbc | heroku pg:backups:capture | +| hpbd | heroku pg:backups:download | +| hpbr | heroku pg:backups:restore | + +### certs + +| Alias | Command | +| ----- | ------------------- | +| hssl | heroku certs | +| hssli | heroku certs:info | +| hssla | heroku certs:add | +| hsslu | heroku certs:update | +| hsslr | heroku certs:remove | diff --git a/zsh/plugins/heroku-alias/heroku-alias.plugin.zsh b/zsh/plugins/heroku-alias/heroku-alias.plugin.zsh new file mode 100644 index 0000000..7daf715 --- /dev/null +++ b/zsh/plugins/heroku-alias/heroku-alias.plugin.zsh @@ -0,0 +1,92 @@ +# general +alias h='heroku' +alias hauto='heroku autocomplete $(echo $SHELL)' +alias hl='heroku local' + +# log +alias hg='heroku logs' +alias hgt='heroku log tail' + +# database +alias hpg='heroku pg' +alias hpsql='heroku pg:psql' +alias hpb='heroku pg:backups' +alias hpbc='heroku pg:backups:capture' +alias hpbd='heroku pg:backups:download' +alias hpbr='heroku pg:backups:restore' + +# config +alias hc='heroku config' +alias hca='heroku config -a' +alias hcr='heroku config -r' +alias hcs='heroku config:set' +alias hcu='heroku config:unset' + +# this function allow to load multi env set in a file +hcfile() { + echo 'Which platform [-r/a name] ?' + read platform + echo 'Which file ?' + read file + while read line; + do heroku config:set "$platform" "$line"; + done < "$file" +} + +# apps and favorites +alias ha='heroku apps' +alias hpop='heroku create' +alias hkill='heroku apps:destroy' +alias hlog='heroku apps:errors' +alias hfav='heroku apps:favorites' +alias hfava='heroku apps:favorites:add' +alias hfavr='heroku apps:favorites:remove' +alias hai='heroku apps:info' +alias hair='heroku apps:info -r' +alias haia='heroku apps:info -a' + +# auth +alias h2fa='heroku auth:2fa' +alias h2far='heroku auth:2fa:disable' + +# access +alias hac='heroku access' +alias hacr='heroku access -r' +alias haca='heroku access -a' +alias hadd='heroku access:add' +alias hdel='heroku access:remove' +alias hup='heroku access:update' + +# addons +alias hads='heroku addons -A' +alias hada='heroku addons -a' +alias hadr='heroku addons -r' +alias hadat='heroku addons:attach' +alias hadc='heroku addons:create' +alias hadel='heroku addons:destroy' +alias hadde='heroku addons:detach' +alias hadoc='heroku addons:docs' + +# login +alias hin='heroku login' +alias hout='heroku logout' +alias hi='heroku login -i' +alias hwho='heroku auth:whoami' + +# authorizations +alias hth='heroku authorizations' +alias hthadd='heroku authorizations:create' +alias hthif='heroku authorizations:info' +alias hthdel='heroku authorizations:revoke' +alias hthrot='heroku authorizations:rotate' +alias hthup='heroku authorizations:update' + +# plugins +alias hp='heroku plugins' + +# cert +alias hssl='heroku certs' +alias hssli='heroku certs:info' +alias hssla='heroku certs:add' +alias hsslu='heroku certs:update' +alias hsslr='heroku certs:remove' diff --git a/zsh/plugins/history-substring-search/README.md b/zsh/plugins/history-substring-search/README.md index 6d8b564..49bed52 100644 --- a/zsh/plugins/history-substring-search/README.md +++ b/zsh/plugins/history-substring-search/README.md @@ -23,7 +23,15 @@ Install Using the [Homebrew]( https://brew.sh ) package manager: brew install zsh-history-substring-search - echo 'source /usr/local/share/zsh-history-substring-search/zsh-history-substring-search.zsh' >> ~/.zshrc + echo 'source $(brew --prefix)/share/zsh-history-substring-search/zsh-history-substring-search.zsh' >> ~/.zshrc + +Using [Fig](https://fig.io): + +Fig adds apps, shortcuts, and autocomplete to your existing terminal. + +Install `zsh-history-substring-search` in just one click. + + Using [Oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh): @@ -33,24 +41,63 @@ Using [Oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh): 2. Activate the plugin in `~/.zshrc`: - plugins=( [plugins...] history-substring-search) + plugins=( [plugins...] zsh-history-substring-search) -3. Source `~/.zshrc` to take changes into account: +3. Run `exec zsh` to take changes into account: - source ~/.zshrc + exec zsh + +Using [zplug](https://github.com/zplug/zplug): + +1. Add this repo to `~/.zshrc`: + + zplug "zsh-users/zsh-history-substring-search", as: plugin + +Using [antigen](https://github.com/zsh-users/antigen): + +1. Add the `antigen bundle` command just before `antigen apply`, like this: + +``` +antigen bundle zsh-users/zsh-history-substring-search +antigen apply +``` + +2. Then, **after** `antigen apply`, add the key binding configurations, like this: + +``` +# zsh-history-substring-search configuration +bindkey '^[[A' history-substring-search-up # or '\eOA' +bindkey '^[[B' history-substring-search-down # or '\eOB' +HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE=1 +``` + +Using [Zinit](https://github.com/zdharma-continuum/zinit): + +1. Use the `Oh-my-zsh` Zinit snippet in `~/.zshrc`: + + zinit snippet OMZ::plugins/git/git.plugin.zsh` + +2. Load the plugin in `~/.zshrc`: + + zinit load 'zsh-users/zsh-history-substring-search' + zinit ice wait atload'_history_substring_search_config' + +3. Run `exec zsh` to take changes into account: + + exec zsh Usage ------------------------------------------------------------------------------ 1. Load this script into your interactive ZSH session: - % source zsh-history-substring-search.zsh + source zsh-history-substring-search.zsh If you want to use [zsh-syntax-highlighting][6] along with this script, then make sure that you load it *before* you load this script: - % source zsh-syntax-highlighting.zsh - % source zsh-history-substring-search.zsh + source zsh-syntax-highlighting.zsh + source zsh-history-substring-search.zsh 2. Bind keyboard shortcuts to this script's functions. @@ -73,6 +120,10 @@ Usage bindkey "$terminfo[kcuu1]" history-substring-search-up bindkey "$terminfo[kcud1]" history-substring-search-down + Users have also observed that `[OA` and `[OB` are correct values, + _even if_ these were not the observed values. If you are having trouble + with the observed values, give these a try. + You might also want to bind the Control-P/N keys for use in EMACS mode: bindkey -M emacs '^P' history-substring-search-up @@ -115,7 +166,7 @@ Configuration ------------------------------------------------------------------------------ This script defines the following global variables. You may override their -default values only after having loaded this script into your ZSH session. +default values. * `HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND` is a global variable that defines how the query should be highlighted inside a matching command. Its default @@ -141,6 +192,12 @@ default values only after having loaded this script into your ZSH session. value, causes this script to perform a fuzzy search by words, matching in given order e.g. `ab c` will match `*ab*c*` +* `HISTORY_SUBSTRING_SEARCH_PREFIXED` is a global variable that defines how + the command history will be searched for your query. If set to a non-empty + value, your query will be matched against the start of each history entry. + For example, if this variable is empty, `ls` will match `ls -l` and `echo + ls`; if it is non-empty, `ls` will only match `ls -l`. + * `HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE` is a global variable that defines whether all search results returned are _unique_. If set to a non-empty value, then only unique search results are presented. This behaviour is off @@ -155,6 +212,9 @@ default values only after having loaded this script into your ZSH session. receive globally unique search results only once, then use this configuration variable, or use `setopt HIST_IGNORE_ALL_DUPS`. +* `HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_TIMEOUT` is a global variable that + defines a timeout in seconds for clearing the search highlight. + History ------------------------------------------------------------------------------ @@ -175,24 +235,17 @@ History * March 2016: Geza Lore (@gezalore) greatly refactored it in pull request #55. ------------------------------------------------------------------------------- -Oh My Zsh Distribution Notes ------------------------------------------------------------------------------- +--- -What you are looking at now is Oh My Zsh's repackaging of zsh-history-substring-search -as an OMZ module inside the Oh My Zsh distribution. +## Oh My Zsh Distribution Notes -The upstream repo, zsh-users/zsh-history-substring-search, can be found on GitHub at +What you are looking at now is Oh My Zsh's repackaging of zsh-history-substring-search as an OMZ module inside +the Oh My Zsh distribution. + +The upstream repo, zsh-users/zsh-history-substring-search, can be found on GitHub at https://github.com/zsh-users/zsh-history-substring-search. -This downstream copy was last updated from the following upstream commit: - - SHA: 0f80b8eb3368b46e5e573c1d91ae69eb095db3fb - Commit date: 2019-05-12 17:35:54 -0700 - -Everything above this section is a copy of the original upstream's README, so things -may differ slightly when you're using this inside OMZ. In particular, you do not -need to set up key bindings for the up and down arrows yourself in `~/.zshrc`; the OMZ -plugin does that for you. You may still want to set up additional emacs- or vi-specific -bindings as mentioned above. - +Everything above this section is a copy of the original upstream's README, so things may differ slightly when +you're using this inside OMZ. In particular, you do not need to set up key bindings for the up and down arrows +yourself in `~/.zshrc`; the OMZ plugin does that for you. You may still want to set up additional emacs- or +vi-specific bindings as mentioned above. diff --git a/zsh/plugins/history-substring-search/dependencies/OMZ-README.md b/zsh/plugins/history-substring-search/dependencies/OMZ-README.md new file mode 100644 index 0000000..c5967bb --- /dev/null +++ b/zsh/plugins/history-substring-search/dependencies/OMZ-README.md @@ -0,0 +1,15 @@ + +--- + +## Oh My Zsh Distribution Notes + +What you are looking at now is Oh My Zsh's repackaging of zsh-history-substring-search as an OMZ module inside +the Oh My Zsh distribution. + +The upstream repo, zsh-users/zsh-history-substring-search, can be found on GitHub at +https://github.com/zsh-users/zsh-history-substring-search. + +Everything above this section is a copy of the original upstream's README, so things may differ slightly when +you're using this inside OMZ. In particular, you do not need to set up key bindings for the up and down arrows +yourself in `~/.zshrc`; the OMZ plugin does that for you. You may still want to set up additional emacs- or +vi-specific bindings as mentioned above. diff --git a/zsh/plugins/history-substring-search/history-substring-search.plugin.zsh b/zsh/plugins/history-substring-search/history-substring-search.plugin.zsh index 63f0bdd..c7c4235 100644 --- a/zsh/plugins/history-substring-search/history-substring-search.plugin.zsh +++ b/zsh/plugins/history-substring-search/history-substring-search.plugin.zsh @@ -3,6 +3,13 @@ 0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" 0="${${(M)0:#/*}:-$PWD/$0}" +# Respect case sensitivity settings for globbing in history search +if [[ "$CASE_SENSITIVE" = true ]]; then + : ${HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS=''} +else + : ${HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS='i'} +fi + source ${0:A:h}/history-substring-search.zsh @@ -16,4 +23,3 @@ if [[ -n "$terminfo[kcud1]" ]]; then bindkey -M emacs "$terminfo[kcud1]" history-substring-search-down bindkey -M viins "$terminfo[kcud1]" history-substring-search-down fi - diff --git a/zsh/plugins/history-substring-search/history-substring-search.zsh b/zsh/plugins/history-substring-search/history-substring-search.zsh index c326778..2137b79 100644 --- a/zsh/plugins/history-substring-search/history-substring-search.zsh +++ b/zsh/plugins/history-substring-search/history-substring-search.zsh @@ -43,11 +43,12 @@ # declare global configuration variables #----------------------------------------------------------------------------- -typeset -g HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND='bg=magenta,fg=white,bold' -typeset -g HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND='bg=red,fg=white,bold' -typeset -g HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS='i' -typeset -g HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE='' -typeset -g HISTORY_SUBSTRING_SEARCH_FUZZY='' +: ${HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND='bg=magenta,fg=white,bold'} +: ${HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND='bg=red,fg=white,bold'} +: ${HISTORY_SUBSTRING_SEARCH_GLOBBING_FLAGS='i'} +: ${HISTORY_SUBSTRING_SEARCH_ENSURE_UNIQUE=''} +: ${HISTORY_SUBSTRING_SEARCH_FUZZY=''} +: ${HISTORY_SUBSTRING_SEARCH_PREFIXED=''} #----------------------------------------------------------------------------- # declare internal global variables @@ -64,6 +65,7 @@ typeset -g -i _history_substring_search_raw_match_index typeset -g -a _history_substring_search_matches typeset -g -i _history_substring_search_match_index typeset -g -A _history_substring_search_unique_filter +typeset -g -i _history_substring_search_zsh_5_9 #----------------------------------------------------------------------------- # the main ZLE widgets @@ -97,6 +99,11 @@ zle -N history-substring-search-down #----------------------------------------------------------------------------- zmodload -F zsh/parameter +autoload -Uz is-at-least + +if is-at-least 5.9 $ZSH_VERSION; then + _history_substring_search_zsh_5_9=1 +fi # # We have to "override" some keys and widgets if the @@ -117,80 +124,125 @@ if [[ $+functions[_zsh_highlight] -eq 0 ]]; then } # - # The following snippet was taken from the zsh-syntax-highlighting project: + # Check if $1 denotes the name of a callable function, i.e. it is fully + # defined or it is marked for autoloading and autoloading it at the first + # call to it will succeed. In particular, if $1 has been marked for + # autoloading but is not available in $fpath, then it will return 1 (false). # - # https://github.com/zsh-users/zsh-syntax-highlighting/blob/56b134f5d62ae3d4e66c7f52bd0cc2595f9b305b/zsh-syntax-highlighting.zsh#L126-161 + # This is based on the zsh-syntax-highlighting plugin. # - # Copyright (c) 2010-2011 zsh-syntax-highlighting contributors - # All rights reserved. + _history-substring-search-function-callable() { + if (( ${+functions[$1]} )) && ! [[ "$functions[$1]" == *"builtin autoload -X"* ]]; then + return 0 # already fully loaded + else + # "$1" is either an autoload stub, or not a function at all. + # We expect 'autoload +X' to return non-zero if it fails to fully load + # the function. + ( autoload -U +X -- "$1" 2>/dev/null ) + return $? + fi + } + # - # Redistribution and use in source and binary forms, with or without - # modification, are permitted provided that the following conditions are - # met: + # The zsh-syntax-highlighting plugin uses zle-line-pre-redraw hook instead + # of the legacy "bind all widgets" if 1) zsh has the memo= feature (added in + # version 5.9) and 2) add-zle-hook-widget is available. # - # * Redistributions of source code must retain the above copyright - # notice, this list of conditions and the following disclaimer. - # - # * Redistributions in binary form must reproduce the above copyright - # notice, this list of conditions and the following disclaimer in the - # documentation and/or other materials provided with the distribution. - # - # * Neither the name of the zsh-syntax-highlighting contributors nor the - # names of its contributors may be used to endorse or promote products - # derived from this software without specific prior written permission. - # - # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - # - #--------------8<-------------------8<-------------------8<----------------- - # Rebind all ZLE widgets to make them invoke _zsh_highlights. - _zsh_highlight_bind_widgets() - { - # Load ZSH module zsh/zleparameter, needed to override user defined widgets. - zmodload zsh/zleparameter 2>/dev/null || { - echo 'zsh-syntax-highlighting: failed loading zsh/zleparameter.' >&2 - return 1 + if [[ $_history_substring_search_zsh_5_9 -eq 1 ]] && _history-substring-search-function-callable add-zle-hook-widget; then + # + # The following code is based on the zsh-syntax-highlighting plugin. + # + autoload -U add-zle-hook-widget + + _history-substring-search-zle-line-finish() { + # + # Reset $WIDGET since the 'main' highlighter depends on it. + # + # Since $WIDGET is declared by zle as read-only in this function's scope, + # a nested function is required in order to shadow its built-in value; + # see "User-defined widgets" in zshall. + # + () { + local -h -r WIDGET=zle-line-finish + _zsh_highlight + } } - # Override ZLE widgets to make them invoke _zsh_highlight. - local cur_widget - for cur_widget in ${${(f)"$(builtin zle -la)"}:#(.*|_*|orig-*|run-help|which-command|beep|yank*)}; do - case $widgets[$cur_widget] in + _history-substring-search-zle-line-pre-redraw() { + # + # If the zsh-syntax-highlighting plugin has been loaded (after our plugin + # plugin, otherwise this hook wouldn't be called), remove our hooks. + # + if [[ $+ZSH_HIGHLIGHT_VERSION -eq 1 ]]; then + autoload -U add-zle-hook-widget + add-zle-hook-widget -d zle-line-pre-redraw _history-substring-search-zle-line-pre-redraw + add-zle-hook-widget -d zle-line-finish _history-substring-search-zle-line-finish + return 0 + fi + # + # Set $? to 0 for _zsh_highlight. Without this, subsequent + # zle-line-pre-redraw hooks won't run, since add-zle-hook-widget happens to + # call us with $? == 1 in the common case. + # + true && _zsh_highlight "$@" + } - # Already rebound event: do nothing. - user:$cur_widget|user:_zsh_highlight_widget_*);; + if [[ -o zle ]]; then + add-zle-hook-widget zle-line-pre-redraw _history-substring-search-zle-line-pre-redraw + add-zle-hook-widget zle-line-finish _history-substring-search-zle-line-finish + fi + else + # + # The following snippet was taken from the zsh-syntax-highlighting project: + # https://github.com/zsh-users/zsh-syntax-highlighting/blob/56b134f5d62ae3d4e66c7f52bd0cc2595f9b305b/zsh-syntax-highlighting.zsh#L126-161 + # + # SPDX-SnippetBegin + # SPDX-License-Identifier: BSD-3-Clause + # SPDX-SnippetCopyrightText: 2010-2011 zsh-syntax-highlighting contributors + #--------------8<-------------------8<-------------------8<----------------- + # Rebind all ZLE widgets to make them invoke _zsh_highlights. + _zsh_highlight_bind_widgets() + { + # Load ZSH module zsh/zleparameter, needed to override user defined widgets. + zmodload zsh/zleparameter 2>/dev/null || { + echo 'zsh-syntax-highlighting: failed loading zsh/zleparameter.' >&2 + return 1 + } - # User defined widget: override and rebind old one with prefix "orig-". - user:*) eval "zle -N orig-$cur_widget ${widgets[$cur_widget]#*:}; \ - _zsh_highlight_widget_$cur_widget() { builtin zle orig-$cur_widget -- \"\$@\" && _zsh_highlight }; \ - zle -N $cur_widget _zsh_highlight_widget_$cur_widget";; + # Override ZLE widgets to make them invoke _zsh_highlight. + local cur_widget + for cur_widget in ${${(f)"$(builtin zle -la)"}:#(.*|_*|orig-*|run-help|which-command|beep|yank*)}; do + case $widgets[$cur_widget] in - # Completion widget: override and rebind old one with prefix "orig-". - completion:*) eval "zle -C orig-$cur_widget ${${widgets[$cur_widget]#*:}/:/ }; \ - _zsh_highlight_widget_$cur_widget() { builtin zle orig-$cur_widget -- \"\$@\" && _zsh_highlight }; \ - zle -N $cur_widget _zsh_highlight_widget_$cur_widget";; + # Already rebound event: do nothing. + user:$cur_widget|user:_zsh_highlight_widget_*);; - # Builtin widget: override and make it call the builtin ".widget". - builtin) eval "_zsh_highlight_widget_$cur_widget() { builtin zle .$cur_widget -- \"\$@\" && _zsh_highlight }; \ - zle -N $cur_widget _zsh_highlight_widget_$cur_widget";; + # User defined widget: override and rebind old one with prefix "orig-". + user:*) eval "zle -N orig-$cur_widget ${widgets[$cur_widget]#*:}; \ + _zsh_highlight_widget_$cur_widget() { builtin zle orig-$cur_widget -- \"\$@\" && _zsh_highlight }; \ + zle -N $cur_widget _zsh_highlight_widget_$cur_widget";; - # Default: unhandled case. - *) echo "zsh-syntax-highlighting: unhandled ZLE widget '$cur_widget'" >&2 ;; - esac - done - } - #-------------->8------------------->8------------------->8----------------- + # Completion widget: override and rebind old one with prefix "orig-". + completion:*) eval "zle -C orig-$cur_widget ${${widgets[$cur_widget]#*:}/:/ }; \ + _zsh_highlight_widget_$cur_widget() { builtin zle orig-$cur_widget -- \"\$@\" && _zsh_highlight }; \ + zle -N $cur_widget _zsh_highlight_widget_$cur_widget";; - _zsh_highlight_bind_widgets + # Builtin widget: override and make it call the builtin ".widget". + builtin) eval "_zsh_highlight_widget_$cur_widget() { builtin zle .$cur_widget -- \"\$@\" && _zsh_highlight }; \ + zle -N $cur_widget _zsh_highlight_widget_$cur_widget";; + + # Default: unhandled case. + *) echo "zsh-syntax-highlighting: unhandled ZLE widget '$cur_widget'" >&2 ;; + esac + done + } + #-------------->8------------------->8------------------->8----------------- + # SPDX-SnippetEnd + + _zsh_highlight_bind_widgets + fi + + unfunction _history-substring-search-function-callable fi _history-substring-search-begin() { @@ -243,10 +295,17 @@ _history-substring-search-begin() { fi # - # Escape and join query parts with wildcard character '*' as separator - # `(j:CHAR:)` join array to string with CHAR as separator + # Escape and join query parts with wildcard character '*' as seperator + # `(j:CHAR:)` join array to string with CHAR as seperator # - local search_pattern="*${(j:*:)_history_substring_search_query_parts[@]//(#m)[\][()|\\*?#<>~^]/\\$MATCH}*" + local search_pattern="${(j:*:)_history_substring_search_query_parts[@]//(#m)[\][()|\\*?#<>~^]/\\$MATCH}*" + + # + # Support anchoring history search to the beginning of the command + # + if [[ -z $HISTORY_SUBSTRING_SEARCH_PREFIXED ]]; then + search_pattern="*${search_pattern}" + fi # # Find all occurrences of the search pattern in the history file. @@ -304,12 +363,21 @@ _history-substring-search-begin() { _history-substring-search-end() { setopt localoptions extendedglob + local highlight_memo= _history_substring_search_result=$BUFFER + if [[ $_history_substring_search_zsh_5_9 -eq 1 ]]; then + highlight_memo='memo=history-substring-search' + fi + # the search was successful so display the result properly by clearing away # existing highlights and moving the cursor to the end of the result buffer if [[ $_history_substring_search_refresh_display -eq 1 ]]; then - region_highlight=() + if [[ -n $highlight_memo ]]; then + region_highlight=( "${(@)region_highlight:#*${highlight_memo}*}" ) + else + region_highlight=() + fi CURSOR=${#BUFFER} fi @@ -329,14 +397,33 @@ _history-substring-search-end() { if [[ $query_part_match_index -le ${#BUFFER:$highlight_start_index} ]]; then highlight_start_index=$(( $highlight_start_index + $query_part_match_index )) highlight_end_index=$(( $highlight_start_index + ${#query_part} )) - region_highlight+=("$(($highlight_start_index - 1)) $(($highlight_end_index - 1)) $_history_substring_search_query_highlight") + region_highlight+=( + "$(($highlight_start_index - 1)) $(($highlight_end_index - 1)) ${_history_substring_search_query_highlight}${highlight_memo:+,$highlight_memo}" + ) fi done fi # For debugging purposes: # zle -R "mn: "$_history_substring_search_match_index" m#: "${#_history_substring_search_matches} - # read -k -t 200 && zle -U $REPLY + # read -k -t 200 && zle -U -- "$REPLY" + + # + # When this function returns, z-sy-h runs its line-pre-redraw hook. It has no + # logic for determining highlight priority, when two different memo= marked + # region highlights overlap; instead, it always prioritises itself. Below is + # a workaround for dealing with it. + # + if [[ $_history_substring_search_zsh_5_9 -eq 1 ]]; then + zle -R + # + # After line redraw with desired highlight, wait for timeout or user input + # before removing search highlight and exiting. This ensures no highlights + # are left lingering after search is finished. + # + read -k -t ${HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_TIMEOUT:-1} && zle -U -- "$REPLY" + region_highlight=( "${(@)region_highlight:#*${highlight_memo}*}" ) + fi # Exit successfully from the history-substring-search-* widgets. return 0 diff --git a/zsh/plugins/history-substring-search/update-from-upstream.zsh b/zsh/plugins/history-substring-search/update-from-upstream.zsh deleted file mode 100755 index 81e1942..0000000 --- a/zsh/plugins/history-substring-search/update-from-upstream.zsh +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/env zsh -# -# update-from-upstream.zsh -# -# This script updates the Oh My Zsh version of the zsh-history-substring-search -# plugin from the independent upstream repo. This is to be run by OMZ developers -# when they want to pull in new changes from upstream to OMZ. It is not run -# during normal use of the plugin. -# -# The official upstream repo is zsh-users/zsh-history-substring-search -# https://github.com/zsh-users/zsh-history-substring-search -# -# This is a zsh script, not a function. Call it with `zsh update-from-upstream.zsh` -# from the command line, running it from within the plugin directory. -# -# You can set the environment variable REPO_PATH to point it at an upstream -# repo you have already prepared. Otherwise, it will do a clean checkout of -# upstream's HEAD to a temporary local repo and use that. - - -# Just bail on any error so we don't have to do extra checking. -# This is a developer-use script, so terse output like that should -# be fine. -set -e - - -upstream_basename=zsh-history-substring-search -plugin_basename=history-substring-search -UPSTREAM_REPO=zsh-users/$upstream_basename -need_repo_cleanup=false -upstream_github_url="https://github.com/$UPSTREAM_REPO" - -if [[ -z "$UPSTREAM_REPO_PATH" ]]; then - # Do a clean checkout - my_tempdir=$(mktemp -d -t omz-update-histsubstrsrch) - UPSTREAM_REPO_PATH="$my_tempdir/$upstream_basename" - git clone "$upstream_github_url" "$UPSTREAM_REPO_PATH" - need_repo_cleanup=true - print "Checked out upstream repo to $UPSTREAM_REPO_PATH" -else - print "Using existing $upstream_basename repo at $UPSTREAM_REPO_PATH" -fi - -upstream="$UPSTREAM_REPO_PATH" - -# Figure out what we're pulling in -upstream_sha=$(cd $upstream && git rev-parse HEAD) -upstream_commit_date=$(cd $upstream && git log -1 --pretty=format:%ci) -upstream_just_date=${${=upstream_commit_date}[1]} -print "upstream SHA: $upstream_sha" -print "upstream commit time: $upstream_commit_date" -print "upstream commit date: $upstream_just_date" -print - -# Copy the files over, using the OMZ plugin's names where needed -cp -v "$upstream"/* . -mv -v zsh-history-substring-search.zsh $plugin_basename.zsh -mv -v zsh-history-substring-search.plugin.zsh $plugin_basename.plugin.zsh - -if [[ $need_repo_cleanup == true ]]; then - print "Removing temporary repo at $my_tempdir" - rm -rf "$my_tempdir" -fi - -# Do OMZ-specific edits - -print -print "Updating files with OMZ-specific stuff" -print - -# OMZ binds the keys as part of the plugin loading - -cat >> $plugin_basename.plugin.zsh <> README.md <` @@ -24,6 +33,9 @@ plugins=(... iterm2) * `iterm2_tab_color_reset` resets the color of iTerm2's current tab back to default. + +For shell integration features see the [official documentation](https://iterm2.com/documentation-shell-integration.html). + ## Contributors - [Aviv Rosenberg](https://github.com/avivrosenberg) diff --git a/zsh/plugins/iterm2/iterm2.plugin.zsh b/zsh/plugins/iterm2/iterm2.plugin.zsh index 9d8e40b..03a63a7 100644 --- a/zsh/plugins/iterm2/iterm2.plugin.zsh +++ b/zsh/plugins/iterm2/iterm2.plugin.zsh @@ -7,6 +7,17 @@ # This plugin is only relevant if the terminal is iTerm2 on OSX. if [[ "$OSTYPE" == darwin* ]] && [[ -n "$ITERM_SESSION_ID" ]] ; then + # maybe make it the default in the future and allow opting out? + if zstyle -t ':omz:plugins:iterm2' shell-integration; then + # Handle $0 according to the standard: + # https://zdharma-continuum.github.io/Zsh-100-Commits-Club/Zsh-Plugin-Standard.html + 0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" + 0="${${(M)0:#/*}:-$PWD/$0}" + + # See official docs: https://iterm2.com/documentation-shell-integration.html + source "${0:A:h}/iterm2_shell_integration.zsh" + fi + ### # Executes an arbitrary iTerm2 command via an escape code sequence. # See https://iterm2.com/documentation-escape-codes.html for all supported commands. diff --git a/zsh/plugins/iterm2/iterm2_shell_integration.zsh b/zsh/plugins/iterm2/iterm2_shell_integration.zsh new file mode 100644 index 0000000..281332e --- /dev/null +++ b/zsh/plugins/iterm2/iterm2_shell_integration.zsh @@ -0,0 +1,178 @@ +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +if [[ -o interactive ]]; then + if [ "${ITERM_ENABLE_SHELL_INTEGRATION_WITH_TMUX-}""$TERM" != "tmux-256color" -a "${ITERM_ENABLE_SHELL_INTEGRATION_WITH_TMUX-}""$TERM" != "screen" -a "${ITERM_SHELL_INTEGRATION_INSTALLED-}" = "" -a "$TERM" != linux -a "$TERM" != dumb ]; then + ITERM_SHELL_INTEGRATION_INSTALLED=Yes + ITERM2_SHOULD_DECORATE_PROMPT="1" + # Indicates start of command output. Runs just before command executes. + iterm2_before_cmd_executes() { + if [ "$TERM_PROGRAM" = "iTerm.app" ]; then + printf "\033]133;C;\r\007" + else + printf "\033]133;C;\007" + fi + } + + iterm2_set_user_var() { + printf "\033]1337;SetUserVar=%s=%s\007" "$1" $(printf "%s" "$2" | base64 | tr -d '\n') + } + + # Users can write their own version of this method. It should call + # iterm2_set_user_var but not produce any other output. + # e.g., iterm2_set_user_var currentDirectory $PWD + # Accessible in iTerm2 (in a badge now, elsewhere in the future) as + # \(user.currentDirectory). + whence -v iterm2_print_user_vars > /dev/null 2>&1 + if [ $? -ne 0 ]; then + iterm2_print_user_vars() { + true + } + fi + + iterm2_print_state_data() { + local _iterm2_hostname="${iterm2_hostname-}" + if [ -z "${iterm2_hostname:-}" ]; then + _iterm2_hostname=$(hostname -f 2>/dev/null) + fi + printf "\033]1337;RemoteHost=%s@%s\007" "$USER" "${_iterm2_hostname-}" + printf "\033]1337;CurrentDir=%s\007" "$PWD" + iterm2_print_user_vars + } + + # Report return code of command; runs after command finishes but before prompt + iterm2_after_cmd_executes() { + printf "\033]133;D;%s\007" "$STATUS" + iterm2_print_state_data + } + + # Mark start of prompt + iterm2_prompt_mark() { + printf "\033]133;A\007" + } + + # Mark end of prompt + iterm2_prompt_end() { + printf "\033]133;B\007" + } + + # There are three possible paths in life. + # + # 1) A command is entered at the prompt and you press return. + # The following steps happen: + # * iterm2_preexec is invoked + # * PS1 is set to ITERM2_PRECMD_PS1 + # * ITERM2_SHOULD_DECORATE_PROMPT is set to 1 + # * The command executes (possibly reading or modifying PS1) + # * iterm2_precmd is invoked + # * ITERM2_PRECMD_PS1 is set to PS1 (as modified by command execution) + # * PS1 gets our escape sequences added to it + # * zsh displays your prompt + # * You start entering a command + # + # 2) You press ^C while entering a command at the prompt. + # The following steps happen: + # * (iterm2_preexec is NOT invoked) + # * iterm2_precmd is invoked + # * iterm2_before_cmd_executes is called since we detected that iterm2_preexec was not run + # * (ITERM2_PRECMD_PS1 and PS1 are not messed with, since PS1 already has our escape + # sequences and ITERM2_PRECMD_PS1 already has PS1's original value) + # * zsh displays your prompt + # * You start entering a command + # + # 3) A new shell is born. + # * PS1 has some initial value, either zsh's default or a value set before this script is sourced. + # * iterm2_precmd is invoked + # * ITERM2_SHOULD_DECORATE_PROMPT is initialized to 1 + # * ITERM2_PRECMD_PS1 is set to the initial value of PS1 + # * PS1 gets our escape sequences added to it + # * Your prompt is shown and you may begin entering a command. + # + # Invariants: + # * ITERM2_SHOULD_DECORATE_PROMPT is 1 during and just after command execution, and "" while the prompt is + # shown and until you enter a command and press return. + # * PS1 does not have our escape sequences during command execution + # * After the command executes but before a new one begins, PS1 has escape sequences and + # ITERM2_PRECMD_PS1 has PS1's original value. + iterm2_decorate_prompt() { + # This should be a raw PS1 without iTerm2's stuff. It could be changed during command + # execution. + ITERM2_PRECMD_PS1="$PS1" + ITERM2_SHOULD_DECORATE_PROMPT="" + + # Add our escape sequences just before the prompt is shown. + # Use ITERM2_SQUELCH_MARK for people who can't mdoify PS1 directly, like powerlevel9k users. + # This is gross but I had a heck of a time writing a correct if statetment for zsh 5.0.2. + local PREFIX="" + if [[ $PS1 == *"$(iterm2_prompt_mark)"* ]]; then + PREFIX="" + elif [[ "${ITERM2_SQUELCH_MARK-}" != "" ]]; then + PREFIX="" + else + PREFIX="%{$(iterm2_prompt_mark)%}" + fi + PS1="$PREFIX$PS1%{$(iterm2_prompt_end)%}" + ITERM2_DECORATED_PS1="$PS1" + } + + iterm2_precmd() { + local STATUS="$?" + if [ -z "${ITERM2_SHOULD_DECORATE_PROMPT-}" ]; then + # You pressed ^C while entering a command (iterm2_preexec did not run) + iterm2_before_cmd_executes + if [ "$PS1" != "${ITERM2_DECORATED_PS1-}" ]; then + # PS1 changed, perhaps in another precmd. See issue 9938. + ITERM2_SHOULD_DECORATE_PROMPT="1" + fi + fi + + iterm2_after_cmd_executes "$STATUS" + + if [ -n "$ITERM2_SHOULD_DECORATE_PROMPT" ]; then + iterm2_decorate_prompt + fi + } + + # This is not run if you press ^C while entering a command. + iterm2_preexec() { + # Set PS1 back to its raw value prior to executing the command. + PS1="$ITERM2_PRECMD_PS1" + ITERM2_SHOULD_DECORATE_PROMPT="1" + iterm2_before_cmd_executes + } + + # If hostname -f is slow on your system set iterm2_hostname prior to + # sourcing this script. We know it is fast on macOS so we don't cache + # it. That lets us handle the hostname changing like when you attach + # to a VPN. + if [ -z "${iterm2_hostname-}" ]; then + if [ "$(uname)" != "Darwin" ]; then + iterm2_hostname=`hostname -f 2>/dev/null` + # Some flavors of BSD (i.e. NetBSD and OpenBSD) don't have the -f option. + if [ $? -ne 0 ]; then + iterm2_hostname=`hostname` + fi + fi + fi + + [[ -z ${precmd_functions-} ]] && precmd_functions=() + precmd_functions=($precmd_functions iterm2_precmd) + + [[ -z ${preexec_functions-} ]] && preexec_functions=() + preexec_functions=($preexec_functions iterm2_preexec) + + iterm2_print_state_data + printf "\033]1337;ShellIntegrationVersion=14;shell=zsh\007" + fi +fi diff --git a/zsh/plugins/iterm2/update b/zsh/plugins/iterm2/update new file mode 100755 index 0000000..da8dae6 --- /dev/null +++ b/zsh/plugins/iterm2/update @@ -0,0 +1,4 @@ +#!/bin/sh + +curl -s -L https://iterm2.com/shell_integration/zsh \ + -o iterm2_shell_integration.zsh diff --git a/zsh/plugins/jira/README.md b/zsh/plugins/jira/README.md index a5633af..f6e2e26 100644 --- a/zsh/plugins/jira/README.md +++ b/zsh/plugins/jira/README.md @@ -1,37 +1,68 @@ -# Jira plugin # - -CLI support for JIRA interaction - -## Description ## +# Jira plugin This plugin provides command line tools for interacting with Atlassian's [JIRA](https://www.atlassian.com/software/jira) bug tracking software. +To use it, add `jira` to the plugins array in your zshrc file: + +```zsh +plugins=(... jira) +``` + The interaction is all done through the web. No local installation of JIRA is necessary. In this document, "JIRA" refers to the JIRA issue tracking server, and `jira` refers to the command this plugin supplies. -## Usage ## +## Usage This plugin supplies one command, `jira`, through which all its features are exposed. Most forms of this command open a JIRA page in your web browser. -``` -jira # performs the default action +## Commands -jira new # opens a new issue -jira dashboard # opens your JIRA dashboard -jira tempo # opens your JIRA Tempo -jira reported [username] # queries for issues reported by a user -jira assigned [username] # queries for issues assigned to a user -jira myissues # queries for you own issues -jira branch # opens an existing issue matching the current branch name - # The branch name may have prefixes ending in "/": "feature/MP-1234", - # and also suffixes starting with "_": "MP-1234_fix_dashboard" - # In both these cases, the issue opened will be "MP-1234" -jira ABC-123 # opens an existing issue -jira ABC-123 m # opens an existing issue for adding a comment +`jira help` or `jira usage` will print the below usage instructions + +| Command | Description | +| :---------------------------- | :------------------------------------------------------- | +| `jira` | Performs the default action | +| `jira new` | Opens a new Jira issue dialogue | +| `jira ABC-123` | Opens an existing issue | +| `jira ABC-123 m` | Opens an existing issue for adding a comment | +| `jira project ABC` | Opens JIRA project summary | +| `jira dashboard [rapid_view]` | Opens your JIRA dashboard | +| `jira mine` | Queries for your own issues | +| `jira tempo` | Opens your JIRA Tempo | +| `jira reported [username]` | Queries for issues reported by a user | +| `jira assigned [username]` | Queries for issues assigned to a user | +| `jira branch` | Opens an existing issue matching the current branch name | +| `jira help` | Prints usage instructions | + + +### Jira Branch usage notes + +The branch name may have prefixes ending in "/": "feature/MP-1234", and also suffixes +starting with "_": "MP-1234_fix_dashboard". In both these cases, the issue opened will be "MP-1234" + +This is also checks if the prefix is in the name, and adds it if not, so: "MP-1234" opens the issue "MP-1234", +"mp-1234" opens the issue "mp-1234", and "1234" opens the issue "MP-1234". + +If your branch naming convention deviates, you can overwrite the jira_branch function to determine and echo the Jira issue key yourself. +Define a function `jira_branch` after sourcing `oh-my-zsh.sh` in your `.zshrc`. +Example: +```zsh +# Determine branch name from naming convention 'type/KEY-123/description'. +function jira_branch() { + # Get name of the branch + issue_arg=$(git rev-parse --abbrev-ref HEAD) + # Strip prefixes like feature/ or bugfix/ + issue_arg=${issue_arg#*/} + # Strip suffixes like /some-branch-description + issue_arg=${issue_arg%%/*} + # Return the value + echo $issue_arg +} ``` -#### Debugging usage #### + +#### Debugging usage These calling forms are for developers' use, and may change at any time. @@ -39,7 +70,7 @@ These calling forms are for developers' use, and may change at any time. jira dumpconfig # displays the effective configuration ``` -## Setup ## +## Setup The URL for your JIRA instance is set by `$JIRA_URL` or a `.jira_url` file. @@ -56,15 +87,17 @@ echo "https://jira.atlassian.com" >> .jira-url (Note: The current implementation only looks in the current directory for `.jira-url` and `.jira-prefix`, not up the path, so if you are in a subdirectory of your project, it will fall back to your default JIRA URL. This will probably change in the future though.) -### Variables ### +### Variables * `$JIRA_URL` - Your JIRA instance's URL * `$JIRA_NAME` - Your JIRA username; used as the default user for `assigned`/`reported` searches * `$JIRA_PREFIX` - Prefix added to issue ID arguments * `$JIRA_RAPID_BOARD` - Set to `true` if you use Rapid Board +* `$JIRA_RAPID_VIEW` - Set the default rapid view; it doesn't work if `$JIRA_RAPID_BOARD` is set to false * `$JIRA_DEFAULT_ACTION` - Action to do when `jira` is called with no arguments; defaults to "new" +* `$JIRA_TEMPO_PATH` - Your JIRA tempo url path; defaults to "/secure/Tempo.jspa" -### Browser ### +### Browser Your default web browser, as determined by how `open_command` handles `http://` URLs, is used for interacting with the JIRA instance. If you change your system's URL handler associations, it will change the browser that `jira` uses. diff --git a/zsh/plugins/jira/_jira b/zsh/plugins/jira/_jira index 1ac3eed..617a3e5 100644 --- a/zsh/plugins/jira/_jira +++ b/zsh/plugins/jira/_jira @@ -4,12 +4,15 @@ local -a _1st_arguments _1st_arguments=( 'new:create a new issue' + 'mine:open my issues' + 'project:open the project' 'dashboard:open the dashboard' 'tempo:open the tempo' 'reported:search for issues reported by a user' 'assigned:search for issues assigned to a user' 'branch:open the issue named after the git branch of the current directory' 'dumpconfig:display effective jira configuration' + 'help:print usage help to stdout' ) _arguments -C \ diff --git a/zsh/plugins/jira/jira.plugin.zsh b/zsh/plugins/jira/jira.plugin.zsh index 22807e0..0c90544 100644 --- a/zsh/plugins/jira/jira.plugin.zsh +++ b/zsh/plugins/jira/jira.plugin.zsh @@ -2,6 +2,46 @@ # # See README.md for details +function _jira_usage() { +cat <| "$ZSH_CACHE_DIR/completions/_jj" &| + +function __jj_prompt_jj() { + local -a flags + flags=("--no-pager") + if zstyle -t ':omz:plugins:jj' ignore-working-copy; then + flags+=("--ignore-working-copy") + fi + command jj $flags "$@" +} + +# convenience functions for themes +function jj_prompt_template_raw() { + __jj_prompt_jj log --no-graph -r @ -T "$@" 2> /dev/null +} + +function jj_prompt_template() { + local out + out=$(jj_prompt_template_raw "$@") || return 1 + echo "${out:gs/%/%%}" +} + +# Aliases (sorted alphabetically) +alias jja='jj abandon' +alias jjb='jj bookmark' +alias jjbc='jj bookmark create' +alias jjbd='jj bookmark delete' +alias jjbf='jj bookmark forget' +alias jjbl='jj bookmark list' +alias jjbm='jj bookmark move' +alias jjbr='jj bookmark rename' +alias jjbs='jj bookmark set' +alias jjbt='jj bookmark track' +alias jjbu='jj bookmark untrack' +alias jjc='jj commit' +alias jjcmsg='jj commit --message' +alias jjd='jj diff' +alias jjdmsg='jj desc --message' +alias jjds='jj desc' +alias jje='jj edit' +alias jjgcl='jj git clone' +alias jjgf='jj git fetch' +alias jjgfa='jj git fetch --all-remotes' +alias jjgp='jj git push' +alias jjgpa='jj git push --all' +alias jjgpd='jj git push --deleted' +alias jjgpt='jj git push --tracked' +alias jjl='jj log' +alias jjla='jj log -r "all()"' +alias jjn='jj new' +alias jjnt='jj new "trunk()"' +alias jjrb='jj rebase' +alias jjrbm='jj rebase -d "trunk()"' +alias jjrs='jj restore' +alias jjrt='cd "$(jj root || echo .)"' +alias jjsp='jj split' +alias jjsq='jj squash' +alias jjst='jj status' diff --git a/zsh/plugins/jsontools/README.md b/zsh/plugins/jsontools/README.md index 6a27400..804edba 100644 --- a/zsh/plugins/jsontools/README.md +++ b/zsh/plugins/jsontools/README.md @@ -8,6 +8,17 @@ To use it, add `jsontools` to the plugins array in your zshrc file: plugins=(... jsontools) ``` +## Requirements + +The plugin uses one of these tools to process JSON data, in the following order: + +- `node` +- `python3` +- `ruby` + +Any of these must be in `$PATH` before the plugin is loaded, otherwise the plugin exits +prematurely and the functions will not be available. + ## Usage Usage is simple... just take your json data and pipe it into the appropriate jsontool: @@ -19,7 +30,7 @@ Usage is simple... just take your json data and pipe it into the appropriate jso ### Supports NDJSON (Newline Delimited JSON) -The plugin also supports [NDJSON](http://ndjson.org/) input, which means all functions +The plugin also supports [NDJSON](https://github.com/ndjson/ndjson-spec) input, which means all functions have an alternative function that reads and processes the input line by line. These functions have the same name except using `ndjson` instead of `json`: diff --git a/zsh/plugins/juju/README.md b/zsh/plugins/juju/README.md index f0c6530..6ee333f 100644 --- a/zsh/plugins/juju/README.md +++ b/zsh/plugins/juju/README.md @@ -126,5 +126,7 @@ Naming convention: - `jaddr [unit_num]`: display app or unit IP address. - `jreld `: display app and unit relation data. - `jclean`: destroy all controllers +- `jcontroller`: display the controller your are connected to. +- `jmodel`: display the model your are connected to. - `wjst [interval_secs] [args_for_watch]`: watch juju status, with optional interval (default: 5s); you may pass additional arguments to `watch`. diff --git a/zsh/plugins/juju/juju.plugin.zsh b/zsh/plugins/juju/juju.plugin.zsh index be8a2c7..3c159da 100644 --- a/zsh/plugins/juju/juju.plugin.zsh +++ b/zsh/plugins/juju/juju.plugin.zsh @@ -98,7 +98,7 @@ jaddr() { elif [[ $# -eq 2 ]]; then # Get unit address juju status "$1/$2" --format=json \ - | jq -r ".applications.\"$1\".units.\"$1/$2\".address" + | jq -r ".applications.\"$1\".units.\"$1/$2\" | .address // .\"public-address\"" else echo "Invalid number of arguments." echo "Usage: jaddr []" @@ -163,10 +163,40 @@ jreld() { juju run "relation-get -r $relid - $2" --unit $2/$3 } +# Return Juju current controller +jcontroller() { + local controller="$(awk '/current-controller/ {print $2}' ~/.local/share/juju/controllers.yaml)" + if [[ -z "$controller" ]]; then + return 1 + fi + + echo $controller + return 0 +} + +# Return Juju current model +jmodel() { + local yqbin="$(whereis yq | awk '{print $2}')" + + if [[ -z "$yqbin" ]]; then + echo "--" + return 1 + fi + + local model="$(yq e ".controllers.$(jcontroller).current-model" < ~/.local/share/juju/models.yaml | cut -d/ -f2)" + + if [[ -z "$model" ]]; then + echo "--" + return 1 + fi + + echo $model + return 0 +} + # Watch juju status, with optional interval (default: 5 sec) wjst() { local interval="${1:-5}" shift $(( $# > 0 )) watch -n "$interval" --color juju status --relations --color "$@" } - diff --git a/zsh/plugins/jump/jump.plugin.zsh b/zsh/plugins/jump/jump.plugin.zsh index c2da114..c2b21e9 100644 --- a/zsh/plugins/jump/jump.plugin.zsh +++ b/zsh/plugins/jump/jump.plugin.zsh @@ -8,8 +8,10 @@ # export MARKPATH=$HOME/.marks + jump() { - builtin cd -P "$MARKPATH/$1" 2>/dev/null || {echo "No such mark: $1"; return 1} + local markpath="$(readlink $MARKPATH/$1)" || {echo "No such mark: $1"; return 1} + builtin cd "$markpath" 2>/dev/null || {echo "Destination does not exist for mark [$1]: $markpath"; return 2} } mark() { @@ -35,12 +37,11 @@ marks() { max=${#link:t} fi done - local printf_markname_template="$(printf -- "%%%us " "$max")" + local printf_markname_template="$(printf -- "%%%us" "$max")" for link in $MARKPATH/{,.}*(@N); do - local markname="$fg[cyan]${link:t}$reset_color" + local markname="$fg[cyan]$(printf -- "$printf_markname_template" "${link:t}")$reset_color" local markpath="$fg[blue]$(readlink $link)$reset_color" - printf -- "$printf_markname_template" "$markname" - printf -- "-> %s\n" "$markpath" + printf -- "%s -> %s\n" "$markname" "$markpath" done } diff --git a/zsh/plugins/k9s/README.md b/zsh/plugins/k9s/README.md new file mode 100644 index 0000000..275048c --- /dev/null +++ b/zsh/plugins/k9s/README.md @@ -0,0 +1,9 @@ +# k9s plugin + +This plugin adds completion support for the [k9s](https://k9scli.io). + +To use it, add `k9s` to the plugins array in your zshrc file: + +```zsh +plugins=(... k9s) +``` diff --git a/zsh/plugins/k9s/k9s.plugin.zsh b/zsh/plugins/k9s/k9s.plugin.zsh new file mode 100644 index 0000000..630d4f7 --- /dev/null +++ b/zsh/plugins/k9s/k9s.plugin.zsh @@ -0,0 +1,14 @@ +if (( ! $+commands[k9s] )); then + return +fi + +# If the completion file does not exist, fake it and load it +if [[ ! -f "$ZSH_CACHE_DIR/completions/_k9s" ]]; then + typeset -g -A _comps + autoload -Uz _k9s + _comps[k9s]=_k9s +fi + +# and then generate it in the background. On first completion, +# the actual completion file will be loaded. +k9s completion zsh >| "$ZSH_CACHE_DIR/completions/_k9s" &| diff --git a/zsh/plugins/kamal/README.md b/zsh/plugins/kamal/README.md new file mode 100644 index 0000000..af57168 --- /dev/null +++ b/zsh/plugins/kamal/README.md @@ -0,0 +1,16 @@ +# Kamal + +This plugin provides completion for [Kamal](https://kamal-deploy.org/) as well as some +aliases for frequent Kamal commands. + +To use it, add kamal to the plugins array of your zshrc file: + +```zsh +plugins=(... kamal) +``` + +## Aliase + +| Alias | Command | Description | +|-----------|----------------------------------|----------------------------------------------------------------------------------| +| kad | `kamal deploy` | Deploy app to servers | diff --git a/zsh/plugins/kamal/_kamal b/zsh/plugins/kamal/_kamal new file mode 100644 index 0000000..52b29e8 --- /dev/null +++ b/zsh/plugins/kamal/_kamal @@ -0,0 +1,691 @@ +#compdef kamal + +# Description +# ----------- +# zsh completion for Kamal (https://kamal-deploy.org/) +# ------------------------------------------------------------------------- +# Authors +# ------- +# * Igor Aleksandrov +# ------------------------------------------------------------------------- +# Inspiration +# ----------- +# * docker-compose ohmyzsh completion script by @sdurrheimer Steve Durrheimer +# ------------------------------------------------------------------------- + +# _kamal_commands() { +# # Only initialize if empty +# if (( ${#kamal_commands} == 0 )); then +# kamal_commands=( +# accessory +# app +# audit +# build +# config +# deploy +# details +# docs +# help +# init +# lock +# proxy +# prune +# redeploy +# registry +# remove +# rollback +# secrets +# server +# setup +# upgrade +# version +# ) +# fi + +# _values 'Kamal commands' $kamal_commands +# } + +typeset -gr _kamal_commands=( + 'accessory:Control accessory services' + 'app:Control application deployment' + 'audit:Audit security of deployment' + 'build:Build and manage app images' + 'config:Show effective configuration' + 'deploy:Deploy app to servers' + 'details:Show details about deployment' + 'docs:Open documentation in browser' + 'help:Show command help' + 'init:Initialize new Kamal project' + 'lock:Manage deployment locks' + 'proxy:Control reverse proxy' + 'prune:Clean up containers and images' + 'redeploy:Redeploy current version' + 'registry:Manage Docker registry access' + 'remove:Remove app from servers' + 'rollback:Rollback to a previous version' + 'secrets:Manage deployment secrets' + 'server:Control server configuration' + 'setup:Setup initial deployment' + 'upgrade:Upgrade deployment' + 'version:Show Kamal version' +) + +# Helper function to display messages +_kamal_message() { + local msg="$1" + _kamal_message "==> $msg" +} + +# Helper function to extract destination names from ./config/deploy.*.yml +_kamal_destinations() { + local -a dests + local file + + # Check if config directory exists + if [[ ! -d "config" ]]; then + _kamal_message "Cannot find Kamal configuration directory at ./config" && return 1 + fi + + for file in config/deploy.*.yml(N); do + [[ $file =~ config/deploy\.(.+)\.yml ]] && dests+=("${match[1]}") + done + + _values 'Destination' $dests +} + +# Define global _kamal_flags array +typeset -ga _kamal_flags +_kamal_flags=( + '(-v --verbose )'{-v,--verbose}'[Detailed logging]' + '(--no-verbose --skip-verbose)'{--no-verbose,--skip-verbose}'[No detailed logging]' + '(-q --quiet --no-quiet --skip-quiet)'{-q,--quiet}'[Minimal logging]' + '(-q --quiet --no-quiet --skip-quiet)'{--no-quiet,--skip-quiet}'[No minimal logging]' + '--version=[Run commands against a specific app version]:version' + '(-p --primary --no-primary --skip-primary)'{-p,--primary}'[Run commands only on primary host instead of all]' + '(-p --primary --no-primary --skip-primary)'{--no-primary,--skip-primary}'[Do not run commands only on primary host]' + '(-h --hosts)'{-h,--hosts=}'[Run commands on these hosts instead of all]:hosts' + '(-r --roles)'{-r,--roles=}'[Run commands on these roles instead of all]:roles' + '(-c --config-file)'{-c,--config-file=}'[Path to config file]:config file:_files' + '(-d --destination)'{-d,--destination=}'[Specify destination to be used for config file]:destination:_kamal_destinations' + '(-H --skip-hooks)'{-H,--skip-hooks}'[Do not run hooks]' +) + +_kamal() { + local context state state_descr line curcontext="$curcontext" + typeset -A opt_args + + local ret=1 + + _arguments -C \ + $_kamal_flags \ + '1: :->command' \ + '*:: :->args' && ret=0 + + case $state in + (command) + # First argument - show available commands + _describe -t kamal-commands "Kamal commands" _kamal_commands && ret=0 + ;; + (args) + # Subsequent arguments - handle based on the command + case $words[1] in + (accessory) + _kamal_accessory && ret=0 + ;; + (app) + _kamal_app && ret=0 + ;; + (audit) + _arguments $_kamal_flags && ret=0 + ;; + (build) + _kamal_build && ret=0 + ;; + (config) + _arguments $_kamal_flags && ret=0 + ;; + (deploy) + _arguments $_kamal_flags && ret=0 + ;; + (details) + _arguments $_kamal_flags && ret=0 + ;; + (docs) + _arguments $_kamal_flags && ret=0 + ;; + (help) + _kamal_help && ret=0 + ;; + (init) + local -a init_flags + init_flags=( + $_kamal_flags + '(--bundle --no-bundle --skip-bundle)--bundle[Add Kamal to the Gemfile and create a bin/kamal binstub]' + '(--bundle --no-bundle --skip-bundle)--no-bundle[Do not add Kamal to the Gemfile and create a bin/kamal binstub]' + '(--bundle --no-bundle --skip-bundle)--skip-bundle[Skip add Kamal to the Gemfile and create a bin/kamal binstub]' + ) + _arguments $init_flags && ret=0 + ;; + (lock) + _kamal_lock && ret=0 + ;; + (proxy) + _kamal_proxy && ret=0 + ;; + (prune) + _kamal_prune && ret=0 + ;; + (redeploy) + _arguments $_kamal_flags && ret=0 + ;; + (registry) + _kamal_registry && ret=0 + ;; + (remove) + local -a remove_flags + remove_flags=( + $_kamal_flags + '(-y --confirmed --no-confirmed --skip-confirmed)'{-y,--confirmed}'[Proceed without confirmation question]' + '(-y --confirmed --no-confirmed --skip-confirmed)--no-confirmed[Proceed without confirmation question]' + '(-y --confirmed --no-confirmed --skip-confirmed)--skip-confirmed[Proceed without confirmation question]' + ) + _arguments $remove_flags && ret=0 + ;; + (rollback) + if (( CURRENT == 2 )); then + _kamal_message "Enter the version to rollback to" && ret=0 + else + _values $_kamal_flags && ret=0 + fi + ;; + (secrets) + _kamal_secrets && ret=0 + ;; + (server) + _kamal_server && ret=0 + ;; + (setup) + local -a setup_flags + setup_flags=( + $_kamal_flags + '(-P --skip-push)'{-P,--skip-push}'[Skip image build and push]' + ) + _arguments $setup_flags && ret=0 + ;; + (upgrade) + local -a upgrade_flags + upgrade_flags=( + $_kamal_flags + '(-y --confirmed --no-confirmed --skip-confirmed)'{-y,--confirmed}'[Proceed without confirmation question]' + '(-y --confirmed --no-confirmed --skip-confirmed)--no-confirmed[Do not proceed without confirmation question]' + '(-y --confirmed --no-confirmed --skip-confirmed)--skip-confirmed[Skip confirmation question]' + '(--rolling --no-rolling --skip-rolling)--rolling[Upgrade one host at a time]' + '(--rolling --no-rolling --skip-rolling)--no-rolling[Do not upgrade one host at a time]' + '(--rolling --no-rolling --skip-rolling)--skip-rolling[Skip rolling upgrade]' + ) + _arguments $upgrade_flags && ret=0 + ;; + (version) + _arguments $_kamal_flags && ret=0 + esac + ;; + esac + + return ret +} + +_kamal_accessory() { + local context state line + typeset -A opt_args + local ret=1 + + # Define accessory subcommands + local -a accessory_subcommands + accessory_subcommands=( + "boot:Boot new accessory service on host (use NAME=all to boot all accessories)" + "details:Show details about accessory on host (use NAME=all to show all accessories)" + "exec:Execute a custom command on servers within the accessory container (use --help to show options)" + "help:Describe subcommands or one specific subcommand" + "logs:Show log lines from accessory on host (use --help to show options)" + "reboot:Reboot existing accessory on host (stop container, remove container, start new container; use NAME=all to boot all accessories)" + "remove:Remove accessory container, image and data directory from host (use NAME=all to remove all accessories)" + "restart:Restart existing accessory container on host" + "start:Start existing accessory container on host" + "stop:Stop existing accessory container on host" + "upgrade:Upgrade accessories from Kamal 1.x to 2.0 (restart them in 'kamal' network)" + ) + + _arguments -C \ + '1: :->subcmd' \ + '*:: :->args' && ret=0 + + case $state in + (subcmd) + _describe -t accessory-commands "Kamal accessory commands" accessory_subcommands && ret=0 + ;; + (args) + case $words[1] in + (boot|details|exec|logs|reboot|remove|restart|start|stop) + # These commands require a NAME parameter + if (( CURRENT == 2 )); then + # At the NAME position - we could add accessory name completion here + # if we had a way to list available accessories + _kamal_message "Specify an accessory name (or 'all' for all accessories)" && ret=0 + elif [[ "$words[1]" == "exec" && CURRENT == 3 ]]; then + # For exec, the 3rd argument is a command + _kamal_message "Enter a command to execute" && ret=0 + elif (( CURRENT > 2 )) && [[ "$words[1]" != "exec" || CURRENT > 3 ]]; then + _values $_kamal_flags && ret=0 + fi + ;; + (help) + # Remove help itself from the list of commands + accessory_subcommands=("${(@)accessory_subcommands:#help*}") + _describe -t accessory-help-commands "Kamal accessory help commands" accessory_subcommands + ;; + (upgrade) + # For upgrade, show flags immediately + _arguments $_kamal_flags && ret=0 + ;; + esac + ;; + esac + + return ret +} + +_kamal_app() { + local context state line + typeset -A opt_args + local ret=1 + + local -a app_subcommands + app_subcommands=( + "boot:Boot app on servers (or reboot app if already running)" + "containers:Show app containers on servers" + "details:Show details about app containers" + "exec:Execute a custom command on servers within the app container (use --help to show options)" + "help:Describe subcommands or one specific subcommand" + "images:Show app images on servers" + "logs:Show log lines from app on servers (use --help to show options)" + "remove:Remove app containers and images from servers" + "stale_containers:Detect app stale containers" + "start:Start existing app container on servers" + "stop:Stop app container on servers" + "version:Show app version currently running on servers" + ) + + _arguments -C \ + '1: :->subcmd' \ + '*:: :->args' && ret=0 + + case $state in + (subcmd) + _describe -t app-commands "Kamal app commands" app_subcommands && ret=0 + ;; + (args) + case $words[1] in + (boot|containers|details|images|logs|remove|stale_containers|start|stop) + _arguments $_kamal_flags && ret=0 + ;; + (exec) + # For exec, the next argument is a command + if (( CURRENT == 2 )); then + _kamal_message "Enter a command to execute" && ret=0 + else + _values $_kamal_flags && ret=0 + fi + ;; + (help) + # Remove help itself from the list of commands + app_subcommands=("${(@)app_subcommands:#help*}") + _describe -t app-help-commands "Kamal app help commands" app_subcommands + ;; + esac + ;; + esac + + return ret +} + +_kamal_build() { + local context state line + typeset -A opt_args + local ret=1 + + local -a build_subcommands + build_subcommands=( + "create:Create a build setup" + "deliver:Build app and push app image to registry then pull image on servers" + "details:Show build setup" + "dev:Build using the working directory, tag it as dirty, and push to local image store." + "help:Describe subcommands or one specific subcommand" + "pull:Pull app image from registry onto servers" + "push:Build and push app image to registry" + "remove:Remove build setup" + ) + + _arguments -C \ + '1: :->subcmd' \ + '*:: :->args' && ret=0 + + case $state in + (subcmd) + _describe -t build-commands "Kamal build commands" build_subcommands && ret=0 + ;; + (args) + case $words[1] in + (create|deliver|details|dev|pull|push|remove) + _arguments $_kamal_flags && ret=0 + ;; + (help) + # Remove help itself from the list of commands + build_subcommands=("${(@)build_subcommands:#help*}") + _describe -t build-help-commands "Kamal build help commands" build_subcommands + ;; + esac + ;; + esac + + return ret +} + +_kamal_help() { + local ret=1 + + # Make sure kamal_commands is initialized properly + # if (( ${#kamal_commands} == 0 )); then + # _kamal_commands >/dev/null + # fi + + # If we already have a command after "help", return without suggestions + if (( CURRENT > 2 )); then + ret=0 + else + local -a help_commands + # Filter out help from the list of commands + help_commands=("${(@)_kamal_commands:#help}") + + _values 'Kamal help' $help_commands && ret=0 + fi + + return ret +} + +_kamal_lock() { + local context state line + typeset -A opt_args + local ret=1 + + local -a lock_subcommands + lock_subcommands=( + "acquire:Acquire the deploy lock" + "help:Describe subcommands or one specific subcommand" + "release:Release the deploy lock" + "status:Report lock status" + ) + + _arguments -C \ + '1: :->subcmd' \ + '*:: :->args' && ret=0 + + case $state in + (subcmd) + _describe -t lock-commands "Kamal lock commands" lock_subcommands && ret=0 + ;; + (args) + case $words[1] in + (acquire) + local -a acquire_flags + acquire_flags=( + $_kamal_flags + '(-m --message)'{-m,--message=}'[A lock message]:message:' # Required flag + ) + _arguments $acquire_flags && ret=0 + ;; + (release|status) + _arguments $_kamal_flags && ret=0 + ;; + (help) + # Remove help itself from the list of commands + lock_subcommands=("${(@)lock_subcommands:#help*}") + _describe -t lock-help-commands "Kamal lock help commands" lock_subcommands + ;; + esac + ;; + esac + + return ret +} + +_kamal_proxy() { + local context state line + typeset -A opt_args + local ret=1 + + local -a proxy_subcommands + proxy_subcommands=( + "boot:Boot proxy on servers" + "boot_config:Manage kamal-proxy boot configuration" + "details:Show details about proxy container from servers" + "help:Describe subcommands or one specific subcommand" + "logs:Show log lines from proxy on servers" + "reboot:Reboot proxy on servers (stop container, remove container, start new container)" + "remove:Remove proxy container and image from servers" + "restart:Restart existing proxy container on servers" + "start:Start existing proxy container on servers" + "stop:Stop existing proxy container on servers" + ) + + _arguments -C \ + '1: :->subcmd' \ + '*:: :->args' && ret=0 + + case $state in + (subcmd) + _describe -t proxy-commands "Kamal proxy commands" proxy_subcommands && ret=0 + ;; + (args) + case $words[1] in + (boot|details|logs|reboot|remove|restart|start|stop) + _arguments $_kamal_flags && ret=0 + ;; + (boot_config) + if (( CURRENT == 2 )); then + local -a boot_config_commands=( + "set:Set boot configuration" + "get:Get boot configuration" + "reset:Reset boot configuration" + ) + _describe -t boot-config-commands "Boot config commands" boot_config_commands && ret=0 + else + _values $_kamal_flags && ret=0 + fi + ;; + (help) + # Remove help itself from the list of commands + proxy_subcommands=("${(@)proxy_subcommands:#help*}") + _describe -t proxy-help-commands "Kamal proxy help commands" proxy_subcommands + ;; + esac + ;; + esac + + return ret +} + +_kamal_prune() { + local context state line + typeset -A opt_args + local ret=1 + + local -a prune_subcommands + prune_subcommands=( + "all:Prune unused images and stopped containers" + "containers:Prune all stopped containers, except the last n (default 5)" + "help:Describe subcommands or one specific subcommand" + "images:Prune unused images" + ) + + _arguments -C \ + '1: :->subcmd' \ + '*:: :->args' && ret=0 + + case $state in + (subcmd) + _describe -t prune-commands "Kamal prune commands" prune_subcommands && ret=0 + ;; + (args) + case $words[1] in + (all|containers|images) + _arguments $_kamal_flags && ret=0 + ;; + (help) + # Remove help itself from the list of commands + prune_subcommands=("${(@)prune_subcommands:#help*}") + _describe -t prune-help-commands "Kamal prune help commands" prune_subcommands + ;; + esac + ;; + esac + + return ret +} + +_kamal_registry() { + local context state line + typeset -A opt_args + local ret=1 + + local -a registry_subcommands + registry_subcommands=( + "help:Describe subcommands or one specific subcommand" + "login:Log in to registry locally and remotely" + "logout:Log out of registry locally and remotely" + ) + + _arguments -C \ + '1: :->subcmd' \ + '*:: :->args' && ret=0 + + case $state in + (subcmd) + _describe -t registry-commands "Kamal registry commands" registry_subcommands && ret=0 + ;; + (args) + case $words[1] in + (help) + # Remove help itself from the list of commands + registry_subcommands=("${(@)registry_subcommands:#help*}") + _describe -t registry-help-commands "Kamal registry help commands" registry_subcommands + ;; + (login|logout) + _arguments $_kamal_flags && ret=0 + ;; + esac + ;; + esac + + return ret +} + +_kamal_secrets() { + local context state line + typeset -A opt_args + local ret=1 + + local -a secrets_subcommands + secrets_subcommands=( + "extract:Extract a single secret from the results of a fetch call" + "fetch:Fetch secrets from a vault" + "help:Describe subcommands or one specific subcommand" + "print:Print the secrets (for debugging)" + ) + + _arguments -C \ + '1: :->subcmd' \ + '*:: :->args' && ret=0 + + case $state in + (subcmd) + _describe -t secrets-commands "Kamal secrets commands" secrets_subcommands && ret=0 + ;; + (args) + case $words[1] in + (fetch) + local -a fetch_flags + fetch_flags=( + $_kamal_flags + '(-a --adapter)'{-a,--adapter=}'[Secret storage adapter]:adapter:(aws-parameter-store)' + ) + _arguments $fetch_flags && ret=0 + ;; + (extract|print) + _arguments $_kamal_flags && ret=0 + ;; + (help) + # Remove help itself from the list of commands + secrets_subcommands=("${(@)secrets_subcommands:#help*}") + _describe -t secrets-help-commands "Kamal secrets help commands" secrets_subcommands + ;; + esac + ;; + esac + + return ret +} + +_kamal_server() { + local context state line + typeset -A opt_args + local ret=1 + + local -a server_subcommands + server_subcommands=( + "bootstrap:Set up Docker to run Kamal apps" + "exec:Run a custom command on the server (use --help to show options)" + "help:Describe subcommands or one specific subcommand" + ) + + local -a server_flags + server_flags=( + $_kamal_flags + '(-i --interactive --no-interactive --skip-interactive)'{-i,--interactive}'[Run the command interactively]' + '(-i --interactive --no-interactive --skip-interactive)--no-interactive[Do not run the command interactively]' + '(-i --interactive --no-interactive --skip-interactive)--skip-interactive[Skip interactive mode]' + ) + + _arguments -C \ + '1: :->subcmd' \ + '*:: :->args' && ret=0 + + case $state in + (subcmd) + _describe -t server-commands "Kamal server commands" server_subcommands && ret=0 + ;; + (args) + case $words[1] in + (bootstrap) + _arguments $server_flags && ret=0 + ;; + (exec) + if (( CURRENT == 2 )); then + # For exec, the next argument is a command + _kamal_message "Enter a command to execute" && ret=0 + else + _values $server_flags && ret=0 + fi + ;; + (help) + # Remove help itself from the list of commands + server_subcommands=("${(@)server_subcommands:#help*}") + _describe -t server-help-commands "Kamal server help commands" server_subcommands + ;; + esac + ;; + esac + + return ret +} + +_kamal "$@" \ No newline at end of file diff --git a/zsh/plugins/kamal/kamal.plugin.zsh b/zsh/plugins/kamal/kamal.plugin.zsh new file mode 100644 index 0000000..e21ab4f --- /dev/null +++ b/zsh/plugins/kamal/kamal.plugin.zsh @@ -0,0 +1,25 @@ +# Find kamal binary (local ./bin/kamal or global) +function _kamal_command () { + if [ -x "./bin/kamal" ]; then + ./bin/kamal "$@" + else + command kamal "$@" + fi +} + +function which-kamal() { + if [ -x "./bin/kamal" ]; then + echo "Using local ./bin/kamal" + else + echo "Using global $(command -v kamal)" + fi +} + +# Use `_kamal_command`` function for `kamal` command +alias kamal='_kamal_command' + +# Aliases +alias kad='kamal deploy' + +# Hook up completion +compdef _kamal_command=kamal diff --git a/zsh/plugins/keychain/keychain.plugin.zsh b/zsh/plugins/keychain/keychain.plugin.zsh index f122f79..23cf1af 100644 --- a/zsh/plugins/keychain/keychain.plugin.zsh +++ b/zsh/plugins/keychain/keychain.plugin.zsh @@ -19,8 +19,16 @@ function { # load additional options zstyle -a :omz:plugins:keychain options options - # start keychain... - keychain ${^options:-} --agents ${agents:-gpg} ${^identities} --host $SHORT_HOST + # Check keychain version to decide whether to use --agents + local version_string=$(keychain --version 2>&1) + # start keychain, only use --agents for versions below 2.9.0 + autoload -Uz is-at-least + if [[ "$version_string" =~ 'keychain ([0-9]+\.[0-9]+)' ]] && \ + is-at-least 2.9 "$match[1]"; then + keychain ${^options:-} ${^identities} --host $SHORT_HOST + else + keychain ${^options:-} --agents ${agents:-gpg} ${^identities} --host $SHORT_HOST + fi # Get the filenames to store/lookup the environment from _keychain_env_sh="$HOME/.keychain/$SHORT_HOST-sh" diff --git a/zsh/plugins/kind/README.md b/zsh/plugins/kind/README.md new file mode 100644 index 0000000..4902464 --- /dev/null +++ b/zsh/plugins/kind/README.md @@ -0,0 +1,22 @@ +# Kind plugin + +This plugin adds completion for the [Kind](https://kind.sigs.k8s.io/) tool, as well +as a few aliases for easier use. + +To use it, add `kind` to the plugins array in your zshrc file: + +```zsh +plugins=(... kind) +``` + +## Aliases + +| Alias | Command | +| ------- | ---------------------------- | +| `kicc` | `kind create cluster` | +| `kiccn` | `kind create cluster --name` | +| `kigc` | `kind get clusters` | +| `kidc` | `kind delete cluster` | +| `kidcn` | `kind delete cluster --name` | +| `kidca` | `kind delete clusters -A` | +| `kigk` | `kind get kubeconfig` | diff --git a/zsh/plugins/kind/kind.plugin.zsh b/zsh/plugins/kind/kind.plugin.zsh new file mode 100644 index 0000000..183eb7b --- /dev/null +++ b/zsh/plugins/kind/kind.plugin.zsh @@ -0,0 +1,23 @@ +if (( ! $+commands[kind] )); then + return +fi + +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `kind`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_kind" ]]; then + typeset -g -A _comps + autoload -Uz _kind + _comps[kind]=_kind +fi + +# Generate and load kind completion +kind completion zsh >! "$ZSH_CACHE_DIR/completions/_kind" &| + +# Register aliases +alias kicc="kind create cluster" +alias kiccn="kind create cluster --name" +alias kigc="kind get clusters" +alias kidc="kind delete cluster" +alias kidcn="kind delete cluster --name" +alias kidca="kind delete clusters -A" +alias kigk="kind get kubeconfig" diff --git a/zsh/plugins/kitchen/_kitchen b/zsh/plugins/kitchen/_kitchen index d93d93d..64c01e3 100644 --- a/zsh/plugins/kitchen/_kitchen +++ b/zsh/plugins/kitchen/_kitchen @@ -1,6 +1,6 @@ #compdef kitchen # ------------------------------------------------------------------------------ -# Copyright (c) 2014 Github zsh-users - https://github.com/zsh-users +# Copyright (c) 2014 GitHub zsh-users - https://github.com/zsh-users # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/zsh/plugins/kitty/README.md b/zsh/plugins/kitty/README.md new file mode 100644 index 0000000..ec9e375 --- /dev/null +++ b/zsh/plugins/kitty/README.md @@ -0,0 +1,23 @@ +# Kitty plugin + +This plugin adds a few aliases and functions that are useful for users of the [Kitty](https://sw.kovidgoyal.net/kitty/) terminal. + +To use it, add _kitty_ to the plugins array of your zshrc file: +``` +plugins=(... kitty) +``` + +## Plugin commands + +* `kssh` + Runs a kitten ssh session that ensures your terminfo settings are copied + correctly to the remote hose. +* `kssh-slow` + A slower form of `kssh` that should always work. Use this if `kssh` fails + to set terminfo correctly for you on the remote host. +* `kitty-theme` + Browse and change the theme of your Kitty terminal. + +## Contributors + +- [Ian Chesal](https://github.com/ianchesal) diff --git a/zsh/plugins/kitty/kitty.plugin.zsh b/zsh/plugins/kitty/kitty.plugin.zsh new file mode 100644 index 0000000..1094236 --- /dev/null +++ b/zsh/plugins/kitty/kitty.plugin.zsh @@ -0,0 +1,16 @@ +##################################################### +# Kitty plugin for oh-my-zsh # +##################################################### + +if [[ "$TERM" == 'xterm-kitty' ]]; then + ## kssh + # Use this when your terminfo isn't recognized on remote hosts. + # See: https://sw.kovidgoyal.net/kitty/faq/#i-get-errors-about-the-terminal-being-unknown-or-opening-the-terminal-failing-when-sshing-into-a-different-computer + alias kssh="kitty +kitten ssh" + compdef kssh='ssh' + # Use this if kssh fails + alias kssh-slow="infocmp -a xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin" + + # Change the colour theme + alias kitty-theme="kitty +kitten themes" +fi diff --git a/zsh/plugins/kn/kn.plugin.zsh b/zsh/plugins/kn/kn.plugin.zsh index f60177d..483d1d6 100644 --- a/zsh/plugins/kn/kn.plugin.zsh +++ b/zsh/plugins/kn/kn.plugin.zsh @@ -4,5 +4,5 @@ if [ $commands[kn] ]; then source <(kn completion zsh) - compdef _kn kn + compdef _kn kn fi diff --git a/zsh/plugins/kompose/README.md b/zsh/plugins/kompose/README.md new file mode 100644 index 0000000..e86d926 --- /dev/null +++ b/zsh/plugins/kompose/README.md @@ -0,0 +1,12 @@ +# kompose + +This plugin provides completion for [kompose](https://github.com/kubernetes/kompose), +to migrate from docker compose to Kubernetes resource definitions. + +To use it, add `kompose` to the plugins array in your zshrc file. + +``` +plugins=(... kompose) +``` + +**Author:** [@kevinkirkup](https://github.com/kevinkirkup) diff --git a/zsh/plugins/kompose/kompose.plugin.zsh b/zsh/plugins/kompose/kompose.plugin.zsh new file mode 100644 index 0000000..764e724 --- /dev/null +++ b/zsh/plugins/kompose/kompose.plugin.zsh @@ -0,0 +1,3 @@ +if [ $commands[kompose] ]; then + source <(kompose completion zsh) +fi diff --git a/zsh/plugins/kube-ps1/LICENSE b/zsh/plugins/kube-ps1/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/zsh/plugins/kube-ps1/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/zsh/plugins/kube-ps1/README.md b/zsh/plugins/kube-ps1/README.md index 1ed3e44..ef6d781 100644 --- a/zsh/plugins/kube-ps1/README.md +++ b/zsh/plugins/kube-ps1/README.md @@ -1,50 +1,82 @@ -kube-ps1: Kubernetes prompt for bash and zsh -============================================ +# kube-ps1: Kubernetes prompt for bash and zsh + +![GitHub Release](https://img.shields.io/github/v/release/jonmosco/kube-ps1) +[![CI](https://github.com/jonmosco/kube-ps1/actions/workflows/ci.yml/badge.svg)](https://github.com/jonmosco/kube-ps1/actions/workflows/ci.yml) A script that lets you add the current Kubernetes context and namespace configured on `kubectl` to your Bash/Zsh prompt strings (i.e. the `$PS1`). Inspired by several tools used to simplify usage of `kubectl`. +![prompt demo](img/kube-ps1-demo.gif) + ## Installing -### MacOS +### Packages + +### MacOS Brew Ports Homebrew package manager: +```sh +brew update +brew install kube-ps1 ``` -$ brew update -$ brew install kube-ps1 + +### Arch Linux + +AUR Package available at [https://aur.archlinux.org/packages/kube-ps1/](https://aur.archlinux.org/packages/kube-ps1/). + +### Oh My Zsh + +https://github.com/ohmyzsh/ohmyzsh + +kube-ps1 is included as a plugin in the oh-my-zsh project. To enable it, edit your `~/.zshrc` and +add the plugin: + +```bash +plugins=( + kube-ps1 +) +PROMPT='$(kube_ps1)'$PROMPT # or RPROMPT='$(kube_ps1)' ``` -### From Source + +## Zsh zinit plugin + +### Using [zinit](https://github.com/zdharma-continuum/zinit) + +Update `.zshrc` with: + +```sh +zinit light jonmosco/kube-ps1 +PROMPT='$(kube_ps1)'$PROMPT # or RPROMPT='$(kube_ps1)' +``` + +### Fig + +Install `kube-ps1` in zsh, bash, or fish with one click. + + + +### From Source (git clone) 1. Clone this repository 2. Source the kube-ps1.sh in your `~/.zshrc` or your `~/.bashrc` -### Arch Linux -AUR Package available at [https://aur.archlinux.org/packages/kube-ps1/](https://aur.archlinux.org/packages/kube-ps1/). - #### Zsh + ```sh source /path/to/kube-ps1.sh -PROMPT='$(kube_ps1)'$PROMPT +PROMPT='$(kube_ps1)'$PROMPT # or RPROMPT='$(kube_ps1)' ``` + #### Bash + ```sh source /path/to/kube-ps1.sh PS1='[\u@\h \W $(kube_ps1)]\$ ' ``` -### Zsh Plugin Managers - -#### Using [zplugin](https://github.com/zdharma/zplugin) - -Update `.zshrc` with: -```sh -zplugin light jonmosco/kube-ps1 -PROMPT='$(kube_ps1)'$PROMPT -``` - ## Requirements The default prompt assumes you have the `kubectl` command line utility installed. @@ -55,22 +87,23 @@ Official installation instructions and binaries are available: If using this with OpenShift, the `oc` tool needs installed. It can be obtained from brew ports: -``` +```sh brew install openshift-cli ``` + or the source can be downloaded: -[OC Client Tools](https://www.openshift.org/download.html) +[OC Client Tools](https://github.com/okd-project/okd/releases) -Set the binary to `oc` with the following environment variable: +Set the binary to `oc` with the following variable: -``` +```sh KUBE_PS1_BINARY=oc ``` If neither binary is available, the prompt will print the following: -``` +```sh (|BINARY-N/A:N/A) ``` @@ -91,13 +124,13 @@ tmux, and like the functionality provided by kube-ps1, checkout the The default prompt layout is: -``` +```sh (|:) ``` If the current-context is not set, kube-ps1 will return the following: -``` +```sh (|N/A:N/A) ``` @@ -108,7 +141,7 @@ run `kubeoff`. To disable the prompt for all shell sessions, run `kubeoff -g`. You can enable it again in the current shell by running `kubeon`, and globally with `kubeon -g`. -``` +```sh kubeon : turn on kube-ps1 status for this shell. Takes precedence over global setting for current session kubeon -g : turn on kube-ps1 status globally @@ -117,38 +150,69 @@ kubeoff : turn off kube-ps1 status for this shell. Takes precedence over kubeoff -g : turn off kube-ps1 status globally ``` +## Symbol + +The default symbols are UTF8 and should work with most fonts. If you want to use the Kubernetes and OpenShift +glyphs, you need to install a patched font that contains the glyph. [Nerd Fonts](https://www.nerdfonts.com/) provides both glyphs. Follow their installation instructions to install the patched font. + +`KUBE_PS1_SYMBOL_CUSTOM` options + +| Options | Symbol | Description | +| ------------- | ------ | ----------- | +| default (empty string) | ⎈ | Default symbol (Unicode `\u2388`) | +| img | ☸️ | Symbol often used to represent Kubernetes (Unicode `\u2638`) | +| oc | ![openshift-glyph](img/openshift-glyph.png) | Symbol representing OpenShift (Unicode `\ue7b7`) | +| k8s | ![k8s-glyph](img/k8s-glyph.png) | Symbol representing Kubernetes (Unicode `\ue7b7`) | + +To set the symbol to one of the custom glyphs, add the following to your `~/.bashrc` or `~/.zshrc`: + +```sh +KUBE_PS1_SYMBOL_CUSTOM=img +``` + +To set the symbol to the default, set the `KUBE_PS1_SYMBOL` to an empty string. + +Heres a demo of the symbols in action: +![kube-ps1-symbols](img/kube-ps1-symbol-demo.gif) + +If the font is not properly installed, and the glyph is not available, it will display an empty set of brackets or similar: + +```sh + echo -n "\ue7b7" + +``` + ## Customization The default settings can be overridden in `~/.bashrc` or `~/.zshrc` by setting -the following environment variables: +the following variables: | Variable | Default | Meaning | | :------- | :-----: | ------- | | `KUBE_PS1_BINARY` | `kubectl` | Default Kubernetes binary | | `KUBE_PS1_NS_ENABLE` | `true` | Display the namespace. If set to `false`, this will also disable `KUBE_PS1_DIVIDER` | -| `KUBE_PS1_PREFIX` | `(` | Prompt opening character | -| `KUBE_PS1_SYMBOL_ENABLE` | `true ` | Display the prompt Symbol. If set to `false`, this will also disable `KUBE_PS1_SEPARATOR` | +| `KUBE_PS1_PREFIX` | `(` | Prompt opening character | +| `KUBE_PS1_SYMBOL_ENABLE` | `true` | Display the prompt Symbol. If set to `false`, this will also disable `KUBE_PS1_SEPARATOR` | | `KUBE_PS1_SYMBOL_PADDING` | `false` | Adds a space (padding) after the symbol to prevent clobbering prompt characters | -| `KUBE_PS1_SYMBOL_DEFAULT` | `⎈ ` | Default prompt symbol. Unicode `\u2388` | -| `KUBE_PS1_SYMBOL_USE_IMG` | `false` | ☸️ , Unicode `\u2638` as the prompt symbol | +| `KUBE_PS1_SYMBOL_CUSTOM` | `⎈` | Change the Default prompt symbol. Unicode `\u2388`. Options are `k8s`, `img`, `oc` | +| `KUBE_PS1_SYMBOL_COLOR` | `blue` | Change the Default symbol color. | | `KUBE_PS1_SEPARATOR` | | | Separator between symbol and context name | | `KUBE_PS1_DIVIDER` | `:` | Separator between context and namespace | | `KUBE_PS1_SUFFIX` | `)` | Prompt closing character | | `KUBE_PS1_CLUSTER_FUNCTION` | No default, must be user supplied | Function to customize how cluster is displayed | | `KUBE_PS1_NAMESPACE_FUNCTION` | No default, must be user supplied | Function to customize how namespace is displayed | - -For terminals that do not support UTF-8, the symbol will be replaced with the -string `k8s`. +| `KUBE_PS1_CTX_COLOR_FUNCTION` | No default, must be user supplied | Function to customize context color based on context name | +| `KUBE_PS1_HIDE_IF_NOCONTEXT` | `false` | Hide the kube-ps1 prompt if no context is set | To disable a feature, set it to an empty string: -``` +```sh KUBE_PS1_SEPARATOR='' ``` ## Colors -The default colors are set with the following environment variables: +The default colors are set with the following variables: | Variable | Default | Meaning | | :------- | :-----: | ------- | @@ -166,13 +230,13 @@ namespace. Set the variable to an empty string if you do not want color for each prompt section: -``` +```sh KUBE_PS1_CTX_COLOR='' ``` Names are usable for the following colors: -``` +```text black, red, green, yellow, blue, magenta, cyan ``` @@ -216,6 +280,45 @@ export KUBE_PS1_NAMESPACE_FUNCTION=get_namespace_upper In both cases, the variable is set to the name of the function, and you must have defined the function in your shell configuration before kube_ps1 is called. The function must accept a single parameter and echo out the final value. +## Dynamic Context Colors + +You can set different colors for different contexts using the +`KUBE_PS1_CTX_COLOR_FUNCTION` variable. This is useful for color-coding +contexts to make production environments stand out visually. + +For example, to make production contexts red and development contexts green: + +```sh +function kube_ps1_ctx_color() { + local context="$1" + + case "$context" in + *prod*) + echo "red" + ;; + *dev*) + echo "green" + ;; + *staging*|*stg*) + echo "yellow" + ;; + *) + echo "cyan" # default color for other contexts + ;; + esac +} + +export KUBE_PS1_CTX_COLOR_FUNCTION=kube_ps1_ctx_color +``` + +The function receives the context name as the first parameter and should echo +the desired color name. All color options supported by `KUBE_PS1_CTX_COLOR` are +available, including named colors (black, red, green, yellow, blue, magenta, +cyan, white) and 256-color codes (0-256). + +If `KUBE_PS1_CTX_COLOR_FUNCTION` is not set, kube-ps1 will use the value of +`KUBE_PS1_CTX_COLOR` (default: red). + ### Bug Reports and shell configuration Due to the vast ways of customizing the shell, please try the prompt with a @@ -224,18 +327,28 @@ minimal configuration before submitting a bug report. This can be done as follows for each shell before loading kube-ps1: Bash: -```bash + +```sh bash --norc ``` Zsh: -```bash + +```sh zsh -f or zsh --no-rcs ``` -## Contributors +For the prompt symbol, a patched font that contains the glyphs must be installed. +[Nerd Fonts Downloads](https://www.nerdfonts.com/font-downloads) provides patched +fonts containing the glyphs. Please consult their documentation for this, support +is out of scope for this project. -* [Ahmet Alp Balkan](https://github.com/ahmetb) -* Jared Yanovich +### Contributors + +Thank you to everyone in the community for their contributions to kube-ps1! + + + + diff --git a/zsh/plugins/kube-ps1/kube-ps1.plugin.zsh b/zsh/plugins/kube-ps1/kube-ps1.plugin.zsh index 894e0f7..9dcd6da 100644 --- a/zsh/plugins/kube-ps1/kube-ps1.plugin.zsh +++ b/zsh/plugins/kube-ps1/kube-ps1.plugin.zsh @@ -3,7 +3,7 @@ # Kubernetes prompt helper for bash/zsh # Displays current context and namespace -# Copyright 2021 Jon Mosco +# Copyright 2026 Jon Mosco # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -24,9 +24,9 @@ # Override these values in ~/.zshrc or ~/.bashrc KUBE_PS1_BINARY="${KUBE_PS1_BINARY:-kubectl}" KUBE_PS1_SYMBOL_ENABLE="${KUBE_PS1_SYMBOL_ENABLE:-true}" -KUBE_PS1_SYMBOL_DEFAULT=${KUBE_PS1_SYMBOL_DEFAULT:-$'\u2388'} KUBE_PS1_SYMBOL_PADDING="${KUBE_PS1_SYMBOL_PADDING:-false}" -KUBE_PS1_SYMBOL_USE_IMG="${KUBE_PS1_SYMBOL_USE_IMG:-false}" +KUBE_PS1_SYMBOL_COLOR="${KUBE_PS1_SYMBOL_COLOR:-}" + KUBE_PS1_NS_ENABLE="${KUBE_PS1_NS_ENABLE:-true}" KUBE_PS1_CONTEXT_ENABLE="${KUBE_PS1_CONTEXT_ENABLE:-true}" KUBE_PS1_PREFIX="${KUBE_PS1_PREFIX-(}" @@ -34,28 +34,28 @@ KUBE_PS1_SEPARATOR="${KUBE_PS1_SEPARATOR-|}" KUBE_PS1_DIVIDER="${KUBE_PS1_DIVIDER-:}" KUBE_PS1_SUFFIX="${KUBE_PS1_SUFFIX-)}" -KUBE_PS1_SYMBOL_COLOR="${KUBE_PS1_SYMBOL_COLOR-blue}" -KUBE_PS1_CTX_COLOR="${KUBE_PS1_CTX_COLOR-red}" -KUBE_PS1_NS_COLOR="${KUBE_PS1_NS_COLOR-cyan}" -KUBE_PS1_BG_COLOR="${KUBE_PS1_BG_COLOR}" +KUBE_PS1_HIDE_IF_NOCONTEXT="${KUBE_PS1_HIDE_IF_NOCONTEXT:-false}" -KUBE_PS1_KUBECONFIG_CACHE="${KUBECONFIG}" -KUBE_PS1_DISABLE_PATH="${HOME}/.kube/kube-ps1/disabled" -KUBE_PS1_LAST_TIME=0 -KUBE_PS1_CLUSTER_FUNCTION="${KUBE_PS1_CLUSTER_FUNCTION}" -KUBE_PS1_NAMESPACE_FUNCTION="${KUBE_PS1_NAMESPACE_FUNCTION}" +_KUBE_PS1_KUBECONFIG_CACHE="${KUBECONFIG}" +_KUBE_PS1_DISABLE_PATH="${HOME}/.kube/kube-ps1/disabled" +_KUBE_PS1_LAST_TIME=0 # Determine our shell -if [ "${ZSH_VERSION-}" ]; then - KUBE_PS1_SHELL="zsh" -elif [ "${BASH_VERSION-}" ]; then - KUBE_PS1_SHELL="bash" -fi +_kube_ps1_shell_type() { + local _KUBE_PS1_SHELL_TYPE + + if [ "${ZSH_VERSION-}" ]; then + _KUBE_PS1_SHELL_TYPE="zsh" + elif [ "${BASH_VERSION-}" ]; then + _KUBE_PS1_SHELL_TYPE="bash" + fi + echo $_KUBE_PS1_SHELL_TYPE +} _kube_ps1_init() { - [[ -f "${KUBE_PS1_DISABLE_PATH}" ]] && KUBE_PS1_ENABLED=off + [[ -f "${_KUBE_PS1_DISABLE_PATH}" ]] && KUBE_PS1_ENABLED=off - case "${KUBE_PS1_SHELL}" in + case "$(_kube_ps1_shell_type)" in "zsh") _KUBE_PS1_OPEN_ESC="%{" _KUBE_PS1_CLOSE_ESC="%}" @@ -63,7 +63,7 @@ _kube_ps1_init() { _KUBE_PS1_DEFAULT_FG="%f" setopt PROMPT_SUBST autoload -U add-zsh-hook - add-zsh-hook precmd _kube_ps1_update_cache + add-zsh-hook precmd _kube_ps1_prompt_update zmodload -F zsh/stat b:zstat zmodload zsh/datetime ;; @@ -72,75 +72,75 @@ _kube_ps1_init() { _KUBE_PS1_CLOSE_ESC=$'\002' _KUBE_PS1_DEFAULT_BG=$'\033[49m' _KUBE_PS1_DEFAULT_FG=$'\033[39m' - [[ $PROMPT_COMMAND =~ _kube_ps1_update_cache ]] || PROMPT_COMMAND="_kube_ps1_update_cache;${PROMPT_COMMAND:-:}" + [[ $PROMPT_COMMAND =~ _kube_ps1_prompt_update ]] || PROMPT_COMMAND="_kube_ps1_prompt_update;${PROMPT_COMMAND:-:}" ;; esac } _kube_ps1_color_fg() { - local KUBE_PS1_FG_CODE + local _KUBE_PS1_FG_CODE case "${1}" in - black) KUBE_PS1_FG_CODE=0;; - red) KUBE_PS1_FG_CODE=1;; - green) KUBE_PS1_FG_CODE=2;; - yellow) KUBE_PS1_FG_CODE=3;; - blue) KUBE_PS1_FG_CODE=4;; - magenta) KUBE_PS1_FG_CODE=5;; - cyan) KUBE_PS1_FG_CODE=6;; - white) KUBE_PS1_FG_CODE=7;; + black) _KUBE_PS1_FG_CODE=0;; + red) _KUBE_PS1_FG_CODE=1;; + green) _KUBE_PS1_FG_CODE=2;; + yellow) _KUBE_PS1_FG_CODE=3;; + blue) _KUBE_PS1_FG_CODE=4;; + magenta) _KUBE_PS1_FG_CODE=5;; + cyan) _KUBE_PS1_FG_CODE=6;; + white) _KUBE_PS1_FG_CODE=7;; # 256 - [0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-6]) KUBE_PS1_FG_CODE="${1}";; - *) KUBE_PS1_FG_CODE=default + [0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-6]) _KUBE_PS1_FG_CODE="${1}";; + *) _KUBE_PS1_FG_CODE=default esac - if [[ "${KUBE_PS1_FG_CODE}" == "default" ]]; then - KUBE_PS1_FG_CODE="${_KUBE_PS1_DEFAULT_FG}" + if [[ "${_KUBE_PS1_FG_CODE}" == "default" ]]; then + _KUBE_PS1_FG_CODE="${_KUBE_PS1_DEFAULT_FG}" return - elif [[ "${KUBE_PS1_SHELL}" == "zsh" ]]; then - KUBE_PS1_FG_CODE="%F{$KUBE_PS1_FG_CODE}" - elif [[ "${KUBE_PS1_SHELL}" == "bash" ]]; then + elif [[ "$(_kube_ps1_shell_type)" == "zsh" ]]; then + _KUBE_PS1_FG_CODE="%F{$_KUBE_PS1_FG_CODE}" + elif [[ "$(_kube_ps1_shell_type)" == "bash" ]]; then if tput setaf 1 &> /dev/null; then - KUBE_PS1_FG_CODE="$(tput setaf ${KUBE_PS1_FG_CODE})" - elif [[ $KUBE_PS1_FG_CODE -ge 0 ]] && [[ $KUBE_PS1_FG_CODE -le 256 ]]; then - KUBE_PS1_FG_CODE="\033[38;5;${KUBE_PS1_FG_CODE}m" + _KUBE_PS1_FG_CODE="$(tput setaf "${_KUBE_PS1_FG_CODE}")" + elif [[ $_KUBE_PS1_FG_CODE -ge 0 ]] && [[ $_KUBE_PS1_FG_CODE -le 256 ]]; then + _KUBE_PS1_FG_CODE="\033[38;5;${_KUBE_PS1_FG_CODE}m" else - KUBE_PS1_FG_CODE="${_KUBE_PS1_DEFAULT_FG}" + _KUBE_PS1_FG_CODE="${_KUBE_PS1_DEFAULT_FG}" fi fi - echo ${_KUBE_PS1_OPEN_ESC}${KUBE_PS1_FG_CODE}${_KUBE_PS1_CLOSE_ESC} + echo "${_KUBE_PS1_OPEN_ESC}${_KUBE_PS1_FG_CODE}${_KUBE_PS1_CLOSE_ESC}" } _kube_ps1_color_bg() { - local KUBE_PS1_BG_CODE + local _KUBE_PS1_BG_CODE case "${1}" in - black) KUBE_PS1_BG_CODE=0;; - red) KUBE_PS1_BG_CODE=1;; - green) KUBE_PS1_BG_CODE=2;; - yellow) KUBE_PS1_BG_CODE=3;; - blue) KUBE_PS1_BG_CODE=4;; - magenta) KUBE_PS1_BG_CODE=5;; - cyan) KUBE_PS1_BG_CODE=6;; - white) KUBE_PS1_BG_CODE=7;; + black) _KUBE_PS1_BG_CODE=0;; + red) _KUBE_PS1_BG_CODE=1;; + green) _KUBE_PS1_BG_CODE=2;; + yellow) _KUBE_PS1_BG_CODE=3;; + blue) _KUBE_PS1_BG_CODE=4;; + magenta) _KUBE_PS1_BG_CODE=5;; + cyan) _KUBE_PS1_BG_CODE=6;; + white) _KUBE_PS1_BG_CODE=7;; # 256 - [0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-6]) KUBE_PS1_BG_CODE="${1}";; - *) KUBE_PS1_BG_CODE=$'\033[0m';; + [0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-6]) _KUBE_PS1_BG_CODE="${1}";; + *) _KUBE_PS1_BG_CODE=$'\033[0m';; esac - if [[ "${KUBE_PS1_BG_CODE}" == "default" ]]; then - KUBE_PS1_FG_CODE="${_KUBE_PS1_DEFAULT_BG}" + if [[ "${_KUBE_PS1_BG_CODE}" == "default" ]]; then + _KUBE_PS1_FG_CODE="${_KUBE_PS1_DEFAULT_BG}" return - elif [[ "${KUBE_PS1_SHELL}" == "zsh" ]]; then - KUBE_PS1_BG_CODE="%K{$KUBE_PS1_BG_CODE}" - elif [[ "${KUBE_PS1_SHELL}" == "bash" ]]; then + elif [[ "$(_kube_ps1_shell_type)" == "zsh" ]]; then + _KUBE_PS1_BG_CODE="%K{$_KUBE_PS1_BG_CODE}" + elif [[ "$(_kube_ps1_shell_type)" == "bash" ]]; then if tput setaf 1 &> /dev/null; then - KUBE_PS1_BG_CODE="$(tput setab ${KUBE_PS1_BG_CODE})" - elif [[ $KUBE_PS1_BG_CODE -ge 0 ]] && [[ $KUBE_PS1_BG_CODE -le 256 ]]; then - KUBE_PS1_BG_CODE="\033[48;5;${KUBE_PS1_BG_CODE}m" + _KUBE_PS1_BG_CODE="$(tput setab "${_KUBE_PS1_BG_CODE}")" + elif [[ $_KUBE_PS1_BG_CODE -ge 0 ]] && [[ $_KUBE_PS1_BG_CODE -le 256 ]]; then + _KUBE_PS1_BG_CODE="\033[48;5;${_KUBE_PS1_BG_CODE}m" else - KUBE_PS1_BG_CODE="${DEFAULT_BG}" + _KUBE_PS1_BG_CODE="${DEFAULT_BG}" fi fi - echo ${OPEN_ESC}${KUBE_PS1_BG_CODE}${CLOSE_ESC} + echo "${_KUBE_PS1_OPEN_ESC}${_KUBE_PS1_BG_CODE}${_KUBE_PS1_CLOSE_ESC}" } _kube_ps1_binary_check() { @@ -148,38 +148,60 @@ _kube_ps1_binary_check() { } _kube_ps1_symbol() { + # Exit early if symbol display is disabled [[ "${KUBE_PS1_SYMBOL_ENABLE}" == false ]] && return - case "${KUBE_PS1_SHELL}" in - bash) - if ((BASH_VERSINFO[0] >= 4)) && [[ $'\u2388' != "\\u2388" ]]; then - KUBE_PS1_SYMBOL="${KUBE_PS1_SYMBOL_DEFAULT}" - KUBE_PS1_SYMBOL_IMG=$'\u2638\ufe0f' - else - KUBE_PS1_SYMBOL=$'\xE2\x8E\x88' - KUBE_PS1_SYMBOL_IMG=$'\xE2\x98\xB8' - fi + local symbol_arg="${KUBE_PS1_SYMBOL_CUSTOM}" + + local symbol="" + local symbol_default=$'\u2388' + local symbol_img="☸️" + local k8s_glyph=$'\Uf10fe' + local k8s_symbol_color=blue + local oc_glyph=$'\ue7b7' + local oc_symbol_color=red + local custom_symbol_color="${KUBE_PS1_SYMBOL_COLOR:-$k8s_symbol_color}" + + # Choose the symbol based on the provided argument or environment variable + case "${symbol_arg}" in + "img") + symbol="${symbol_img}" + ;; + "k8s") + symbol="$(_kube_ps1_color_fg "${custom_symbol_color}")${k8s_glyph}${KUBE_PS1_RESET_COLOR}" + ;; + "oc") + symbol="$(_kube_ps1_color_fg ${oc_symbol_color})${oc_glyph}${KUBE_PS1_RESET_COLOR}" ;; - zsh) - KUBE_PS1_SYMBOL="${KUBE_PS1_SYMBOL_DEFAULT}" - KUBE_PS1_SYMBOL_IMG="\u2638";; *) - KUBE_PS1_SYMBOL="k8s" + case "$(_kube_ps1_shell_type)" in + bash) + if ((BASH_VERSINFO[0] >= 4)) && [[ $'\u2388' != "\\u2388" ]]; then + symbol="$(_kube_ps1_color_fg $custom_symbol_color)${symbol_default}${KUBE_PS1_RESET_COLOR}" + symbol_img=$'\u2638\ufe0f' + else + symbol=$'\xE2\x8E\x88' + symbol_img=$'\xE2\x98\xB8' + fi + ;; + zsh) + symbol="$(_kube_ps1_color_fg $custom_symbol_color)${symbol_default}${KUBE_PS1_RESET_COLOR}" + symbol_img="☸️" + ;; + *) + symbol="k8s" + esac esac - if [[ "${KUBE_PS1_SYMBOL_USE_IMG}" == true ]]; then - KUBE_PS1_SYMBOL="${KUBE_PS1_SYMBOL_IMG}" - fi - + # Append padding if enabled if [[ "${KUBE_PS1_SYMBOL_PADDING}" == true ]]; then - echo "${KUBE_PS1_SYMBOL} " + echo "${symbol} " else - echo "${KUBE_PS1_SYMBOL}" + echo "${symbol}" fi - } -_kube_ps1_split() { +_kube_ps1_split_config() { type setopt >/dev/null 2>&1 && setopt SH_WORD_SPLIT local IFS=$1 echo $2 @@ -190,8 +212,9 @@ _kube_ps1_file_newer_than() { local file=$1 local check_time=$2 - if [[ "${KUBE_PS1_SHELL}" == "zsh" ]]; then - mtime=$(zstat +mtime "${file}") + if [[ "$(_kube_ps1_shell_type)" == "zsh" ]]; then + # Use zstat '-F %s.%s' to make it compatible with low zsh version (eg: 5.0.2) + mtime=$(zstat -L +mtime -F %s.%s "${file}") elif stat -c "%s" /dev/null &> /dev/null; then # GNU stat mtime=$(stat -L -c %Y "${file}") @@ -203,7 +226,7 @@ _kube_ps1_file_newer_than() { [[ "${mtime}" -gt "${check_time}" ]] } -_kube_ps1_update_cache() { +_kube_ps1_prompt_update() { local return_code=$? [[ "${KUBE_PS1_ENABLED}" == "off" ]] && return $return_code @@ -212,27 +235,35 @@ _kube_ps1_update_cache() { # No ability to fetch context/namespace; display N/A. KUBE_PS1_CONTEXT="BINARY-N/A" KUBE_PS1_NAMESPACE="N/A" - return + return $return_code fi - if [[ "${KUBECONFIG}" != "${KUBE_PS1_KUBECONFIG_CACHE}" ]]; then + if [[ "${KUBECONFIG}" != "${_KUBE_PS1_KUBECONFIG_CACHE}" ]]; then # User changed KUBECONFIG; unconditionally refetch. - KUBE_PS1_KUBECONFIG_CACHE=${KUBECONFIG} + _KUBE_PS1_KUBECONFIG_CACHE=${KUBECONFIG} _kube_ps1_get_context_ns - return + return $return_code fi # kubectl will read the environment variable $KUBECONFIG # otherwise set it to ~/.kube/config local conf - for conf in $(_kube_ps1_split : "${KUBECONFIG:-${HOME}/.kube/config}"); do + local config_file_cache + + for conf in $(_kube_ps1_split_config : "${KUBECONFIG:-${HOME}/.kube/config}"); do [[ -r "${conf}" ]] || continue - if _kube_ps1_file_newer_than "${conf}" "${KUBE_PS1_LAST_TIME}"; then + config_file_cache+=":${conf}" + if _kube_ps1_file_newer_than "${conf}" "${_KUBE_PS1_LAST_TIME}"; then _kube_ps1_get_context_ns - return + return $return_code fi done + if [[ "${config_file_cache}" != "${_KUBE_PS1_CFGFILES_READ_CACHE}" ]]; then + _kube_ps1_get_context_ns + return $return_code + fi + return $return_code } @@ -242,8 +273,8 @@ _kube_ps1_get_context() { # Set namespace to 'N/A' if it is not defined KUBE_PS1_CONTEXT="${KUBE_PS1_CONTEXT:-N/A}" - if [[ ! -z "${KUBE_PS1_CLUSTER_FUNCTION}" ]]; then - KUBE_PS1_CONTEXT=$($KUBE_PS1_CLUSTER_FUNCTION $KUBE_PS1_CONTEXT) + if [[ -n "${KUBE_PS1_CLUSTER_FUNCTION}" ]]; then + KUBE_PS1_CONTEXT="$("${KUBE_PS1_CLUSTER_FUNCTION}" "${KUBE_PS1_CONTEXT}")" fi fi } @@ -251,27 +282,36 @@ _kube_ps1_get_context() { _kube_ps1_get_ns() { if [[ "${KUBE_PS1_NS_ENABLE}" == true ]]; then KUBE_PS1_NAMESPACE="$(${KUBE_PS1_BINARY} config view --minify --output 'jsonpath={..namespace}' 2>/dev/null)" - # Set namespace to 'default' if it is not defined - KUBE_PS1_NAMESPACE="${KUBE_PS1_NAMESPACE:-default}" + KUBE_PS1_NAMESPACE="${KUBE_PS1_NAMESPACE:-N/A}" - if [[ ! -z "${KUBE_PS1_NAMESPACE_FUNCTION}" ]]; then - KUBE_PS1_NAMESPACE=$($KUBE_PS1_NAMESPACE_FUNCTION $KUBE_PS1_NAMESPACE) + if [[ -n "${KUBE_PS1_NAMESPACE_FUNCTION}" ]]; then + KUBE_PS1_NAMESPACE="$("${KUBE_PS1_NAMESPACE_FUNCTION}" "${KUBE_PS1_NAMESPACE}")" fi fi } _kube_ps1_get_context_ns() { # Set the command time - if [[ "${KUBE_PS1_SHELL}" == "bash" ]]; then + if [[ "$(_kube_ps1_shell_type)" == "bash" ]]; then if ((BASH_VERSINFO[0] >= 4 && BASH_VERSINFO[1] >= 2)); then - KUBE_PS1_LAST_TIME=$(printf '%(%s)T') + _KUBE_PS1_LAST_TIME=$(printf '%(%s)T') else - KUBE_PS1_LAST_TIME=$(date +%s) + _KUBE_PS1_LAST_TIME=$(date +%s) fi - elif [[ "${KUBE_PS1_SHELL}" == "zsh" ]]; then - KUBE_PS1_LAST_TIME=$EPOCHSECONDS + elif [[ "$(_kube_ps1_shell_type)" == "zsh" ]]; then + _KUBE_PS1_LAST_TIME=$EPOCHREALTIME fi + KUBE_PS1_CONTEXT="${KUBE_PS1_CONTEXT:-N/A}" + KUBE_PS1_NAMESPACE="${KUBE_PS1_NAMESPACE:-N/A}" + + # Cache which cfgfiles we can read in case they change. + local conf + _KUBE_PS1_CFGFILES_READ_CACHE= + for conf in $(_kube_ps1_split_config : "${KUBECONFIG:-${HOME}/.kube/config}"); do + [[ -r $conf ]] && _KUBE_PS1_CFGFILES_READ_CACHE+=":$conf" + done + _kube_ps1_get_context _kube_ps1_get_ns } @@ -285,7 +325,7 @@ Toggle kube-ps1 prompt on Usage: kubeon [-g | --global] [-h | --help] -With no arguments, turn off kube-ps1 status for this shell instance (default). +With no arguments, turn oon kube-ps1 status for this shell instance (default). -g --global turn on kube-ps1 status globally -h --help print this message @@ -309,7 +349,7 @@ kubeon() { if [[ "${1}" == '-h' || "${1}" == '--help' ]]; then _kubeon_usage elif [[ "${1}" == '-g' || "${1}" == '--global' ]]; then - rm -f -- "${KUBE_PS1_DISABLE_PATH}" + rm -f -- "${_KUBE_PS1_DISABLE_PATH}" elif [[ "$#" -ne 0 ]]; then echo -e "error: unrecognized flag ${1}\\n" _kubeon_usage @@ -323,8 +363,8 @@ kubeoff() { if [[ "${1}" == '-h' || "${1}" == '--help' ]]; then _kubeoff_usage elif [[ "${1}" == '-g' || "${1}" == '--global' ]]; then - mkdir -p -- "$(dirname "${KUBE_PS1_DISABLE_PATH}")" - touch -- "${KUBE_PS1_DISABLE_PATH}" + mkdir -p -- "$(dirname "${_KUBE_PS1_DISABLE_PATH}")" + touch -- "${_KUBE_PS1_DISABLE_PATH}" elif [[ $# -ne 0 ]]; then echo "error: unrecognized flag ${1}" >&2 _kubeoff_usage @@ -338,22 +378,29 @@ kubeoff() { kube_ps1() { [[ "${KUBE_PS1_ENABLED}" == "off" ]] && return [[ -z "${KUBE_PS1_CONTEXT}" ]] && [[ "${KUBE_PS1_CONTEXT_ENABLE}" == true ]] && return + [[ "${KUBE_PS1_CONTEXT}" == "N/A" ]] && [[ ${KUBE_PS1_HIDE_IF_NOCONTEXT} == true ]] && return + local KUBE_PS1 local KUBE_PS1_RESET_COLOR="${_KUBE_PS1_OPEN_ESC}${_KUBE_PS1_DEFAULT_FG}${_KUBE_PS1_CLOSE_ESC}" + # If background color is set, reset color should also reset the background + # if [[ -n "${KUBE_PS1_BG_COLOR}" ]]; then + # KUBE_PS1_RESET_COLOR="${_KUBE_PS1_OPEN_ESC}${_KUBE_PS1_DEFAULT_FG}${_KUBE_PS1_DEFAULT_BG}${_KUBE_PS1_CLOSE_ESC}" + # fi + # Background Color - [[ -n "${KUBE_PS1_BG_COLOR}" ]] && KUBE_PS1+="$(_kube_ps1_color_bg ${KUBE_PS1_BG_COLOR})" + [[ -n "${KUBE_PS1_BG_COLOR}" ]] && KUBE_PS1+="$(_kube_ps1_color_bg "${KUBE_PS1_BG_COLOR}")" # Prefix if [[ -z "${KUBE_PS1_PREFIX_COLOR:-}" ]] && [[ -n "${KUBE_PS1_PREFIX}" ]]; then KUBE_PS1+="${KUBE_PS1_PREFIX}" else - KUBE_PS1+="$(_kube_ps1_color_fg $KUBE_PS1_PREFIX_COLOR)${KUBE_PS1_PREFIX}${KUBE_PS1_RESET_COLOR}" + KUBE_PS1+="$(_kube_ps1_color_fg "${KUBE_PS1_PREFIX_COLOR}")${KUBE_PS1_PREFIX}${KUBE_PS1_RESET_COLOR}" fi # Symbol - KUBE_PS1+="$(_kube_ps1_color_fg $KUBE_PS1_SYMBOL_COLOR)$(_kube_ps1_symbol)${KUBE_PS1_RESET_COLOR}" + KUBE_PS1+="$(_kube_ps1_symbol)" if [[ -n "${KUBE_PS1_SEPARATOR}" ]] && [[ "${KUBE_PS1_SYMBOL_ENABLE}" == true ]]; then KUBE_PS1+="${KUBE_PS1_SEPARATOR}" @@ -361,7 +408,14 @@ kube_ps1() { # Context if [[ "${KUBE_PS1_CONTEXT_ENABLE}" == true ]]; then - KUBE_PS1+="$(_kube_ps1_color_fg $KUBE_PS1_CTX_COLOR)${KUBE_PS1_CONTEXT}${KUBE_PS1_RESET_COLOR}" + local ctx_color="${KUBE_PS1_CTX_COLOR:-red}" + + # Allow custom function to override color based on context + if [[ -n "${KUBE_PS1_CTX_COLOR_FUNCTION}" ]]; then + ctx_color="$("${KUBE_PS1_CTX_COLOR_FUNCTION}" "${KUBE_PS1_CONTEXT}")" + fi + + KUBE_PS1+="$(_kube_ps1_color_fg "${ctx_color}")${KUBE_PS1_CONTEXT}${KUBE_PS1_RESET_COLOR}" fi # Namespace @@ -369,14 +423,14 @@ kube_ps1() { if [[ -n "${KUBE_PS1_DIVIDER}" ]] && [[ "${KUBE_PS1_CONTEXT_ENABLE}" == true ]]; then KUBE_PS1+="${KUBE_PS1_DIVIDER}" fi - KUBE_PS1+="$(_kube_ps1_color_fg ${KUBE_PS1_NS_COLOR})${KUBE_PS1_NAMESPACE}${KUBE_PS1_RESET_COLOR}" + KUBE_PS1+="$(_kube_ps1_color_fg "${KUBE_PS1_NS_COLOR:-cyan}")${KUBE_PS1_NAMESPACE}${KUBE_PS1_RESET_COLOR}" fi # Suffix if [[ -z "${KUBE_PS1_SUFFIX_COLOR:-}" ]] && [[ -n "${KUBE_PS1_SUFFIX}" ]]; then KUBE_PS1+="${KUBE_PS1_SUFFIX}" else - KUBE_PS1+="$(_kube_ps1_color_fg $KUBE_PS1_SUFFIX_COLOR)${KUBE_PS1_SUFFIX}${KUBE_PS1_RESET_COLOR}" + KUBE_PS1+="$(_kube_ps1_color_fg "${KUBE_PS1_SUFFIX_COLOR}")${KUBE_PS1_SUFFIX}${KUBE_PS1_RESET_COLOR}" fi # Close Background color if defined diff --git a/zsh/plugins/kubectl/README.md b/zsh/plugins/kubectl/README.md index 579a90b..5e4ae7e 100644 --- a/zsh/plugins/kubectl/README.md +++ b/zsh/plugins/kubectl/README.md @@ -11,122 +11,130 @@ plugins=(... kubectl) ## Aliases -| Alias | Command | Description | -|:--------|:------------------------------------|:-------------------------------------------------------------------------------------------------| -| k | `kubectl` | The kubectl command | -| kca | `kubectl --all-namespaces` | The kubectl command targeting all namespaces | -| kaf | `kubectl apply -f` | Apply a YML file | -| keti | `kubectl exec -ti` | Drop into an interactive terminal on a container | -| | | **Manage configuration quickly to switch contexts between local, dev and staging** | -| kcuc | `kubectl config use-context` | Set the current-context in a kubeconfig file | -| kcsc | `kubectl config set-context` | Set a context entry in kubeconfig | -| kcdc | `kubectl config delete-context` | Delete the specified context from the kubeconfig | -| kccc | `kubectl config current-context` | Display the current-context | -| kcgc | `kubectl config get-contexts` | List of contexts available | -| | | **General aliases** | -| kdel | `kubectl delete` | Delete resources by filenames, stdin, resources and names, or by resources and label selector | -| kdelf | `kubectl delete -f` | Delete a pod using the type and name specified in -f argument | -| | | **Pod management** | -| kgp | `kubectl get pods` | List all pods in ps output format | -| kgpw | `kgp --watch` | After listing/getting the requested object, watch for changes | -| kgpwide | `kgp -o wide` | Output in plain-text format with any additional information. For pods, the node name is included | -| kep | `kubectl edit pods` | Edit pods from the default editor | -| kdp | `kubectl describe pods` | Describe all pods | -| kdelp | `kubectl delete pods` | Delete all pods matching passed arguments | -| kgpl | `kgp -l` | Get pods by label. Example: `kgpl "app=myapp" -n myns` | -| kgpn | `kgp -n` | Get pods by namespace. Example: `kgpn kube-system` | -| | | **Service management** | -| kgs | `kubectl get svc` | List all services in ps output format | -| kgsw | `kgs --watch` | After listing all services, watch for changes | -| kgswide | `kgs -o wide` | After listing all services, output in plain-text format with any additional information | -| kes | `kubectl edit svc` | Edit services(svc) from the default editor | -| kds | `kubectl describe svc` | Describe all services in detail | -| kdels | `kubectl delete svc` | Delete all services matching passed argument | -| | | **Ingress management** | -| kgi | `kubectl get ingress` | List ingress resources in ps output format | -| kei | `kubectl edit ingress` | Edit ingress resource from the default editor | -| kdi | `kubectl describe ingress` | Describe ingress resource in detail | -| kdeli | `kubectl delete ingress` | Delete ingress resources matching passed argument | -| | | **Namespace management** | -| kgns | `kubectl get namespaces` | List the current namespaces in a cluster | -| kcn | `kubectl config set-context --current --namespace` | Change current namespace | -| kens | `kubectl edit namespace` | Edit namespace resource from the default editor | -| kdns | `kubectl describe namespace` | Describe namespace resource in detail | -| kdelns | `kubectl delete namespace` | Delete the namespace. WARNING! This deletes everything in the namespace | -| | | **ConfigMap management** | -| kgcm | `kubectl get configmaps` | List the configmaps in ps output format | -| kecm | `kubectl edit configmap` | Edit configmap resource from the default editor | -| kdcm | `kubectl describe configmap` | Describe configmap resource in detail | -| kdelcm | `kubectl delete configmap` | Delete the configmap | -| | | **Secret management** | -| kgsec | `kubectl get secret` | Get secret for decoding | -| kdsec | `kubectl describe secret` | Describe secret resource in detail | -| kdelsec | `kubectl delete secret` | Delete the secret | -| | | **Deployment management** | -| kgd | `kubectl get deployment` | Get the deployment | -| kgdw | `kgd --watch` | After getting the deployment, watch for changes | -| kgdwide | `kgd -o wide` | After getting the deployment, output in plain-text format with any additional information | -| ked | `kubectl edit deployment` | Edit deployment resource from the default editor | -| kdd | `kubectl describe deployment` | Describe deployment resource in detail | -| kdeld | `kubectl delete deployment` | Delete the deployment | -| ksd | `kubectl scale deployment` | Scale a deployment | -| krsd | `kubectl rollout status deployment` | Check the rollout status of a deployment | -| kres | `kubectl set env $@ REFRESHED_AT=...` | Recreate all pods in deployment with zero-downtime | -| | | **Rollout management** | -| kgrs | `kubectl get replicaset` | List all ReplicaSets `rs` created by the deployment | -| kdrs | `kubectl describe replicaset` | Describe ReplicaSet in detail | -| kers | `kubectl edit replicaset` | Edit ReplicaSet from the default editor | -| krh | `kubectl rollout history` | Check the revisions of this deployment | -| kru | `kubectl rollout undo` | Rollback to the previous revision | -| | | **Port forwarding** | -| kpf | `kubectl port-forward` | Forward one or more local ports to a pod | -| | | **Tools for accessing all information** | -| kga | `kubectl get all` | List all resources in ps format | -| kgaa | `kubectl get all --all-namespaces` | List the requested object(s) across all namespaces | -| | | **Logs** | -| kl | `kubectl logs` | Print the logs for a container or resource | -| klf | `kubectl logs -f` | Stream the logs for a container or resource (follow) | -| | | **File copy** | -| kcp | `kubectl cp` | Copy files and directories to and from containers | -| | | **Node management** | -| kgno | `kubectl get nodes` | List the nodes in ps output format | -| keno | `kubectl edit node` | Edit nodes resource from the default editor | -| kdno | `kubectl describe node` | Describe node resource in detail | -| kdelno | `kubectl delete node` | Delete the node | -| | | **Persistent Volume Claim management** | -| kgpvc | `kubectl get pvc` | List all PVCs | -| kgpvcw | `kgpvc --watch` | After listing/getting the requested object, watch for changes | -| kepvc | `kubectl edit pvc` | Edit pvcs from the default editor | -| kdpvc | `kubectl describe pvc` | Describe all pvcs | -| kdelpvc | `kubectl delete pvc` | Delete all pvcs matching passed arguments | -| | | **StatefulSets management** | -| kgss | `kubectl get statefulset` | List the statefulsets in ps format | -| kgssw | `kgss --watch` | After getting the list of statefulsets, watch for changes | -| kgsswide| `kgss -o wide` | After getting the statefulsets, output in plain-text format with any additional information | -| kess | `kubectl edit statefulset` | Edit statefulset resource from the default editor | -| kdss | `kubectl describe statefulset` | Describe statefulset resource in detail | -| kdelss | `kubectl delete statefulset` | Delete the statefulset | -| ksss | `kubectl scale statefulset` | Scale a statefulset | -| krsss | `kubectl rollout status statefulset`| Check the rollout status of a deployment | -| | | **Service Accounts management** | -| kdsa | `kubectl describe sa` | Describe a service account in details | -| kdelsa | `kubectl delete sa` | Delete the service account | -| | | **DaemonSet management** | -| kgds | `kubectl get daemonset` | List all DaemonSets in ps output format | -| kgdsw | `kgds --watch` | After listing all DaemonSets, watch for changes | -| keds | `kubectl edit daemonset` | Edit DaemonSets from the default editor | -| kdds | `kubectl describe daemonset` | Describe all DaemonSets in detail | -| kdelds | `kubectl delete daemonset` | Delete all DaemonSets matching passed argument | -| | | **CronJob management** | -| kgcj | `kubectl get cronjob` | List all CronJobs in ps output format | -| kecj | `kubectl edit cronjob` | Edit CronJob from the default editor | -| kdcj | `kubectl describe cronjob` | Describe a CronJob in details | -| kdelcj | `kubectl delete cronjob` | Delete the CronJob | -| | | **Job management** | -| kgj | `kubectl get job` | List all Job in ps output format | -| kej | `kubectl edit job` | Edit a Job in details | -| kdj | `kubectl describe job` | Describe the Job | -| kdelj | `kubectl delete job` | Delete the Job | +| Alias | Command | Description | +| :------- | :------------------------------------------------------ | :----------------------------------------------------------------------------------------------- | +| k | `kubectl` | The kubectl command | +| kca | `kubectl --all-namespaces` | The kubectl command targeting all namespaces | +| kaf | `kubectl apply -f` | Apply a YML file | +| kapk | `kubectl apply -k` | Apply a kustomization directory | +| keti | `kubectl exec -ti` | Drop into an interactive terminal on a container | +| | | **Manage configuration quickly to switch contexts between local, dev and staging** | +| kcuc | `kubectl config use-context` | Set the current-context in a kubeconfig file | +| kcsc | `kubectl config set-context` | Set a context entry in kubeconfig | +| kcdc | `kubectl config delete-context` | Delete the specified context from the kubeconfig | +| kccc | `kubectl config current-context` | Display the current-context | +| kcgc | `kubectl config get-contexts` | List of contexts available | +| | | **General aliases** | +| kdel | `kubectl delete` | Delete resources by filenames, stdin, resources and names, or by resources and label selector | +| kdelf | `kubectl delete -f` | Delete a pod using the type and name specified in -f argument | +| kdelk | `kubectl delete -k` | Delete all resources defined in a kustomization directory | +| kge | `kubectl get events --sort-by=".lastTimestamp"` | Get events (sorted by timestamp) | +| kgew | `kubectl get events --watch --sort-by=".lastTimestamp"` | Get events and watch as they occur (sorted by timestamp) | +| | | **Pod management** | +| kgp | `kubectl get pods` | List all pods in ps output format | +| kgpl | `kgp -l` | Get pods by label. Example: `kgpl "app=myapp" -n myns` | +| kgpn | `kgp -n` | Get pods by namespace. Example: `kgpn kube-system` | +| kgpsl | `kubectl get pods --show-labels` | List all pods in ps output format with labels | +| kgpw | `kgp --watch` | After listing/getting the requested object, watch for changes | +| kgpwide | `kgp -o wide` | Output in plain-text format with any additional information. For pods, the node name is included | +| kep | `kubectl edit pods` | Edit pods from the default editor | +| kdp | `kubectl describe pods` | Describe all pods | +| kdelp | `kubectl delete pods` | Delete all pods matching passed arguments | +| | | **Service management** | +| kgs | `kubectl get svc` | List all services in ps output format | +| kgsw | `kgs --watch` | After listing all services, watch for changes | +| kgswide | `kgs -o wide` | After listing all services, output in plain-text format with any additional information | +| kes | `kubectl edit svc` | Edit services(svc) from the default editor | +| kds | `kubectl describe svc` | Describe all services in detail | +| kdels | `kubectl delete svc` | Delete all services matching passed argument | +| | | **Ingress management** | +| kgi | `kubectl get ingress` | List ingress resources in ps output format | +| kei | `kubectl edit ingress` | Edit ingress resource from the default editor | +| kdi | `kubectl describe ingress` | Describe ingress resource in detail | +| kdeli | `kubectl delete ingress` | Delete ingress resources matching passed argument | +| | | **Namespace management** | +| kgns | `kubectl get namespaces` | List the current namespaces in a cluster | +| kcn | `kubectl config set-context --current --namespace` | Change current namespace | +| kens | `kubectl edit namespace` | Edit namespace resource from the default editor | +| kdns | `kubectl describe namespace` | Describe namespace resource in detail | +| kdelns | `kubectl delete namespace` | Delete the namespace. WARNING! This deletes everything in the namespace | +| | | **ConfigMap management** | +| kgcm | `kubectl get configmaps` | List the configmaps in ps output format | +| kecm | `kubectl edit configmap` | Edit configmap resource from the default editor | +| kdcm | `kubectl describe configmap` | Describe configmap resource in detail | +| kdelcm | `kubectl delete configmap` | Delete the configmap | +| | | **Secret management** | +| kgsec | `kubectl get secret` | Get secret for decoding | +| kdsec | `kubectl describe secret` | Describe secret resource in detail | +| kdelsec | `kubectl delete secret` | Delete the secret | +| | | **Deployment management** | +| kgd | `kubectl get deployment` | Get the deployment | +| kgdw | `kgd --watch` | After getting the deployment, watch for changes | +| kgdwide | `kgd -o wide` | After getting the deployment, output in plain-text format with any additional information | +| ked | `kubectl edit deployment` | Edit deployment resource from the default editor | +| kdd | `kubectl describe deployment` | Describe deployment resource in detail | +| kdeld | `kubectl delete deployment` | Delete the deployment | +| ksd | `kubectl scale deployment` | Scale a deployment | +| krsd | `kubectl rollout status deployment` | Check the rollout status of a deployment | +| krrd | `kubectl rollout restart deployment` | Rollout restart a deployment | +| kres | `kubectl set env $@ REFRESHED_AT=...` | Recreate all pods in deployment with zero-downtime | +| | | **Rollout management** | +| kgrs | `kubectl get replicaset` | List all ReplicaSets `rs` created by the deployment | +| kdrs | `kubectl describe replicaset` | Describe ReplicaSet in detail | +| kers | `kubectl edit replicaset` | Edit ReplicaSet from the default editor | +| krh | `kubectl rollout history` | Check the revisions of this deployment | +| kru | `kubectl rollout undo` | Rollback to the previous revision | +| | | **Port forwarding** | +| kpf | `kubectl port-forward` | Forward one or more local ports to a pod | +| | | **Tools for accessing all information** | +| kga | `kubectl get all` | List all resources in ps format | +| kgaa | `kubectl get all --all-namespaces` | List the requested object(s) across all namespaces | +| | | **Logs** | +| kl | `kubectl logs` | Print the logs for a container or resource | +| klf | `kubectl logs -f` | Stream the logs for a container or resource (follow) | +| | | **File copy** | +| kcp | `kubectl cp` | Copy files and directories to and from containers | +| | | **Node management** | +| kgno | `kubectl get nodes` | List the nodes in ps output format | +| kgnosl | `kubectl get nodes --show-labels` | List the nodes in ps output format with labels | +| keno | `kubectl edit node` | Edit nodes resource from the default editor | +| kdno | `kubectl describe node` | Describe node resource in detail | +| kdelno | `kubectl delete node` | Delete the node | +| | | **Persistent Volume Claim management** | +| kgpvc | `kubectl get pvc` | List all PVCs | +| kgpvcw | `kgpvc --watch` | After listing/getting the requested object, watch for changes | +| kepvc | `kubectl edit pvc` | Edit pvcs from the default editor | +| kdpvc | `kubectl describe pvc` | Describe all pvcs | +| kdelpvc | `kubectl delete pvc` | Delete all pvcs matching passed arguments | +| | | **StatefulSets management** | +| kgss | `kubectl get statefulset` | List the statefulsets in ps format | +| kgssw | `kgss --watch` | After getting the list of statefulsets, watch for changes | +| kgsswide | `kgss -o wide` | After getting the statefulsets, output in plain-text format with any additional information | +| kess | `kubectl edit statefulset` | Edit statefulset resource from the default editor | +| kdss | `kubectl describe statefulset` | Describe statefulset resource in detail | +| kdelss | `kubectl delete statefulset` | Delete the statefulset | +| ksss | `kubectl scale statefulset` | Scale a statefulset | +| krsss | `kubectl rollout status statefulset` | Check the rollout status of a deployment | +| krrss | `kubectl rollout restart statefulset` | Rollout restart a statefulset | +| | | **Service Accounts management** | +| kdsa | `kubectl describe sa` | Describe a service account in details | +| kdelsa | `kubectl delete sa` | Delete the service account | +| | | **DaemonSet management** | +| kgds | `kubectl get daemonset` | List all DaemonSets in ps output format | +| kgdsw | `kgds --watch` | After listing all DaemonSets, watch for changes | +| keds | `kubectl edit daemonset` | Edit DaemonSets from the default editor | +| kdds | `kubectl describe daemonset` | Describe all DaemonSets in detail | +| kdelds | `kubectl delete daemonset` | Delete all DaemonSets matching passed argument | +| | | **CronJob management** | +| kgcj | `kubectl get cronjob` | List all CronJobs in ps output format | +| kecj | `kubectl edit cronjob` | Edit CronJob from the default editor | +| kdcj | `kubectl describe cronjob` | Describe a CronJob in details | +| kdelcj | `kubectl delete cronjob` | Delete the CronJob | +| | | **Job management** | +| kgj | `kubectl get job` | List all Job in ps output format | +| kej | `kubectl edit job` | Edit a Job in details | +| kdj | `kubectl describe job` | Describe the Job | +| kdelj | `kubectl delete job` | Delete the Job | ## Wrappers diff --git a/zsh/plugins/kubectl/kubectl.plugin.zsh b/zsh/plugins/kubectl/kubectl.plugin.zsh index 095d2b3..ba371cd 100644 --- a/zsh/plugins/kubectl/kubectl.plugin.zsh +++ b/zsh/plugins/kubectl/kubectl.plugin.zsh @@ -1,15 +1,17 @@ -if (( $+commands[kubectl] )); then - # If the completion file does not exist, generate it and then source it - # Otherwise, source it and regenerate in the background - if [[ ! -f "$ZSH_CACHE_DIR/completions/_kubectl" ]]; then - kubectl completion zsh | tee "$ZSH_CACHE_DIR/completions/_kubectl" >/dev/null - source "$ZSH_CACHE_DIR/completions/_kubectl" - else - source "$ZSH_CACHE_DIR/completions/_kubectl" - kubectl completion zsh | tee "$ZSH_CACHE_DIR/completions/_kubectl" >/dev/null &| - fi +if (( ! $+commands[kubectl] )); then + return fi +# If the completion file doesn't exist yet, we need to autoload it and +# bind it to `kubectl`. Otherwise, compinit will have already done that. +if [[ ! -f "$ZSH_CACHE_DIR/completions/_kubectl" ]]; then + typeset -g -A _comps + autoload -Uz _kubectl + _comps[kubectl]=_kubectl +fi + +kubectl completion zsh 2> /dev/null >| "$ZSH_CACHE_DIR/completions/_kubectl" &| + # This command is used a LOT both below and in daily life alias k=kubectl @@ -19,6 +21,9 @@ alias kca='_kca(){ kubectl "$@" --all-namespaces; unset -f _kca; }; _kca' # Apply a YML file alias kaf='kubectl apply -f' +# Apply a kustomization directory +alias kapk='kubectl apply -k' + # Drop into an interactive terminal on a container alias keti='kubectl exec -t -i' @@ -34,9 +39,15 @@ alias kcgc='kubectl config get-contexts' # General aliases alias kdel='kubectl delete' alias kdelf='kubectl delete -f' +alias kdelk='kubectl delete -k' +alias kge='kubectl get events --sort-by=".lastTimestamp"' +alias kgew='kubectl get events --sort-by=".lastTimestamp" --watch' # Pod management. alias kgp='kubectl get pods' +alias kgpl='kgp -l' +alias kgpn='kgp -n' +alias kgpsl='kubectl get pods --show-labels' alias kgpa='kubectl get pods --all-namespaces' alias kgpw='kgp --watch' alias kgpwide='kgp -o wide' @@ -45,12 +56,6 @@ alias kdp='kubectl describe pods' alias kdelp='kubectl delete pods' alias kgpall='kubectl get pods --all-namespaces -o wide' -# get pod by label: kgpl "app=myapp" -n myns -alias kgpl='kgp -l' - -# get pod by namespace: kgpn kube-system" -alias kgpn='kgp -n' - # Service management. alias kgs='kubectl get svc' alias kgsa='kubectl get svc --all-namespaces' @@ -97,6 +102,7 @@ alias kdd='kubectl describe deployment' alias kdeld='kubectl delete deployment' alias ksd='kubectl scale deployment' alias krsd='kubectl rollout status deployment' +alias krrd='kubectl rollout restart deployment' function kres(){ kubectl set env $@ REFRESHED_AT=$(date +%Y%m%d%H%M%S) @@ -119,6 +125,7 @@ alias kdss='kubectl describe statefulset' alias kdelss='kubectl delete statefulset' alias ksss='kubectl scale statefulset' alias krsss='kubectl rollout status statefulset' +alias krrss='kubectl rollout restart statefulset' # Port forwarding alias kpf="kubectl port-forward" @@ -142,6 +149,7 @@ alias kcp='kubectl cp' # Node Management alias kgno='kubectl get nodes' +alias kgnosl='kubectl get nodes --show-labels' alias keno='kubectl edit node' alias kdno='kubectl describe node' alias kdelno='kubectl delete node' @@ -160,6 +168,7 @@ alias kdelsa="kubectl delete sa" # DaemonSet management. alias kgds='kubectl get daemonset' +alias kgdsa='kubectl get daemonset --all-namespaces' alias kgdsw='kgds --watch' alias keds='kubectl edit daemonset' alias kdds='kubectl describe daemonset' @@ -177,13 +186,23 @@ alias kej='kubectl edit job' alias kdj='kubectl describe job' alias kdelj='kubectl delete job' -# Only run if the user actually has kubectl installed -if (( ${+_comps[kubectl]} )); then - function kj() { kubectl "$@" -o json | jq; } - function kjx() { kubectl "$@" -o json | fx; } - function ky() { kubectl "$@" -o yaml | yh; } +# Utility print functions (json / yaml) +function _build_kubectl_out_alias { + setopt localoptions norcexpandparam - compdef kj=kubectl - compdef kjx=kubectl - compdef ky=kubectl -fi + # alias function + eval "function $1 { $2 }" + + # completion function + eval "function _$1 { + words=(kubectl \"\${words[@]:1}\") + _kubectl + }" + + compdef _$1 $1 +} + +_build_kubectl_out_alias "kj" 'kubectl "$@" -o json | jq' +_build_kubectl_out_alias "kjx" 'kubectl "$@" -o json | fx' +_build_kubectl_out_alias "ky" 'kubectl "$@" -o yaml | yh' +unfunction _build_kubectl_out_alias diff --git a/zsh/plugins/kubectx/README.md b/zsh/plugins/kubectx/README.md index 98f1cf0..e3987b4 100644 --- a/zsh/plugins/kubectx/README.md +++ b/zsh/plugins/kubectx/README.md @@ -1,25 +1,55 @@ # kubectx - show active kubectl context -This plugins adds ```kubectx_prompt_info()``` function. It shows name of the -active kubectl context (```kubectl config current-context```). +This plugins adds `kubectx_prompt_info()` function. It shows name of the active +kubectl context (`kubectl config current-context`). You can use it to customize prompt and know if You are on prod cluster ;) -_Example_. Add to **.zshrc**: +To use this plugin, add `kubectx` to the plugins array in your zshrc file: +```zsh +plugins=(... kubectx) ``` + +### Usage + +Add to **.zshrc**: + +```zsh +# right prompt RPS1='$(kubectx_prompt_info)' +# left prompt +PROMPT="$PROMPT"'$(kubectx_prompt_info)' ``` -### custom ctx names +### Custom context names -One can rename default context name for better readability. +You can rename the default context name for better readability or additional formatting. +These values accept [prompt expansion sequences](http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html) +such as `%F{color}`, `%f`, `%K{color}`, `%k`, `%B`, `%b`, `%U`, `%u`, `%S`, `%s`, `%{...%}`. -_Example_. Add to **.zshrc**: -``` +**Example**: add this to your .zshrc file: + +```zsh kubectx_mapping[minikube]="mini" kubectx_mapping[context_name_from_kubeconfig]="$emoji[wolf_face]" kubectx_mapping[production_cluster]="%{$fg[yellow]%}prod!%{$reset_color%}" +# contexts with spaces +kubectx_mapping[context\ with\ spaces]="%F{red}spaces%f" +# don't use quotes as it will break the prompt +kubectx_mapping["context with spaces"]="%F{red}spaces%f" # ti +``` + +You can also define the whole mapping array at once: + +```zsh +typeset -A kubectx_mapping +kubectx_mapping=( + minikube "mini" + context_name_from_kubeconfig "$emoji[wolf_face]" + production_cluster "%{$fg[yellow]%}prod!%{$reset_color%}" + "context with spaces" "%F{red}spaces%f" +) ``` ![staging](stage.png) diff --git a/zsh/plugins/kubectx/kubectx.plugin.zsh b/zsh/plugins/kubectx/kubectx.plugin.zsh index 6096fee..f1ca990 100644 --- a/zsh/plugins/kubectx/kubectx.plugin.zsh +++ b/zsh/plugins/kubectx/kubectx.plugin.zsh @@ -7,7 +7,9 @@ function kubectx_prompt_info() { [[ -n "$current_ctx" ]] || return - # use value in associative array if it exists - # otherwise fall back to the context name + # Use value in associative array if it exists, otherwise fall back to the context name + # + # Note: we need to escape the % character in the prompt string when coming directly from + # the context name, as it could contain a % character. echo "${kubectx_mapping[$current_ctx]:-${current_ctx:gs/%/%%}}" } diff --git a/zsh/plugins/lando/README.md b/zsh/plugins/lando/README.md index 928a42b..2f881cf 100644 --- a/zsh/plugins/lando/README.md +++ b/zsh/plugins/lando/README.md @@ -8,7 +8,7 @@ To use it, add `lando` to the plugins array in your zshrc file: plugins=(... lando) ``` -## ALIASES: +## Wrapped Commands | Alias | Description | |:----------:|:----------------:| @@ -17,19 +17,38 @@ plugins=(... lando) | `drush` | `lando drush` | | `gulp` | `lando gulp` | | `npm` | `lando npm` | +| `php` | `lando php` | | `wp` | `lando wp` | | `yarn` | `lando yarn` | +More or different commands can be wrapped by setting the `LANDO_ZSH_WRAPPED_COMMANDS` setting, see [Settings](#settings) below. + ## How It Works: This plugin removes the requirement to type `lando` before a command. It utilizes the lando version of supported commands run within directories with the following criteria: + - The `.lando.yml` file is found in the current directory or any parent directory within `$LANDO_ZSH_SITES_DIRECTORY`. - The current directory is within `$LANDO_ZSH_SITES_DIRECTORY` but is not `$LANDO_ZSH_SITES_DIRECTORY` itself. +- If the command is not a part of the commands available in the lando environment, it will run the command without `lando`. ## Settings: -- `LANDO_ZSH_SITES_DIRECTORY`: The plugin will stop searching through parents for `CONFIG_FILE` once it hits this directory. -- `LANDO_ZSH_CONFIG_FILE`: The plugin will check to see if this provided file exists to check for presence of Lando. +> NOTE: these settings must be set *before* the plugin is loaded, and any changes require a restart of the shell to be applied. + +- `LANDO_ZSH_SITES_DIRECTORY`: The plugin will stop searching through parents for `CONFIG_FILE` once it hits this directory: + ```sh + LANDO_ZSH_SITES_DIRECTORY="$HOME/Code" + ``` + +- `LANDO_ZSH_CONFIG_FILE`: The plugin will check to see if this provided file exists to check for presence of Lando: + ```sh + LANDO_ZSH_CONFIG_FILE=".lando.dev.yml" + ``` + +- `LANDO_ZSH_WRAPPED_COMMANDS`: The list of commands to wrap, as a string of commands separated by whitespace: + ```sh + LANDO_ZSH_WRAPPED_COMMANDS="mysql php composer test artisan" + ``` ## Author: diff --git a/zsh/plugins/lando/lando.plugin.zsh b/zsh/plugins/lando/lando.plugin.zsh index af53e7e..ee796d2 100644 --- a/zsh/plugins/lando/lando.plugin.zsh +++ b/zsh/plugins/lando/lando.plugin.zsh @@ -1,25 +1,36 @@ # Settings : ${LANDO_ZSH_SITES_DIRECTORY:="$HOME/Sites"} : ${LANDO_ZSH_CONFIG_FILE:=.lando.yml} +: ${LANDO_ZSH_WRAPPED_COMMANDS:=" + artisan + composer + drush + gulp + npm + php + wp + yarn +"} # Enable multiple commands with lando. -function artisan \ - composer \ - drush \ - gulp \ - npm \ - php \ - wp \ - yarn { - if checkForLandoFile; then - lando "$0" "$@" +function ${=LANDO_ZSH_WRAPPED_COMMANDS} { + # If the lando task is available in `lando --help`, then it means: + # + # 1. `lando` is in a project with a `.lando.yml` file. + # 2. The lando task is available for lando, based on the .lando.yml config file. + # + # This has a penalty of about 250ms, so we still want to check if the lando file + # exists before, which is the fast path. If it exists, checking help output is + # still faster than running the command and failing. + if _lando_file_exists && lando --help 2>&1 | command grep -Eq "^ +lando $0 "; then + command lando "$0" "$@" else command "$0" "$@" fi } # Check for the file in the current and parent directories. -checkForLandoFile() { +_lando_file_exists() { # Only bother checking for lando within the Sites directory. if [[ "$PWD/" != "$LANDO_ZSH_SITES_DIRECTORY"/* ]]; then # Not within $LANDO_ZSH_SITES_DIRECTORY @@ -38,4 +49,4 @@ checkForLandoFile() { # Could not find $LANDO_ZSH_CONFIG_FILE in the current directory # or in any of its parents up to $LANDO_ZSH_SITES_DIRECTORY. return 1 -} \ No newline at end of file +} diff --git a/zsh/plugins/laravel/README.md b/zsh/plugins/laravel/README.md index 95f5901..c5375f2 100644 --- a/zsh/plugins/laravel/README.md +++ b/zsh/plugins/laravel/README.md @@ -10,6 +10,7 @@ plugins=(... laravel) |:-:|:-:| | `artisan` | `php artisan` | | `pas` | `php artisan serve` | +| `pats` | `php artisan test` | ## Database @@ -20,6 +21,7 @@ plugins=(... laravel) | `pamfs` | `php artisan migrate:fresh --seed` | | `pamr` | `php artisan migrate:rollback` | | `pads` | `php artisan db:seed` | +| `padw` | `php artisan db:wipe` | ## Makers @@ -35,6 +37,10 @@ plugins=(... laravel) | `pamj` | `php artisan make:job` | | `paml` | `php artisan make:listener` | | `pamn` | `php artisan make:notification` | +| `pamcl` | `php artisan make:class` | +| `pamen` | `php artisan make:enum` | +| `pami` | `php artisan make:interface` | +| `pamtr` | `php artisan make:trait` | ## Clears @@ -44,6 +50,7 @@ plugins=(... laravel) | `pacoc` | `php artisan config:clear` | | `pavic` | `php artisan view:clear` | | `paroc` | `php artisan route:clear` | +| `paopc` | `php artisan optimize:clear` | ## Queues diff --git a/zsh/plugins/laravel/laravel.plugin.zsh b/zsh/plugins/laravel/laravel.plugin.zsh index a8382d3..20a1c47 100644 --- a/zsh/plugins/laravel/laravel.plugin.zsh +++ b/zsh/plugins/laravel/laravel.plugin.zsh @@ -4,6 +4,7 @@ alias bob='php artisan bob::build' # Development alias pas='php artisan serve' +alias pats='php artisan test' # Database alias pam='php artisan migrate' @@ -11,6 +12,7 @@ alias pamf='php artisan migrate:fresh' alias pamfs='php artisan migrate:fresh --seed' alias pamr='php artisan migrate:rollback' alias pads='php artisan db:seed' +alias padw='php artisan db:wipe' # Makers alias pamm='php artisan make:model' @@ -24,6 +26,10 @@ alias pamj='php artisan make:job' alias paml='php artisan make:listener' alias pamn='php artisan make:notification' alias pampp='php artisan make:provider' +alias pamcl='php artisan make:class' +alias pamen='php artisan make:enum' +alias pami='php artisan make:interface' +alias pamtr='php artisan make:trait' # Clears @@ -31,6 +37,7 @@ alias pacac='php artisan cache:clear' alias pacoc='php artisan config:clear' alias pavic='php artisan view:clear' alias paroc='php artisan route:clear' +alias paopc='php artisan optimize:clear' # queues alias paqf='php artisan queue:failed' diff --git a/zsh/plugins/last-working-dir/last-working-dir.plugin.zsh b/zsh/plugins/last-working-dir/last-working-dir.plugin.zsh index 905a02a..951ebff 100644 --- a/zsh/plugins/last-working-dir/last-working-dir.plugin.zsh +++ b/zsh/plugins/last-working-dir/last-working-dir.plugin.zsh @@ -9,20 +9,23 @@ chpwd_last_working_dir() { [[ "$ZSH_SUBSHELL" -eq 0 ]] || return 0 # Add ".$SSH_USER" suffix to cache file if $SSH_USER is set and non-empty local cache_file="$ZSH_CACHE_DIR/last-working-dir${SSH_USER:+.$SSH_USER}" - pwd >| "$cache_file" + 'builtin' 'echo' '-E' "$PWD" >| "$cache_file" } # Changes directory to the last working directory lwd() { # Add ".$SSH_USER" suffix to cache file if $SSH_USER is set and non-empty local cache_file="$ZSH_CACHE_DIR/last-working-dir${SSH_USER:+.$SSH_USER}" - [[ -r "$cache_file" ]] && cd "$(cat "$cache_file")" + [[ -r "$cache_file" ]] && cd "$(<"$cache_file")" } # Jump to last directory automatically unless: -# - this isn't the first time the plugin is loaded -# - it's not in $HOME directory -[[ -n "$ZSH_LAST_WORKING_DIRECTORY" ]] && return -[[ "$PWD" != "$HOME" ]] && return +# +# - This isn't the first time the plugin is loaded +# - We're not in the $HOME directory (e.g. if terminal opened a different folder) +[[ -z "$ZSH_LAST_WORKING_DIRECTORY" ]] || return 0 +[[ "$PWD" == "$HOME" ]] || return 0 -lwd 2>/dev/null && ZSH_LAST_WORKING_DIRECTORY=1 || true +if lwd 2>/dev/null; then + ZSH_LAST_WORKING_DIRECTORY=1 +fi diff --git a/zsh/plugins/localstack/README.md b/zsh/plugins/localstack/README.md new file mode 100644 index 0000000..2c71e9e --- /dev/null +++ b/zsh/plugins/localstack/README.md @@ -0,0 +1,24 @@ +# Localstack plugin # + +CLI support for LOCALSTACK interaction + +## Description ## +To use it, add `localstack` to the plugins array in your zshrc file: + +```zsh +plugins=(... localstack) +``` + +## Usage ## + +This plugin supplies one command, `lsk`, through which all its features are exposed. + +## Commands + +| Command | Description | +| :------------ | :-------------------------------------------------------------------- | +| `lsk sqs-send ` | sends a given message in sqs to a given queue | + +## Examples + +![staging](sqs-send-result.png) diff --git a/zsh/plugins/localstack/localstack.plugin.zsh b/zsh/plugins/localstack/localstack.plugin.zsh new file mode 100644 index 0000000..080b14a --- /dev/null +++ b/zsh/plugins/localstack/localstack.plugin.zsh @@ -0,0 +1,37 @@ +# CLI support for LOCALSTACK interaction +# +# See README.md for details +lsk() { + case $1 in + sqs-send) + shift + sqs-send "$@" + ;; + *) + echo "Command not found: $1" + return 1 + ;; + esac +} + +# Send SQS function +# +# This function sends a given message in sqs to a given queue, when used Localstack +# +# Use: +# sqs-send +# +# Parameters +# A given queue +# A content of message em json archive +# +# Example +# sqs-send user user.json +sqs-send(){ + if [ -z "$1" ]; then + echo "Use: sqs-send " + return 1 + fi + + curl -X POST "http://localhost:4566/000000000000/$1" -d "Action=SendMessage" -d "MessageBody=$(cat $2)" +} \ No newline at end of file diff --git a/zsh/plugins/localstack/sqs-send-result.png b/zsh/plugins/localstack/sqs-send-result.png new file mode 100644 index 0000000000000000000000000000000000000000..69eb2a64096b0b3fc476234fce1c50e51ea56b5a GIT binary patch literal 70661 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