├── .gitignore ├── .pre-commit-config.yaml ├── README.md ├── ansible.cfg ├── bin ├── dot-bootstrap ├── dot-bootstrap-remote ├── dot-update ├── dot-update-remote ├── e ├── git-find-commit ├── itry └── upgrades ├── docs └── MAC_MINI.md ├── group_vars ├── local └── remote ├── hosts ├── local_env.yml ├── misc ├── bettertouchtool │ ├── README.md │ └── sloria.bttpreset └── terminal │ ├── sloria-ayu.terminal │ └── sloria-night-owl.terminal ├── remote_env.yml └── roles ├── adguard ├── README.md └── tasks │ └── main.yml ├── ansible └── aliases.zsh ├── bat ├── aliases.zsh ├── defaults │ └── main.yml └── tasks │ ├── debian.yml │ └── main.yml ├── beszel-agent ├── README.md ├── tasks │ └── main.yml └── templates │ ├── beszel-agent.env.j2 │ └── com.sloria.beszel-agent.plist.j2 ├── docker ├── _docker ├── _docker-compose └── aliases.zsh ├── eza ├── aliases.zsh └── tasks │ └── main.yml ├── fzf ├── _env.zsh └── tasks │ └── main.yml ├── git ├── README.md ├── aliases.zsh ├── files │ ├── gitattributes_global.link │ └── gitignore_global.link ├── tasks │ ├── .pre-commit-config.yaml │ ├── debian.yml │ ├── mac.yml │ ├── main.yml │ └── redhat.yml └── templates │ └── gitconfig.j2 ├── gsed ├── path.zsh └── tasks │ └── main.yml ├── jrnl ├── README.md ├── files │ └── jrnl.yaml ├── meta │ └── main.yml └── tasks │ └── main.yml ├── k9s ├── aliases.zsh └── tasks │ └── main.yml ├── kubernetes ├── aliases.zsh └── tasks │ ├── mac.yml │ └── main.yml ├── lctl ├── _lctl └── tasks │ └── main.yml ├── macos ├── aliases.zsh ├── defaults │ └── main.yml ├── files │ └── set-defaults.sh └── tasks │ └── main.yml ├── mise ├── README.md ├── activate.zsh ├── files │ ├── config.toml │ └── config.toml.link └── tasks │ └── main.yml ├── ollama ├── README.md ├── _env.zsh ├── files │ └── com.sloria.ollama.plist └── tasks │ ├── mac.yml │ └── main.yml ├── package_manager ├── README.md ├── defaults │ └── main.yml └── tasks │ ├── debian.yml │ ├── mac.yml │ ├── main.yml │ └── redhat.yml ├── python ├── README.md ├── _env.zsh ├── aliases.zsh ├── completion.zsh ├── final.zsh ├── functions.zsh └── tasks │ ├── mac.yml │ └── main.yml ├── rg ├── README.md ├── defaults │ └── main.yml └── tasks │ ├── debian.yml │ └── main.yml ├── rust ├── path.zsh └── tasks │ └── main.yml ├── vim ├── README.md ├── defaults │ └── main.yml ├── files │ ├── javascript.snippets │ ├── python.snippets │ ├── rst.snippets │ └── vimrc ├── meta │ └── main.yml └── tasks │ ├── debian.yml │ ├── mac.yml │ ├── main.yml │ └── redhat.yml ├── z ├── enable.zsh └── z.sh └── zsh ├── README.md ├── _env.zsh ├── _path.zsh ├── aliases.zsh ├── config.zsh ├── defaults └── main.yml ├── files ├── install_prezto.sh ├── zpreztorc.link ├── zshrc.link └── zshrc_minimal ├── fpath.zsh ├── functions.zsh └── tasks ├── debian.yml ├── mac.yml ├── main.yml ├── prezto.yml └── redhat.yml /.gitignore: -------------------------------------------------------------------------------- 1 | ########## Generated by gig ########### 2 | 3 | ### Python ### 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | 45 | # Translations 46 | *.mo 47 | *.pot 48 | 49 | # Django stuff: 50 | *.log 51 | 52 | # Sphinx documentation 53 | docs/_build/ 54 | 55 | # PyBuilder 56 | target/ 57 | 58 | remotehosts 59 | *.retry 60 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/rbubley/mirrors-prettier 3 | rev: v3.5.3 4 | hooks: 5 | - id: prettier 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dotfiles 2 | 3 | [sloria's dotfiles](https://github.com/sloria/dotfiles-old), rewritten as Ansible roles. Sets up a full local development environment with a **single command.** 4 | 5 | **As of 2025, this repo only supports macOS.** There's still remnants of Red Hat and Debian support, but they are not maintained. 6 | 7 | ## a few neat features 8 | 9 | - zsh configured with [prezto](https://github.com/sorin-ionescu/prezto). 10 | - nice fonts for the terminal and coding. 11 | - python managed with [uv](https://docs.astral.sh/uv/) 12 | - vim with [vim-plug](https://github.com/junegunn/vim-plug) for plugin management. All configuration in a single file [.vimrc](https://github.com/sloria/dotfiles/blob/master/roles/vim/files/vimrc). 13 | - pluggable. Everything is optional. Fork this. Remove what you don't use. Configure what you do use. 14 | - Mac packages installed with [homebrew][]. Mac apps installed with [homebrew cask][] and [mas][]. 15 | - Useful git aliases 16 | 17 | ## prerequisites 18 | 19 | - homebrew (If on macOS) - **Install this first** 20 | - git: `brew install git` 21 | - ansible >= 1.6: `brew install ansible` 22 | 23 | ## install 24 | 25 | - [Fork](https://github.com/sloria/dotfiles/fork) this repo. 26 | - Clone your fork. 27 | 28 | ```bash 29 | # Replace git url with your fork 30 | # NOTE: It is important that you clone to ~/dotfiles 31 | git clone https://github.com/YOU/dotfiles.git ~/dotfiles 32 | cd ~/dotfiles 33 | ``` 34 | 35 | - Update the following variables in `group_vars/local` (at a minimum) 36 | - `full_name`: Your name, which will be attached to commit messages, e.g. "Steven Loria" 37 | - `git_user`: Your Github username. 38 | - `git_email`: Your git email address. 39 | - Optional, but recommended: Update `group_vars/local` with the programs you want installed by [homebrew][], [homebrew-cask][], and npm. 40 | - `mac_homebrew_packages`: Utilities that don't get installed by the roles. 41 | - `mac_cask_packages`: Mac Apps you want installed with [homebrew-cask][]. 42 | - Edit `local_env.yml` as you see fit. Remove any roles you don't use. Edit roles that you do use. 43 | - Run the installation script. 44 | 45 | ```bash 46 | ./bin/dot-bootstrap 47 | ``` 48 | 49 | ## authenticating with github 50 | 51 | You won't be able to push to repos until you authenticate with GitHub. 52 | You can use `gh` for this, which should have been installed by `dot-bootstrap` above. 53 | 54 | ``` 55 | gh auth login 56 | ``` 57 | 58 | ## updating your local environment 59 | 60 | Once you have the dotfiles installed you can run the following command to rerun the ansible playbook: 61 | 62 | ```bash 63 | dot-update 64 | ``` 65 | 66 | You can optionally pass role names 67 | 68 | ```bash 69 | dot-update git python 70 | ``` 71 | 72 | ## updating your dotfiles repo 73 | 74 | To keep your fork up to date with the `sloria` fork: 75 | 76 | ``` 77 | git remote add sloria https://github.com/sloria/dotfiles.git 78 | git pull sloria master 79 | ``` 80 | 81 | ## commands 82 | 83 | There are three main commands in the `bin` directory for setting up and updating development environments: 84 | 85 | - `dot-bootstrap`: sets up local environment by executing all roles in `local_env.yml`. 86 | - `dot-update`: updates local environment by executing all roles in `local_env.yml` except for the ones tagged with "bootstrap". 87 | 88 | ## special files 89 | 90 | All configuration is done in `~/dotfiles`. Each role may contain (in addition to the typical ansible directories and files) a number of special files 91 | 92 | - **role/\*.zsh**: Any files ending in `.zsh` get loaded into your environment. 93 | - **bin/**: Anything in `bin/` will get added to your `$PATH` and be made available everywhere. 94 | 95 | ## notes 96 | 97 | **vscode** 98 | 99 | Use built-in Settings Sync to sync VSCode settings. 100 | 101 | **macOS keyboard settings** 102 | 103 | There are a few keyboard customizations that must be done manually: 104 | 105 | - System Settings > Keyboard > Turn "Key repeat rate" and "Delay until repeat" to their highest settings. 106 | 107 | ![Keyboard settings](https://github.com/user-attachments/assets/0c0e9ed6-3e5b-4996-b1e0-4aa4e9de3725 "Key repeat settings") 108 | 109 | - System Settings > Keyboard > Keyboard Shortcuts > Modifier Keys > Change Caps Lock key to Control. 110 | 111 | ![Modifier keys](https://github.com/user-attachments/assets/79a883cd-9eec-472e-bdb6-0b4c2efeea9d) 112 | 113 | **mac mini** 114 | 115 | I also use this repo to configure my Mac Mini server which I have running in headless mode. My setup is documented in [docs/MAC_MINI.md](docs/MAC_MINI.md). 116 | 117 | ## what if I only want your vim? 118 | 119 | First make sure you have a sane vim compiled. On macOS, the following will do: 120 | 121 | ``` 122 | brew install vim 123 | ``` 124 | 125 | The following commands will install vim-plug and download my `.vimrc`. 126 | 127 | After backing up your `~/.vim` directory and `~/.vimrc`: 128 | 129 | ``` 130 | mkdir -p ~/.vim/autoload 131 | curl -fLo ~/.vim/autoload/plug.vim https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim 132 | curl -fLo ~/.vimrc https://raw.githubusercontent.com/sloria/dotfiles/master/roles/vim/files/vimrc 133 | ``` 134 | 135 | You will now be able to open vim and run `:PlugInstall` to install all plugins. 136 | 137 | ## troubleshooting 138 | 139 | If you get an error about Xcode command-line tools, you may need to run 140 | 141 | ``` 142 | sudo xcode-select -s /Applications/Xcode.app/Contents/Developer 143 | ``` 144 | 145 | [homebrew]: http://brew.sh/ 146 | [homebrew-cask]: https://github.com/caskroom/homebrew-cask 147 | [mas]: https://github.com/mas-cli/mas 148 | 149 | ## license 150 | 151 | [MIT Licensed](http://sloria.mit-license.org/). 152 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | pipelining = True 3 | become = True 4 | host_key_checking = False 5 | -------------------------------------------------------------------------------- /bin/dot-bootstrap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | echo "Setting up local dev environment..." 5 | ansible-playbook -i ~/dotfiles/hosts ~/dotfiles/local_env.yml --ask-become-pass 6 | 7 | # If terminal-notifier is installed, use it to display a notification 8 | if command -v terminal-notifier 1>/dev/null 2>&1; then 9 | terminal-notifier -title "dotfiles: Bootstrap complete" -message "Successfully set up dev environment." 10 | fi 11 | -------------------------------------------------------------------------------- /bin/dot-bootstrap-remote: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | echo "Setting up remote environment(s)..." 5 | ansible-playbook -i ~/dotfiles/hosts ~/dotfiles/mac-mini.yml --ask-become-pass 6 | 7 | # If terminal-notifier is installed, use it to display a notification 8 | if command -v terminal-notifier 1>/dev/null 2>&1; then 9 | terminal-notifier -title "dotfiles: Bootstrap complete" -message "Successfully set up remote environment(s)." 10 | fi 11 | -------------------------------------------------------------------------------- /bin/dot-update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Update local dev environment using ansible-playbook. 3 | # Optionally pass role names. 4 | set -e 5 | 6 | if [[ $# -eq 0 ]]; then 7 | # Run all roles except for the ones tagged with 'bootstrap' 8 | echo "Updating local dev environment..." 9 | ansible-playbook -i ~/dotfiles/hosts ~/dotfiles/local_env.yml --skip-tags "bootstrap" 10 | else 11 | echo "Updating local dev environment... (--tags $@)" 12 | ansible-playbook -i ~/dotfiles/hosts ~/dotfiles/local_env.yml --skip-tags "bootstrap" --tags $@ 13 | fi 14 | 15 | # If terminal-notifier is installed, use it to display a notification 16 | if command -v terminal-notifier 1>/dev/null 2>&1; then 17 | terminal-notifier -title "dotfiles: Update complete" -message "Successfully updated dev environment." 18 | fi 19 | -------------------------------------------------------------------------------- /bin/dot-update-remote: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Update remote environment(s) using ansible-playbook. 3 | # Optionally pass role names. 4 | set -e 5 | 6 | if [[ $# -eq 0 ]]; then 7 | # Run all roles except for the ones tagged with 'bootstrap' 8 | echo "Updating remote environment(s)..." 9 | ansible-playbook -i ~/dotfiles/hosts ~/dotfiles/remote_env.yml --skip-tags "bootstrap" --ask-become-pass 10 | else 11 | echo "Updating remote environment(s)... (--tags $@)" 12 | ansible-playbook -i ~/dotfiles/hosts ~/dotfiles/remote_env.yml --skip-tags "bootstrap" --tags $@ --ask-become-pass 13 | fi 14 | 15 | # If terminal-notifier is installed, use it to display a notification 16 | if command -v terminal-notifier 1>/dev/null 2>&1; then 17 | terminal-notifier -title "dotfiles: Update complete" -message "Successfully updated remote environment(s)." 18 | fi 19 | -------------------------------------------------------------------------------- /bin/e: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Quick shortcut to an editor. 4 | # 5 | # This means that as I travel back and forth between editors, hey, I don't have 6 | # to re-learn any arcane commands. Neat. 7 | # 8 | # USAGE: 9 | # 10 | # e 11 | # # => opens the current directory in your editor 12 | # 13 | # e . 14 | # e /usr/local 15 | # => opens the specified directory in your editor 16 | 17 | if [ "$1" = "" ] ; then 18 | exec $EDITOR . 19 | else 20 | exec $EDITOR "$1" 21 | fi 22 | -------------------------------------------------------------------------------- /bin/git-find-commit: -------------------------------------------------------------------------------- 1 | # Fuzzy commit finder 2 | # Requires fzf 3 | # https://github.com/junegunn/fzf/wiki/Examples 4 | git log --graph --color=always \ 5 | --format="%C(auto)%h%d %s %C(black)%C(bold)%cr" "$@" | 6 | fzf --ansi --no-sort --reverse --tiebreak=index --bind=ctrl-s:toggle-sort \ 7 | --bind "ctrl-m:execute: 8 | (grep -o '[a-f0-9]\{7\}' | head -1 | 9 | xargs -I % sh -c 'git show --color=always % | less -R') << 'FZF-EOF' 10 | {} 11 | FZF-EOF" 12 | -------------------------------------------------------------------------------- /bin/itry: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # itry - A portable script for launching ipython with uvx packages 3 | # Source: https://til.simonwillison.net/python/itry 4 | 5 | # Show help if requested 6 | [ "$1" = "--help" ] && { 7 | echo "Usage: itry [packages...]" 8 | echo "Example: itry llm sqlite-utils datasette" 9 | exit 0 10 | } 11 | 12 | # Initialize empty string for packages 13 | PACKAGES="" 14 | 15 | # Process all arguments, adding --with before each 16 | for arg in "$@"; do 17 | PACKAGES="$PACKAGES --with $arg" 18 | done 19 | 20 | # Remove leading space if present 21 | PACKAGES="${PACKAGES# }" 22 | 23 | # Execute uvx command with Python 3.13 24 | exec uvx $PACKAGES --python 3.13 ipython 25 | -------------------------------------------------------------------------------- /bin/upgrades: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "==> Upgrading Homebrew packages..." 4 | brew upgrade 5 | echo "==> Upgrading Vim plugins..." 6 | vim +PlugUpdate +qall 7 | 8 | if command -v ollama > /dev/null 2>&1; then 9 | echo "==> Upgrading Ollama models..." 10 | ollama list | tail -n +2 | awk '{print $1}' | while read -r model; do 11 | echo "==> Upgrading $model..." 12 | ollama pull $model 13 | done 14 | fi 15 | 16 | echo "==> Upgrades complete." 17 | 18 | if [[ -z "$SSH_CLIENT" && -z "$SSH_TTY" ]] && command -v terminal-notifier 1>/dev/null 2>&1; then 19 | terminal-notifier -title "dotfiles: upgrades" -message "Upgrades complete." 20 | fi 21 | -------------------------------------------------------------------------------- /docs/MAC_MINI.md: -------------------------------------------------------------------------------- 1 | # mac mini-specific setup 2 | 3 | ## first boot setup 4 | 5 | - Skip iCloud configuration 6 | - Enable FileVault. Save recovery key in password manager. 7 | NOTE: this requires running `sudo fdesetup authrestart` to restart. 8 | `sudo shutdown` **will not work**. 9 | 10 | ### system settings 11 | 12 | - System Settings / Network / Firewall - Enable 13 | - System Settings / Energy / Prevent automatic sleeping with the display is off, Wake for network access, Start up automatically after network failure. These settings are enabled to ensure the device does not got to sleep 14 | - System Settings / Accessibility / Display / Reduce motion, Reduce transparency - On 15 | - System Settings / Appearance / Allow wallpaper tinting in windows - Off 16 | - System Settings / General / Software Update / Automatic Updates - Download new updates when available, Install macOS updates, Install Security Responses and system files - On 17 | - System Settings / Spotlight / Search results - Disable all options 18 | - Manually remove all notification center widgets 19 | 20 | ### sharing settings 21 | 22 | - System Settings / General / Sharing / Screen Sharing - On. This allows remote access to the device via the Screen Sharing app 23 | - System Settings / General / Sharing / Content Caching - Storage, Clients / Devices using the same public IP address, use ony public IP address. 24 | - System Settings / General / Sharing / Remote Login - On. This allows SSH while while using Tailscale 25 | 26 | ### misc 27 | 28 | - Disable Bluetooth in Control Center 29 | - Once the mac mini is connected to via ethernet, disable Wi-Fi in Control Center 30 | 31 | ### sources 32 | 33 | - https://stealthpuppy.com/mac-mini-home-server/#first-boot-setup 34 | 35 | ## bootstrapping the mac mini environment 36 | 37 | ``` 38 | dot-bootstrap-remote 39 | ``` 40 | 41 | ## updating roles 42 | 43 | ``` 44 | dot-update-remote 45 | ``` 46 | 47 | to update a specific role 48 | 49 | ``` 50 | dot-update-remote python 51 | ``` 52 | 53 | ## upgrading packages, docker images, etc. 54 | 55 | ssh into the mac-mini and run the `upgrades` script 56 | 57 | ``` 58 | ssh mac-mini 59 | upgrades 60 | ``` 61 | -------------------------------------------------------------------------------- /group_vars/local: -------------------------------------------------------------------------------- 1 | # vi: set ft=yaml : 2 | 3 | # NOTE: The below 2 variables should not need to be changed if you cloned 4 | # the dotfiles repo to '~/dotfiles' 5 | # Local home directory 6 | dotfiles_user_home: "{{ '~' | expanduser }}" 7 | # Where your dotfiles live. Probably don't need to change this. 8 | dotfiles_home: "{{dotfiles_user_home}}/dotfiles" 9 | 10 | # Name used in commit messages 11 | full_name: Steven Loria 12 | # Git 13 | # Github username 14 | git_user: sloria 15 | # If you use github, this should be the same as the email 16 | # used on Github 17 | git_email: sloria1@gmail.com 18 | 19 | # Determines if iCloud Drive is symlinked to ~/iCloud 20 | icloud_enabled: true 21 | 22 | # Utilities that don't get installed by a role 23 | mac_homebrew_packages: 24 | - curl 25 | - jq 26 | - wget 27 | - terminal-notifier 28 | - yt-dlp 29 | - htop 30 | - bottom 31 | - imagemagick # for resizing images 32 | - diff-so-fancy 33 | - gh 34 | # Top for docker containers 35 | - ctop 36 | # User-contributed docs for Unix commands 37 | - tldr 38 | # what's the wifi password? 39 | - wifi-password 40 | # For repeating commands 41 | - watch 42 | - watchexec 43 | - qrtool # for generating QR codes 44 | 45 | # Mac Apps to be installed with homebrew-cask 46 | mac_cask_packages: 47 | # Password manager 48 | - 1password 49 | # Editor 50 | - visual-studio-code 51 | # Backup/storage 52 | - dropbox 53 | # Browsers 54 | - firefox 55 | # Display 56 | - keepingyouawake # maintained caffeinate wrapper 57 | # Utilities 58 | - bettertouchtool 59 | - appcleaner 60 | - daisydisk 61 | # More resource-efficient Docker 62 | - orbstack 63 | # chat 64 | - slack 65 | - discord 66 | # Video conferencing 67 | - zoom 68 | # Media/Music 69 | - spotify 70 | - iina 71 | # Images 72 | - imageoptim 73 | # Notetaking 74 | - obsidian 75 | # Fonts 76 | - font-hack 77 | # Database client 78 | - tableplus 79 | # REST client 80 | - insomnia 81 | # Screen captures and recording 82 | - cleanshot 83 | # Email client 84 | - mimestream 85 | # VPN 86 | - tailscale 87 | # Color picker 88 | - pika 89 | 90 | # Mac-App-Store-only apps to be installed with mas 91 | # Use App IDs found with `mas search ` 92 | mac_mas_packages: 93 | # NOTE: the IDs can be found with `mas search ` 94 | - {"id": 409203825, "name": "Numbers"} 95 | -------------------------------------------------------------------------------- /group_vars/remote: -------------------------------------------------------------------------------- 1 | # vi: set ft=yaml : 2 | 3 | # NOTE: The below 2 variables should not need to be changed if you cloned 4 | # the dotfiles repo to '~/dotfiles' 5 | # Local home directory 6 | dotfiles_user_home: "{{ '~' | expanduser }}" 7 | # Where your dotfiles live. Probably don't need to change this. 8 | dotfiles_home: "{{dotfiles_user_home}}/dotfiles" 9 | 10 | # Name used in commit messages 11 | full_name: Steven Loria 12 | # Git 13 | # Github username 14 | git_user: sloria 15 | # If you use github, this should be the same as the email 16 | # used on Github 17 | git_email: sloria1@gmail.com 18 | 19 | # Determines if iCloud Drive is symlinked to ~/iCloud 20 | icloud_enabled: false 21 | 22 | # Utilities that don't get installed by a role 23 | mac_homebrew_packages: 24 | - curl 25 | - jq 26 | - wget 27 | - bottom 28 | - diff-so-fancy 29 | - gh 30 | # Top for docker containers 31 | - ctop 32 | # User-contributed docs for Unix commands 33 | - tldr 34 | 35 | # Mac Apps to be installed with homebrew-cask 36 | mac_cask_packages: 37 | # More resource-efficient Docker 38 | - orbstack 39 | # VPN 40 | - tailscale 41 | 42 | ollama_models: [] 43 | 44 | -------------------------------------------------------------------------------- /hosts: -------------------------------------------------------------------------------- 1 | [local] 2 | localhost ansible_connection=local 3 | 4 | [remote] 5 | mac-mini ansible_user=stevenloria 6 | -------------------------------------------------------------------------------- /local_env.yml: -------------------------------------------------------------------------------- 1 | - name: Set up local development environment 2 | hosts: local 3 | roles: 4 | # Tag each role so that we can select individual roles to run with ansible-playbook --tags 5 | - { role: git, tags: ["git"] } 6 | - { role: package_manager, tags: ["package_manager", "bootstrap"] } 7 | - { role: zsh, tags: ["zsh", "bootstrap"] } 8 | - { role: python, tags: ["python"] } 9 | - { role: mise, tags: ["mise"] } 10 | - { role: rust, tags: ["rust"] } 11 | - { role: vim, tags: ["vim"] } 12 | - { role: rg, tags: ["rg"] } 13 | - { role: eza, tags: ["eza"] } 14 | - { role: gsed, tags: ["gsed"] } 15 | - { role: bat, tags: ["bat"] } 16 | - { role: fzf, tags: ["fzf"] } 17 | - { role: kubernetes, tags: ["kubernetes"] } 18 | - { role: jrnl, tags: ["jrnl"] } 19 | - { role: k9s, tags: ["k9s"] } 20 | - { role: lctl, tags: ["lctl"], when: ansible_os_family == "Darwin" } 21 | - { role: macos, tags: ["macos"], when: ansible_os_family == "Darwin" } 22 | -------------------------------------------------------------------------------- /misc/bettertouchtool/README.md: -------------------------------------------------------------------------------- 1 | # BetterTouchTool 2 | 3 | This folder contains my better touch tool configuration file. To use, open Better Touch Tool, and import the file. 4 | -------------------------------------------------------------------------------- /misc/terminal/sloria-ayu.terminal: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ANSIBlackColor 6 | 7 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 8 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NGMCAw 9 | IDAAEAKAAtIQERITWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xvcqISFFhOU09iamVj 10 | dF8QD05TS2V5ZWRBcmNoaXZlctEXGFRyb290gAEIERojLTI3O0FITltiaWttcn2GjpGa 11 | rK+0AAAAAAAAAQEAAAAAAAAAGQAAAAAAAAAAAAAAAAAAALY= 12 | 13 | ANSIBlueColor 14 | 15 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 16 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 17 | LjIxMTc2NDcwNTkgMC42MzkyMTU2ODYzIDAuODUwOTgwMzkyMgAQAoAC0hAREhNaJGNs 18 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 19 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 20 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 21 | 22 | ANSIBrightBlackColor 23 | 24 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 25 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 26 | LjE5NjA3ODQzMTQgMC4xOTYwNzg0MzE0IDAuMTk2MDc4NDMxNAAQAoAC0hAREhNaJGNs 27 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 28 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 29 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 30 | 31 | ANSIBrightBlueColor 32 | 33 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 34 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPEBww 35 | LjQwNzg0MzEzNzMgMC44MzUyOTQxMTc2IDEAEAKAAtIQERITWiRjbGFzc25hbWVYJGNs 36 | YXNzZXNXTlNDb2xvcqISFFhOU09iamVjdF8QD05TS2V5ZWRBcmNoaXZlctEXGFRyb290 37 | gAEIERojLTI3O0FITltigYOFipWepqmyxMfMAAAAAAAAAQEAAAAAAAAAGQAAAAAAAAAA 38 | AAAAAAAAAM4= 39 | 40 | ANSIBrightCyanColor 41 | 42 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 43 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPEBww 44 | Ljc4MDM5MjE1NjkgMSAwLjk5MjE1Njg2MjcAEAKAAtIQERITWiRjbGFzc25hbWVYJGNs 45 | YXNzZXNXTlNDb2xvcqISFFhOU09iamVjdF8QD05TS2V5ZWRBcmNoaXZlctEXGFRyb290 46 | gAEIERojLTI3O0FITltigYOFipWepqmyxMfMAAAAAAAAAQEAAAAAAAAAGQAAAAAAAAAA 47 | AAAAAAAAAM4= 48 | 49 | ANSIBrightGreenColor 50 | 51 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 52 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 53 | LjkxNzY0NzA1ODggMC45OTYwNzg0MzE0IDAuNTE3NjQ3MDU4OAAQAoAC0hAREhNaJGNs 54 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 55 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 56 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 57 | 58 | ANSIBrightMagentaColor 59 | 60 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 61 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPEBwx 62 | IDAuNjM5MjE1Njg2MyAwLjY2NjY2NjY2NjcAEAKAAtIQERITWiRjbGFzc25hbWVYJGNs 63 | YXNzZXNXTlNDb2xvcqISFFhOU09iamVjdF8QD05TS2V5ZWRBcmNoaXZlctEXGFRyb290 64 | gAEIERojLTI3O0FITltigYOFipWepqmyxMfMAAAAAAAAAQEAAAAAAAAAGQAAAAAAAAAA 65 | AAAAAAAAAM4= 66 | 67 | ANSIBrightRedColor 68 | 69 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 70 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPEBwx 71 | IDAuMzk2MDc4NDMxNCAwLjM5NjA3ODQzMTQAEAKAAtIQERITWiRjbGFzc25hbWVYJGNs 72 | YXNzZXNXTlNDb2xvcqISFFhOU09iamVjdF8QD05TS2V5ZWRBcmNoaXZlctEXGFRyb290 73 | gAEIERojLTI3O0FITltigYOFipWepqmyxMfMAAAAAAAAAQEAAAAAAAAAGQAAAAAAAAAA 74 | AAAAAAAAAM4= 75 | 76 | ANSIBrightWhiteColor 77 | 78 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 79 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NGMSAx 80 | IDEAEAKAAtIQERITWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xvcqISFFhOU09iamVj 81 | dF8QD05TS2V5ZWRBcmNoaXZlctEXGFRyb290gAEIERojLTI3O0FITltiaWttcn2GjpGa 82 | rK+0AAAAAAAAAQEAAAAAAAAAGQAAAAAAAAAAAAAAAAAAALY= 83 | 84 | ANSIBrightYellowColor 85 | 86 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 87 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPEBsx 88 | IDAuOTY4NjI3NDUxIDAuNDc0NTA5ODAzOQAQAoAC0hAREhNaJGNsYXNzbmFtZVgkY2xh 89 | c3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJvb3SA 90 | AQgRGiMtMjc7QUhOW2KAgoSJlJ2lqLHDxssAAAAAAAABAQAAAAAAAAAZAAAAAAAAAAAA 91 | AAAAAAAAzQ== 92 | 93 | ANSICyanColor 94 | 95 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 96 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 97 | LjU4NDMxMzcyNTUgMC45MDE5NjA3ODQzIDAuNzk2MDc4NDMxNAAQAoAC0hAREhNaJGNs 98 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 99 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 100 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 101 | 102 | ANSIGreenColor 103 | 104 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 105 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPEB4w 106 | LjcyMTU2ODYyNzUgMC44IDAuMzIxNTY4NjI3NQAQAoAC0hAREhNaJGNsYXNzbmFtZVgk 107 | Y2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJv 108 | b3SAAQgRGiMtMjc7QUhOW2KDhYeMl6Coq7TGyc4AAAAAAAABAQAAAAAAAAAZAAAAAAAA 109 | AAAAAAAAAAAA0A== 110 | 111 | ANSIMagentaColor 112 | 113 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 114 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 115 | Ljk0MTE3NjQ3MDYgMC40NDMxMzcyNTQ5IDAuNDcwNTg4MjM1MwAQAoAC0hAREhNaJGNs 116 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 117 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 118 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 119 | 120 | ANSIRedColor 121 | 122 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 123 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NKMSAw 124 | LjIgMC4yABACgALSEBESE1okY2xhc3NuYW1lWCRjbGFzc2VzV05TQ29sb3KiEhRYTlNP 125 | YmplY3RfEA9OU0tleWVkQXJjaGl2ZXLRFxhUcm9vdIABCBEaIy0yNztBSE5bYm1vcXaB 126 | ipKVnrCzuAAAAAAAAAEBAAAAAAAAABkAAAAAAAAAAAAAAAAAAAC6 127 | 128 | ANSIWhiteColor 129 | 130 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 131 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NGMSAx 132 | IDEAEAKAAtIQERITWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xvcqISFFhOU09iamVj 133 | dF8QD05TS2V5ZWRBcmNoaXZlctEXGFRyb290gAEIERojLTI3O0FITltiaWttcn2GjpGa 134 | rK+0AAAAAAAAAQEAAAAAAAAAGQAAAAAAAAAAAAAAAAAAALY= 135 | 136 | ANSIYellowColor 137 | 138 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 139 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 140 | LjkwNTg4MjM1MjkgMC43NzI1NDkwMTk2IDAuMjc4NDMxMzcyNQAQAoAC0hAREhNaJGNs 141 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 142 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 143 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 144 | 145 | BackgroundColor 146 | 147 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 148 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECow 149 | LjA1ODgyMzUyOTQxIDAuMDc4NDMxMzcyNTUgMC4wOTgwMzkyMTU2OQAQAoAC0hAREhNa 150 | JGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFy 151 | Y2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KPkZOYo6y0t8DS1doAAAAAAAABAQAA 152 | AAAAAAAZAAAAAAAAAAAAAAAAAAAA3A== 153 | 154 | Bell 155 | 156 | CursorBlink 157 | 158 | CursorColor 159 | 160 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 161 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECgw 162 | Ljk0OTAxOTYwNzggMC41OTIxNTY4NjI3IDAuMDk0MTE3NjQ3MDYAEAKAAtIQERITWiRj 163 | bGFzc25hbWVYJGNsYXNzZXNXTlNDb2xvcqISFFhOU09iamVjdF8QD05TS2V5ZWRBcmNo 164 | aXZlctEXGFRyb290gAEIERojLTI3O0FITltijY+RlqGqsrW+0NPYAAAAAAAAAQEAAAAA 165 | AAAAGQAAAAAAAAAAAAAAAAAAANo= 166 | 167 | Font 168 | 169 | YnBsaXN0MDDUAQIDBAUGGBlYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 170 | AAGGoKQHCBESVSRudWxs1AkKCwwNDg8QVk5TU2l6ZVhOU2ZGbGFnc1ZOU05hbWVWJGNs 171 | YXNzI0AoAAAAAAAAEBCAAoADXEhhY2stUmVndWxhctITFBUWWiRjbGFzc25hbWVYJGNs 172 | YXNzZXNWTlNGb250ohUXWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RobVHJvb3SA 173 | AQgRGiMtMjc8QktSW2JpcnR2eIWKlZ6lqLHDxssAAAAAAAABAQAAAAAAAAAcAAAAAAAA 174 | AAAAAAAAAAAAzQ== 175 | 176 | ProfileCurrentVersion 177 | 2.0600000000000001 178 | SelectionColor 179 | 180 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 181 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPEB4w 182 | LjE0NTA5ODAzOTIgMC4yIDAuMjUwOTgwMzkyMgAQAoAC0hAREhNaJGNsYXNzbmFtZVgk 183 | Y2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RcYVHJv 184 | b3SAAQgRGiMtMjc7QUhOW2KDhYeMl6Coq7TGyc4AAAAAAAABAQAAAAAAAAAZAAAAAAAA 185 | AAAAAAAAAAAA0A== 186 | 187 | ShowActiveProcessInTitle 188 | 189 | ShowDimensionsInTitle 190 | 191 | ShowRepresentedURLInTitle 192 | 193 | TextBoldColor 194 | 195 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 196 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 197 | LjkwMTk2MDc4NDMgMC44ODIzNTI5NDEyIDAuODExNzY0NzA1OQAQAoAC0hAREhNaJGNs 198 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 199 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 200 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 201 | 202 | TextColor 203 | 204 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 205 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 206 | LjkwMTk2MDc4NDMgMC44ODIzNTI5NDEyIDAuODExNzY0NzA1OQAQAoAC0hAREhNaJGNs 207 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 208 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 209 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 210 | 211 | VisualBell 212 | 213 | columnCount 214 | 90 215 | name 216 | sloria-ayu 217 | noWarnProcesses 218 | 219 | 220 | ProcessName 221 | screen 222 | 223 | 224 | rowCount 225 | 50 226 | type 227 | Window Settings 228 | warnOnShellCloseAction 229 | 0 230 | 231 | 232 | -------------------------------------------------------------------------------- /misc/terminal/sloria-night-owl.terminal: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ANSIBlackColor 6 | 7 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 8 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECow 9 | LjAwMzkyMTU2ODg1OSAwLjA4NjI3NDUxMjExIDAuMTUyOTQxMTgyMwAQAYAC0hAREhNa 10 | JGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFy 11 | Y2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KPkZOYo6y0t8DS1doAAAAAAAABAQAA 12 | AAAAAAAZAAAAAAAAAAAAAAAAAAAA3A== 13 | 14 | ANSIBlueColor 15 | 16 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 17 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPEBww 18 | LjUwOTgwMzk1MDggMC42NjY2NjY2ODY1IDEAEAGAAtIQERITWiRjbGFzc25hbWVYJGNs 19 | YXNzZXNXTlNDb2xvcqISFFhOU09iamVjdF8QD05TS2V5ZWRBcmNoaXZlctEXGFRyb290 20 | gAEIERojLTI3O0FITltigYOFipWepqmyxMfMAAAAAAAAAQEAAAAAAAAAGQAAAAAAAAAA 21 | AAAAAAAAAM4= 22 | 23 | ANSIBrightBlackColor 24 | 25 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 26 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 27 | LjI2NjY2NjY4MDYgMC4zNDkwMTk2MTY4IDAuNDE5NjA3ODQ3OQAQAYAC0hAREhNaJGNs 28 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 29 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 30 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 31 | 32 | ANSIBrightBlueColor 33 | 34 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 35 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECYw 36 | LjM2MDc4NDMyMiAwLjY1NDkwMTk4MTQgMC44OTQxMTc2NTM0ABABgALSEBESE1okY2xh 37 | c3NuYW1lWCRjbGFzc2VzV05TQ29sb3KiEhRYTlNPYmplY3RfEA9OU0tleWVkQXJjaGl2 38 | ZXLRFxhUcm9vdIABCBEaIy0yNztBSE5bYouNj5SfqLCzvM7R1gAAAAAAAAEBAAAAAAAA 39 | ABkAAAAAAAAAAAAAAAAAAADY 40 | 41 | ANSIBrightCyanColor 42 | 43 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 44 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECUw 45 | LjEyOTQxMTc3MTkgMC43ODAzOTIxNyAwLjY1ODgyMzU0OTcAEAGAAtIQERITWiRjbGFz 46 | c25hbWVYJGNsYXNzZXNXTlNDb2xvcqISFFhOU09iamVjdF8QD05TS2V5ZWRBcmNoaXZl 47 | ctEXGFRyb290gAEIERojLTI3O0FITltiioyOk56nr7K7zdDVAAAAAAAAAQEAAAAAAAAA 48 | GQAAAAAAAAAAAAAAAAAAANc= 49 | 50 | ANSIBrightGreenColor 51 | 52 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 53 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 54 | LjEzMzMzMzM0MDMgMC44NTQ5MDE5Njk0IDAuNDMxMzcyNTUzMQAQAYAC0hAREhNaJGNs 55 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 56 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 57 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 58 | 59 | ANSIBrightMagentaColor 60 | 61 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 62 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECYw 63 | LjQ5NDExNzY0NzQgMC4zNDExNzY0ODAxIDAuNzYwNzg0MzI4ABABgALSEBESE1okY2xh 64 | c3NuYW1lWCRjbGFzc2VzV05TQ29sb3KiEhRYTlNPYmplY3RfEA9OU0tleWVkQXJjaGl2 65 | ZXLRFxhUcm9vdIABCBEaIy0yNztBSE5bYouNj5SfqLCzvM7R1gAAAAAAAAEBAAAAAAAA 66 | ABkAAAAAAAAAAAAAAAAAAADY 67 | 68 | ANSIBrightRedColor 69 | 70 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 71 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 72 | LjkzNzI1NDkwNTcgMC4zMjU0OTAyMDY1IDAuMzEzNzI1NTAxMwAQAYAC0hAREhNaJGNs 73 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 74 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 75 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 76 | 77 | ANSIBrightWhiteColor 78 | 79 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 80 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NGMSAx 81 | IDEAEAGAAtIQERITWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xvcqISFFhOU09iamVj 82 | dF8QD05TS2V5ZWRBcmNoaXZlctEXGFRyb290gAEIERojLTI3O0FITltiaWttcn2GjpGa 83 | rK+0AAAAAAAAAQEAAAAAAAAAGQAAAAAAAAAAAAAAAAAAALY= 84 | 85 | ANSIBrightYellowColor 86 | 87 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 88 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPEBwx 89 | IDAuOTIxNTY4NjMyMSAwLjU4NDMxMzc1MDMAEAGAAtIQERITWiRjbGFzc25hbWVYJGNs 90 | YXNzZXNXTlNDb2xvcqISFFhOU09iamVjdF8QD05TS2V5ZWRBcmNoaXZlctEXGFRyb290 91 | gAEIERojLTI3O0FITltigYOFipWepqmyxMfMAAAAAAAAAQEAAAAAAAAAGQAAAAAAAAAA 92 | AAAAAAAAAM4= 93 | 94 | ANSICyanColor 95 | 96 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 97 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 98 | LjQ5ODAzOTIxNTggMC44NTg4MjM1Mzc4IDAuNzkyMTU2ODc1MQAQAYAC0hAREhNaJGNs 99 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 100 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 101 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 102 | 103 | ANSIGreenColor 104 | 105 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 106 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 107 | LjY3ODQzMTM5MTcgMC44NTg4MjM1Mzc4IDAuNDAzOTIxNTc0NAAQAYAC0hAREhNaJGNs 108 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 109 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 110 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 111 | 112 | ANSIMagentaColor 113 | 114 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 115 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECUw 116 | Ljc4MDM5MjE3IDAuNTcyNTQ5MDQ1MSAwLjkxNzY0NzA2MzcAEAGAAtIQERITWiRjbGFz 117 | c25hbWVYJGNsYXNzZXNXTlNDb2xvcqISFFhOU09iamVjdF8QD05TS2V5ZWRBcmNoaXZl 118 | ctEXGFRyb290gAEIERojLTI3O0FITltiioyOk56nr7K7zdDVAAAAAAAAAQEAAAAAAAAA 119 | GQAAAAAAAAAAAAAAAAAAANc= 120 | 121 | ANSIRedColor 122 | 123 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 124 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 125 | Ljk2ODYyNzQ1MjkgMC41NDkwMTk2MzQ3IDAuNDIzNTI5NDE2MwAQAYAC0hAREhNaJGNs 126 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 127 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 128 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 129 | 130 | ANSIWhiteColor 131 | 132 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 133 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 134 | Ljc0NTA5ODA1NDQgMC43NzI1NDkwMzMyIDAuODMxMzcyNTU5MQAQAYAC0hAREhNaJGNs 135 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 136 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 137 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 138 | 139 | ANSIYellowColor 140 | 141 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 142 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPEBwx 143 | IDAuNzk2MDc4NDQzNSAwLjU0NTA5ODA2NjMAEAGAAtIQERITWiRjbGFzc25hbWVYJGNs 144 | YXNzZXNXTlNDb2xvcqISFFhOU09iamVjdF8QD05TS2V5ZWRBcmNoaXZlctEXGFRyb290 145 | gAEIERojLTI3O0FITltigYOFipWepqmyxMfMAAAAAAAAAQEAAAAAAAAAGQAAAAAAAAAA 146 | AAAAAAAAAM4= 147 | 148 | BackgroundColor 149 | 150 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 151 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECow 152 | LjAwMzkyMTU2ODg1OSAwLjA4NjI3NDUxMjExIDAuMTUyOTQxMTgyMwAQAYAC0hAREhNa 153 | JGNsYXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFy 154 | Y2hpdmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KPkZOYo6y0t8DS1doAAAAAAAABAQAA 155 | AAAAAAAZAAAAAAAAAAAAAAAAAAAA3A== 156 | 157 | Bell 158 | 159 | BoldTextColor 160 | 161 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 162 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NGMSAx 163 | IDEAEAGAAtIQERITWiRjbGFzc25hbWVYJGNsYXNzZXNXTlNDb2xvcqISFFhOU09iamVj 164 | dF8QD05TS2V5ZWRBcmNoaXZlctEXGFRyb290gAEIERojLTI3O0FITltiaWttcn2GjpGa 165 | rK+0AAAAAAAAAQEAAAAAAAAAGQAAAAAAAAAAAAAAAAAAALY= 166 | 167 | CursorBlink 168 | 169 | CursorColor 170 | 171 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 172 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 173 | LjQzNTI5NDIxMDkgMC40NjY2NjY1NzkyIDAuNTEzNzI1NDU5NgAQAYAC0hAREhNaJGNs 174 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 175 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 176 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 177 | 178 | Font 179 | 180 | YnBsaXN0MDDUAQIDBAUGGBlYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 181 | AAGGoKQHCBESVSRudWxs1AkKCwwNDg8QVk5TU2l6ZVhOU2ZGbGFnc1ZOU05hbWVWJGNs 182 | YXNzI0AoAAAAAAAAEBCAAoADXEhhY2stUmVndWxhctITFBUWWiRjbGFzc25hbWVYJGNs 183 | YXNzZXNWTlNGb250ohUXWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hpdmVy0RobVHJvb3SA 184 | AQgRGiMtMjc8QktSW2JpcnR2eIWKlZ6lqLHDxssAAAAAAAABAQAAAAAAAAAcAAAAAAAA 185 | AAAAAAAAAAAAzQ== 186 | 187 | ProfileCurrentVersion 188 | 2.0600000000000001 189 | SelectionColor 190 | 191 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 192 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECcw 193 | LjM4ODIzNTMwMDggMC40NjY2NjY2Njg3IDAuNDY2NjY2NjY4NwAQAYAC0hAREhNaJGNs 194 | YXNzbmFtZVgkY2xhc3Nlc1dOU0NvbG9yohIUWE5TT2JqZWN0XxAPTlNLZXllZEFyY2hp 195 | dmVy0RcYVHJvb3SAAQgRGiMtMjc7QUhOW2KMjpCVoKmxtL3P0tcAAAAAAAABAQAAAAAA 196 | AAAZAAAAAAAAAAAAAAAAAAAA2Q== 197 | 198 | ShowActiveProcessArgumentsInTitle 199 | 200 | ShowActiveProcessInTabTitle 201 | 202 | ShowActiveProcessInTitle 203 | 204 | ShowDimensionsInTitle 205 | 206 | ShowRepresentedURLInTabTitle 207 | 208 | ShowRepresentedURLInTitle 209 | 210 | TextBoldColor 211 | 212 | YnBsaXN0MDDUAQIDBAUGKyxYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 213 | AAGGoKcHCBMZHSQoVSRudWxs1QkKCwwNDg8QERJcTlNDb21wb25lbnRzVU5TUkdCXE5T 214 | Q29sb3JTcGFjZV8QEk5TQ3VzdG9tQ29sb3JTcGFjZVYkY2xhc3NPECgwLjg1MjUzNDEw 215 | NTMgMC44NTI1MzQxMDUzIDAuODUyNTM0MTA1MyAxTxAmMC44MTgxMTc4NTcgMC44MTgw 216 | OTMzNTk1IDAuODE4MTA3MjQ3NAAQAYACgAbTFBUNFhcYVE5TSURVTlNJQ0MQB4ADgAXS 217 | Gg0bHFdOUy5kYXRhTxEMSAAADEhMaW5vAhAAAG1udHJSR0IgWFlaIAfOAAIACQAGADEA 218 | AGFjc3BNU0ZUAAAAAElFQyBzUkdCAAAAAAAAAAAAAAAAAAD21gABAAAAANMtSFAgIAAA 219 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEWNwcnQA 220 | AAFQAAAAM2Rlc2MAAAGEAAAAbHd0cHQAAAHwAAAAFGJrcHQAAAIEAAAAFHJYWVoAAAIY 221 | AAAAFGdYWVoAAAIsAAAAFGJYWVoAAAJAAAAAFGRtbmQAAAJUAAAAcGRtZGQAAALEAAAA 222 | iHZ1ZWQAAANMAAAAhnZpZXcAAAPUAAAAJGx1bWkAAAP4AAAAFG1lYXMAAAQMAAAAJHRl 223 | Y2gAAAQwAAAADHJUUkMAAAQ8AAAIDGdUUkMAAAQ8AAAIDGJUUkMAAAQ8AAAIDHRleHQA 224 | AAAAQ29weXJpZ2h0IChjKSAxOTk4IEhld2xldHQtUGFja2FyZCBDb21wYW55AABkZXNj 225 | AAAAAAAAABJzUkdCIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAAEnNSR0IgSUVDNjE5NjYt 226 | Mi4xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 227 | AABYWVogAAAAAAAA81EAAQAAAAEWzFhZWiAAAAAAAAAAAAAAAAAAAAAAWFlaIAAAAAAA 228 | AG+iAAA49QAAA5BYWVogAAAAAAAAYpkAALeFAAAY2lhZWiAAAAAAAAAkoAAAD4QAALbP 229 | ZGVzYwAAAAAAAAAWSUVDIGh0dHA6Ly93d3cuaWVjLmNoAAAAAAAAAAAAAAAWSUVDIGh0 230 | dHA6Ly93d3cuaWVjLmNoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 231 | AAAAAAAAAAAAAGRlc2MAAAAAAAAALklFQyA2MTk2Ni0yLjEgRGVmYXVsdCBSR0IgY29s 232 | b3VyIHNwYWNlIC0gc1JHQgAAAAAAAAAAAAAALklFQyA2MTk2Ni0yLjEgRGVmYXVsdCBS 233 | R0IgY29sb3VyIHNwYWNlIC0gc1JHQgAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAA 234 | AAAAACxSZWZlcmVuY2UgVmlld2luZyBDb25kaXRpb24gaW4gSUVDNjE5NjYtMi4xAAAA 235 | AAAAAAAAAAAsUmVmZXJlbmNlIFZpZXdpbmcgQ29uZGl0aW9uIGluIElFQzYxOTY2LTIu 236 | MQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdmlldwAAAAAAE6T+ABRfLgAQzxQAA+3M 237 | AAQTCwADXJ4AAAABWFlaIAAAAAAATAlWAFAAAABXH+dtZWFzAAAAAAAAAAEAAAAAAAAA 238 | AAAAAAAAAAAAAAACjwAAAAJzaWcgAAAAAENSVCBjdXJ2AAAAAAAABAAAAAAFAAoADwAU 239 | ABkAHgAjACgALQAyADcAOwBAAEUASgBPAFQAWQBeAGMAaABtAHIAdwB8AIEAhgCLAJAA 240 | lQCaAJ8ApACpAK4AsgC3ALwAwQDGAMsA0ADVANsA4ADlAOsA8AD2APsBAQEHAQ0BEwEZ 241 | AR8BJQErATIBOAE+AUUBTAFSAVkBYAFnAW4BdQF8AYMBiwGSAZoBoQGpAbEBuQHBAckB 242 | 0QHZAeEB6QHyAfoCAwIMAhQCHQImAi8COAJBAksCVAJdAmcCcQJ6AoQCjgKYAqICrAK2 243 | AsECywLVAuAC6wL1AwADCwMWAyEDLQM4A0MDTwNaA2YDcgN+A4oDlgOiA64DugPHA9MD 244 | 4APsA/kEBgQTBCAELQQ7BEgEVQRjBHEEfgSMBJoEqAS2BMQE0wThBPAE/gUNBRwFKwU6 245 | BUkFWAVnBXcFhgWWBaYFtQXFBdUF5QX2BgYGFgYnBjcGSAZZBmoGewaMBp0GrwbABtEG 246 | 4wb1BwcHGQcrBz0HTwdhB3QHhgeZB6wHvwfSB+UH+AgLCB8IMghGCFoIbgiCCJYIqgi+ 247 | CNII5wj7CRAJJQk6CU8JZAl5CY8JpAm6Cc8J5Qn7ChEKJwo9ClQKagqBCpgKrgrFCtwK 248 | 8wsLCyILOQtRC2kLgAuYC7ALyAvhC/kMEgwqDEMMXAx1DI4MpwzADNkM8w0NDSYNQA1a 249 | DXQNjg2pDcMN3g34DhMOLg5JDmQOfw6bDrYO0g7uDwkPJQ9BD14Peg+WD7MPzw/sEAkQ 250 | JhBDEGEQfhCbELkQ1xD1ERMRMRFPEW0RjBGqEckR6BIHEiYSRRJkEoQSoxLDEuMTAxMj 251 | E0MTYxODE6QTxRPlFAYUJxRJFGoUixStFM4U8BUSFTQVVhV4FZsVvRXgFgMWJhZJFmwW 252 | jxayFtYW+hcdF0EXZReJF64X0hf3GBsYQBhlGIoYrxjVGPoZIBlFGWsZkRm3Gd0aBBoq 253 | GlEadxqeGsUa7BsUGzsbYxuKG7Ib2hwCHCocUhx7HKMczBz1HR4dRx1wHZkdwx3sHhYe 254 | QB5qHpQevh7pHxMfPh9pH5Qfvx/qIBUgQSBsIJggxCDwIRwhSCF1IaEhziH7IiciVSKC 255 | Iq8i3SMKIzgjZiOUI8Ij8CQfJE0kfCSrJNolCSU4JWgllyXHJfcmJyZXJocmtyboJxgn 256 | SSd6J6sn3CgNKD8ocSiiKNQpBik4KWspnSnQKgIqNSpoKpsqzysCKzYraSudK9EsBSw5 257 | LG4soizXLQwtQS12Last4S4WLkwugi63Lu4vJC9aL5Evxy/+MDUwbDCkMNsxEjFKMYIx 258 | ujHyMioyYzKbMtQzDTNGM38zuDPxNCs0ZTSeNNg1EzVNNYc1wjX9Njc2cjauNuk3JDdg 259 | N5w31zgUOFA4jDjIOQU5Qjl/Obw5+To2OnQ6sjrvOy07azuqO+g8JzxlPKQ84z0iPWE9 260 | oT3gPiA+YD6gPuA/IT9hP6I/4kAjQGRApkDnQSlBakGsQe5CMEJyQrVC90M6Q31DwEQD 261 | REdEikTORRJFVUWaRd5GIkZnRqtG8Ec1R3tHwEgFSEtIkUjXSR1JY0mpSfBKN0p9SsRL 262 | DEtTS5pL4kwqTHJMuk0CTUpNk03cTiVObk63TwBPSU+TT91QJ1BxULtRBlFQUZtR5lIx 263 | UnxSx1MTU19TqlP2VEJUj1TbVShVdVXCVg9WXFapVvdXRFeSV+BYL1h9WMtZGllpWbha 264 | B1pWWqZa9VtFW5Vb5Vw1XIZc1l0nXXhdyV4aXmxevV8PX2Ffs2AFYFdgqmD8YU9homH1 265 | YklinGLwY0Njl2PrZEBklGTpZT1lkmXnZj1mkmboZz1nk2fpaD9olmjsaUNpmmnxakhq 266 | n2r3a09rp2v/bFdsr20IbWBtuW4SbmtuxG8eb3hv0XArcIZw4HE6cZVx8HJLcqZzAXNd 267 | c7h0FHRwdMx1KHWFdeF2Pnabdvh3VnezeBF4bnjMeSp5iXnnekZ6pXsEe2N7wnwhfIF8 268 | 4X1BfaF+AX5ifsJ/I3+Ef+WAR4CogQqBa4HNgjCCkoL0g1eDuoQdhICE44VHhauGDoZy 269 | hteHO4efiASIaYjOiTOJmYn+imSKyoswi5aL/IxjjMqNMY2Yjf+OZo7OjzaPnpAGkG6Q 270 | 1pE/kaiSEZJ6kuOTTZO2lCCUipT0lV+VyZY0lp+XCpd1l+CYTJi4mSSZkJn8mmia1ZtC 271 | m6+cHJyJnPedZJ3SnkCerp8dn4uf+qBpoNihR6G2oiailqMGo3aj5qRWpMelOKWpphqm 272 | i6b9p26n4KhSqMSpN6mpqhyqj6sCq3Wr6axcrNCtRK24ri2uoa8Wr4uwALB1sOqxYLHW 273 | skuywrM4s660JbSctRO1irYBtnm28Ldot+C4WbjRuUq5wro7urW7LrunvCG8m70VvY++ 274 | Cr6Evv+/er/1wHDA7MFnwePCX8Lbw1jD1MRRxM7FS8XIxkbGw8dBx7/IPci8yTrJuco4 275 | yrfLNsu2zDXMtc01zbXONs62zzfPuNA50LrRPNG+0j/SwdNE08bUSdTL1U7V0dZV1tjX 276 | XNfg2GTY6Nls2fHadtr724DcBdyK3RDdlt4c3qLfKd+v4DbgveFE4cziU+Lb42Pj6+Rz 277 | 5PzlhOYN5pbnH+ep6DLovOlG6dDqW+rl63Dr++yG7RHtnO4o7rTvQO/M8Fjw5fFy8f/y 278 | jPMZ86f0NPTC9VD13vZt9vv3ivgZ+Kj5OPnH+lf65/t3/Af8mP0p/br+S/7c/23//4AE 279 | 0h4fICFaJGNsYXNzbmFtZVgkY2xhc3Nlc11OU011dGFibGVEYXRhoyAiI1ZOU0RhdGFY 280 | TlNPYmplY3TSHh8lJlxOU0NvbG9yU3BhY2WiJyNcTlNDb2xvclNwYWNl0h4fKSpXTlND 281 | b2xvcqIpI18QD05TS2V5ZWRBcmNoaXZlctEtLlRyb290gAEACAARABoAIwAtADIANwA/ 282 | AEUAUABdAGMAcACFAIwAtwDgAOIA5ADmAO0A8gD4APoA/AD+AQMBCw1XDVkNXg1pDXIN 283 | gA2EDYsNlA2ZDaYNqQ22DbsNww3GDdgN2w3gAAAAAAAAAgEAAAAAAAAALwAAAAAAAAAA 284 | AAAAAAAADeI= 285 | 286 | TextColor 287 | 288 | YnBsaXN0MDDUAQIDBAUGFRZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS 289 | AAGGoKMHCA9VJG51bGzTCQoLDA0OVU5TUkdCXE5TQ29sb3JTcGFjZVYkY2xhc3NPECYw 290 | LjgzOTIxNTY5NTkgMC44NzA1ODgyNDMgMC45MjE1Njg2MzIxABABgALSEBESE1okY2xh 291 | c3NuYW1lWCRjbGFzc2VzV05TQ29sb3KiEhRYTlNPYmplY3RfEA9OU0tleWVkQXJjaGl2 292 | ZXLRFxhUcm9vdIABCBEaIy0yNztBSE5bYouNj5SfqLCzvM7R1gAAAAAAAAEBAAAAAAAA 293 | ABkAAAAAAAAAAAAAAAAAAADY 294 | 295 | UseBoldFonts 296 | 297 | VisualBell 298 | 299 | columnCount 300 | 90 301 | name 302 | sloria-night-owl 303 | noWarnProcesses 304 | 305 | 306 | ProcessName 307 | screen 308 | 309 | 310 | rowCount 311 | 50 312 | type 313 | Window Settings 314 | warnOnShellCloseAction 315 | 0 316 | 317 | 318 | -------------------------------------------------------------------------------- /remote_env.yml: -------------------------------------------------------------------------------- 1 | - name: Set up environment on remote machines 2 | hosts: remote 3 | roles: 4 | # Tag each role so that we can select individual roles to run with ansible-playbook --tags 5 | - { role: git, tags: ["git"] } 6 | - { role: package_manager, tags: ["package_manager", "bootstrap"] } 7 | - { role: zsh, tags: ["zsh", "bootstrap"] } 8 | - { role: python, tags: ["python"] } 9 | - { role: mise, tags: ["mise"] } 10 | - { role: rust, tags: ["rust"] } 11 | - { role: vim, tags: ["vim"] } 12 | - { role: rg, tags: ["rg"] } 13 | - { role: eza, tags: ["eza"] } 14 | - { role: gsed, tags: ["gsed"] } 15 | - { role: bat, tags: ["bat"] } 16 | - { role: fzf, tags: ["fzf"] } 17 | - { role: ollama, tags: ["ollama"] } 18 | - { role: beszel-agent, tags: ["beszel-agent"] } 19 | - { role: adguard, tags: ["adguard"] } 20 | - { role: lctl, tags: ["lctl"], when: ansible_os_family == "Darwin" } 21 | - { role: macos, tags: ["macos"], when: ansible_os_family == "Darwin" } 22 | -------------------------------------------------------------------------------- /roles/adguard/README.md: -------------------------------------------------------------------------------- 1 | # AdGuard Home 2 | 3 | Installs AdGuard Home. 4 | 5 | ## initial setup 6 | 7 | After installing navigate to :3000 and go through the initial wizard. 8 | 9 | By default, AdGuard uses port 80 for the web interface, which interferes will interfere with Caddy. 10 | Edit AdGuardHome.yaml to change the default port to serve the web interface on. 11 | 12 | ``` 13 | sudo vim /Applications/AdGuardHome/AdGuardHome.yaml 14 | ``` 15 | 16 | Then change `http.address` to use a different port. 17 | 18 | ```yaml 19 | http: 20 | address: 0.0.0.0:4321 21 | ``` 22 | 23 | Then restart the server 24 | 25 | ``` 26 | sudo /Applications/AdGuardHome/AdGuardHome -s restart 27 | ``` 28 | -------------------------------------------------------------------------------- /roles/adguard/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: Install AdGuard Home 2 | shell: curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | bash -s -- -v 3 | args: 4 | creates: /Applications/AdGuardHome/AdGuardHome 5 | -------------------------------------------------------------------------------- /roles/ansible/aliases.zsh: -------------------------------------------------------------------------------- 1 | alias av="EDITOR=vim ansible-vault" 2 | alias ave="EDITOR=vim ansible-vault edit" 3 | -------------------------------------------------------------------------------- /roles/bat/aliases.zsh: -------------------------------------------------------------------------------- 1 | alias cat=bat 2 | -------------------------------------------------------------------------------- /roles/bat/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | bat_release_url: https://github.com/sharkdp/bat/releases/download 3 | bat_release_version: v0.10.0 4 | bat_version: "0.10.0" 5 | bat_dpkg_file: bat_0.10.0_amd64.deb 6 | -------------------------------------------------------------------------------- /roles/bat/tasks/debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Check if bat is installed 3 | command: dpkg-query -W bat 4 | register: bat_check_deb 5 | failed_when: bat_check_deb.rc > 1 6 | changed_when: bat_check_deb.rc == 1 7 | 8 | - name: Install bat with a .deb file 9 | apt: 10 | deb: "{{ bat_release_url }}/{{ bat_release_version }}/{{ bat_dpkg_file }}" 11 | become: yes 12 | become_user: root 13 | when: bat_check_deb.rc == 1 14 | 15 | - name: Check if bat is up to date 16 | shell: bat --version | awk NR==1'{print $2}' 17 | register: bat_check_ver 18 | when: bat_check_deb.rc == 1 19 | 20 | - set_fact: bat_ver="{{ bat_check_ver }}" 21 | - set_fact: bat_installed_ver="{{ bat_version }}" 22 | 23 | - name: Update bat 24 | apt: 25 | deb: "{{ bat_release_url }}/{{ bat_release_version }}/{{ bat_dpkg_file }}" 26 | become: yes 27 | become_user: root 28 | when: bat_ver != bat_installed_ver 29 | -------------------------------------------------------------------------------- /roles/bat/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - import_tasks: debian.yml 2 | when: ansible_os_family == "Debian" 3 | 4 | - name: Install bat with Homebrew 5 | homebrew: name=bat state=present 6 | when: ansible_os_family == "Darwin" 7 | -------------------------------------------------------------------------------- /roles/beszel-agent/README.md: -------------------------------------------------------------------------------- 1 | # Beszel 2 | 3 | I use [Beszel](https://beszel.dev/) for lightweight monitoring of my mac mini server. It shows stats on both the host and the Docker containers. 4 | 5 | The UI is run using docker/docker compose (configured in a different repo). This role installs the Beszel agent on the mac mini host. 6 | 7 | Before running it, the Beszel SSH key needs to be set. 8 | 9 | In the Beszel UI: Add System > Name: Mac Mini, Host/IP: host.docker.internal, Port: 45876 (leave as default), Public Key: Copy the key. Add System. 10 | 11 | Paste the key into `~/.localrc` 12 | 13 | ``` 14 | export BESZEL_AGENT_KEY="" 15 | ``` 16 | 17 | Then run the role using the `dot-update-remote` command: 18 | 19 | ``` 20 | reload! 21 | dot-update-remote beszel-agent 22 | ``` 23 | -------------------------------------------------------------------------------- /roles/beszel-agent/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create config and cache directories for beszel 3 | file: 4 | path: "{{ item }}" 5 | state: directory 6 | loop: 7 | - "{{ '~/.config/beszel' | expanduser }}" 8 | - "{{ '~/.cache/beszel' | expanduser }}" 9 | 10 | - name: Create beszel agent environment file 11 | template: 12 | src: "beszel-agent.env.j2" 13 | dest: "{{ '~/.config/beszel/beszel-agent.env' | expanduser }}" 14 | mode: '0644' 15 | 16 | - name: Add beszel tap to Homebrew 17 | command: brew tap henrygd/beszel 18 | changed_when: false 19 | 20 | - name: Install beszel-agent using Homebrew 21 | homebrew: 22 | name: beszel-agent 23 | state: present 24 | 25 | - name: Create com.sloria.beszel-agent.plist in ~/Library/LaunchAgents 26 | template: 27 | src: "com.sloria.beszel-agent.plist.j2" 28 | dest: "{{ '~/Library/LaunchAgents/com.sloria.beszel-agent.plist' | expanduser }}" 29 | 30 | - name: Load beszel-agent service with launchctl 31 | command: "launchctl load {{ '~/Library/LaunchAgents/com.sloria.beszel-agent.plist' | expanduser }}" 32 | changed_when: false 33 | -------------------------------------------------------------------------------- /roles/beszel-agent/templates/beszel-agent.env.j2: -------------------------------------------------------------------------------- 1 | KEY="{{ lookup('env', 'BESZEL_AGENT_KEY') }}" 2 | SENSORS= 3 | -------------------------------------------------------------------------------- /roles/beszel-agent/templates/com.sloria.beszel-agent.plist.j2: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | com.sloria.beszel-agent 7 | ProgramArguments 8 | 9 | /opt/homebrew/bin/beszel-agent-launcher 10 | 11 | 12 | RunAtLoad 13 | 14 | 15 | KeepAlive 16 | 17 | SuccessfulExit 18 | 19 | Crashed 20 | 21 | 22 | ThrottleInterval 23 | 60 24 | 25 | 26 | 27 | Nice 28 | 10 29 | 30 | 31 | ProcessType 32 | Background 33 | 34 | StandardErrorPath 35 | /opt/homebrew/var/log/beszel-agent.log 36 | StandardOutPath 37 | /opt/homebrew/var/log/beszel-agent.log 38 | 39 | 40 | -------------------------------------------------------------------------------- /roles/docker/_docker: -------------------------------------------------------------------------------- 1 | #compdef docker 2 | # 3 | # zsh completion for docker (http://docker.com) 4 | # 5 | # version: 0.3.0 6 | # github: https://github.com/felixr/docker-zsh-completion 7 | # 8 | # contributors: 9 | # - Felix Riedel 10 | # - Steve Durrheimer 11 | # - Vincent Bernat 12 | # 13 | # license: 14 | # 15 | # Copyright (c) 2013, Felix Riedel 16 | # All rights reserved. 17 | # 18 | # Redistribution and use in source and binary forms, with or without 19 | # modification, are permitted provided that the following conditions are met: 20 | # * Redistributions of source code must retain the above copyright 21 | # notice, this list of conditions and the following disclaimer. 22 | # * Redistributions in binary form must reproduce the above copyright 23 | # notice, this list of conditions and the following disclaimer in the 24 | # documentation and/or other materials provided with the distribution. 25 | # * Neither the name of the nor the 26 | # names of its contributors may be used to endorse or promote products 27 | # derived from this software without specific prior written permission. 28 | # 29 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 30 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 31 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 32 | # DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 33 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 34 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 35 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 36 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | # 40 | 41 | # Short-option stacking can be disabled with: 42 | # zstyle ':completion:*:*:docker:*' option-stacking no 43 | # zstyle ':completion:*:*:docker-*:*' option-stacking no 44 | __docker_arguments() { 45 | if zstyle -T ":completion:${curcontext}:" option-stacking; then 46 | print -- -s 47 | fi 48 | } 49 | 50 | __docker_get_containers() { 51 | [[ $PREFIX = -* ]] && return 1 52 | integer ret=1 53 | local kind type line s 54 | declare -a running stopped lines args names 55 | 56 | kind=$1; shift 57 | type=$1; shift 58 | [[ $kind = (stopped|all) ]] && args=($args -a) 59 | 60 | lines=(${(f)"$(_call_program commands docker $docker_options ps --format 'table' --no-trunc $args)"}) 61 | 62 | # Parse header line to find columns 63 | local i=1 j=1 k header=${lines[1]} 64 | declare -A begin end 65 | while (( j < ${#header} - 1 )); do 66 | i=$(( j + ${${header[$j,-1]}[(i)[^ ]]} - 1 )) 67 | j=$(( i + ${${header[$i,-1]}[(i) ]} - 1 )) 68 | k=$(( j + ${${header[$j,-1]}[(i)[^ ]]} - 2 )) 69 | begin[${header[$i,$((j-1))]}]=$i 70 | end[${header[$i,$((j-1))]}]=$k 71 | done 72 | end[${header[$i,$((j-1))]}]=-1 # Last column, should go to the end of the line 73 | lines=(${lines[2,-1]}) 74 | 75 | # Container ID 76 | if [[ $type = (ids|all) ]]; then 77 | for line in $lines; do 78 | s="${${line[${begin[CONTAINER ID]},${end[CONTAINER ID]}]%% ##}[0,12]}" 79 | s="$s:${(l:15:: :::)${${line[${begin[CREATED]},${end[CREATED]}]/ ago/}%% ##}}" 80 | s="$s, ${${${line[${begin[IMAGE]},${end[IMAGE]}]}/:/\\:}%% ##}" 81 | if [[ ${line[${begin[STATUS]},${end[STATUS]}]} = Exit* ]]; then 82 | stopped=($stopped $s) 83 | else 84 | running=($running $s) 85 | fi 86 | done 87 | fi 88 | 89 | # Names: we only display the one without slash. All other names 90 | # are generated and may clutter the completion. However, with 91 | # Swarm, all names may be prefixed by the swarm node name. 92 | if [[ $type = (names|all) ]]; then 93 | for line in $lines; do 94 | names=(${(ps:,:)${${line[${begin[NAMES]},${end[NAMES]}]}%% *}}) 95 | # First step: find a common prefix and strip it (swarm node case) 96 | (( ${#${(u)names%%/*}} == 1 )) && names=${names#${names[1]%%/*}/} 97 | # Second step: only keep the first name without a / 98 | s=${${names:#*/*}[1]} 99 | # If no name, well give up. 100 | (( $#s != 0 )) || continue 101 | s="$s:${(l:15:: :::)${${line[${begin[CREATED]},${end[CREATED]}]/ ago/}%% ##}}" 102 | s="$s, ${${${line[${begin[IMAGE]},${end[IMAGE]}]}/:/\\:}%% ##}" 103 | if [[ ${line[${begin[STATUS]},${end[STATUS]}]} = Exit* ]]; then 104 | stopped=($stopped $s) 105 | else 106 | running=($running $s) 107 | fi 108 | done 109 | fi 110 | 111 | [[ $kind = (running|all) ]] && _describe -t containers-running "running containers" running "$@" && ret=0 112 | [[ $kind = (stopped|all) ]] && _describe -t containers-stopped "stopped containers" stopped "$@" && ret=0 113 | return ret 114 | } 115 | 116 | __docker_stoppedcontainers() { 117 | [[ $PREFIX = -* ]] && return 1 118 | __docker_get_containers stopped all "$@" 119 | } 120 | 121 | __docker_runningcontainers() { 122 | [[ $PREFIX = -* ]] && return 1 123 | __docker_get_containers running all "$@" 124 | } 125 | 126 | __docker_containers() { 127 | [[ $PREFIX = -* ]] && return 1 128 | __docker_get_containers all all "$@" 129 | } 130 | 131 | __docker_containers_ids() { 132 | [[ $PREFIX = -* ]] && return 1 133 | __docker_get_containers all ids "$@" 134 | } 135 | 136 | __docker_containers_names() { 137 | [[ $PREFIX = -* ]] && return 1 138 | __docker_get_containers all names "$@" 139 | } 140 | 141 | __docker_plugins() { 142 | [[ $PREFIX = -* ]] && return 1 143 | integer ret=1 144 | emulate -L zsh 145 | setopt extendedglob 146 | local -a plugins 147 | plugins=(${(ps: :)${(M)${(f)${${"$(_call_program commands docker $docker_options info)"##*$'\n'Plugins:}%%$'\n'^ *}}:# $1: *}## $1: }) 148 | _describe -t plugins "$1 plugins" plugins && ret=0 149 | return ret 150 | } 151 | 152 | __docker_images() { 153 | [[ $PREFIX = -* ]] && return 1 154 | integer ret=1 155 | declare -a images 156 | images=(${${${(f)"$(_call_program commands docker $docker_options images)"}[2,-1]}/(#b)([^ ]##) ##([^ ]##) ##([^ ]##)*/${match[3]}:${(r:15:: :::)match[2]} in ${match[1]}}) 157 | _describe -t docker-images "images" images && ret=0 158 | __docker_repositories_with_tags && ret=0 159 | return ret 160 | } 161 | 162 | __docker_repositories() { 163 | [[ $PREFIX = -* ]] && return 1 164 | declare -a repos 165 | repos=(${${${(f)"$(_call_program commands docker $docker_options images)"}%% *}[2,-1]}) 166 | repos=(${repos#}) 167 | _describe -t docker-repos "repositories" repos 168 | } 169 | 170 | __docker_repositories_with_tags() { 171 | [[ $PREFIX = -* ]] && return 1 172 | integer ret=1 173 | declare -a repos onlyrepos matched 174 | declare m 175 | repos=(${${${${(f)"$(_call_program commands docker $docker_options images)"}[2,-1]}/ ##/:::}%% *}) 176 | repos=(${${repos%:::}#}) 177 | # Check if we have a prefix-match for the current prefix. 178 | onlyrepos=(${repos%::*}) 179 | for m in $onlyrepos; do 180 | [[ ${PREFIX##${~~m}} != ${PREFIX} ]] && { 181 | # Yes, complete with tags 182 | repos=(${${repos/:::/:}/:/\\:}) 183 | _describe -t docker-repos-with-tags "repositories with tags" repos && ret=0 184 | return ret 185 | } 186 | done 187 | # No, only complete repositories 188 | onlyrepos=(${${repos%:::*}/:/\\:}) 189 | _describe -t docker-repos "repositories" onlyrepos -qS : && ret=0 190 | 191 | return ret 192 | } 193 | 194 | __docker_search() { 195 | [[ $PREFIX = -* ]] && return 1 196 | local cache_policy 197 | zstyle -s ":completion:${curcontext}:" cache-policy cache_policy 198 | if [[ -z "$cache_policy" ]]; then 199 | zstyle ":completion:${curcontext}:" cache-policy __docker_caching_policy 200 | fi 201 | 202 | local searchterm cachename 203 | searchterm="${words[$CURRENT]%/}" 204 | cachename=_docker-search-$searchterm 205 | 206 | local expl 207 | local -a result 208 | if ( [[ ${(P)+cachename} -eq 0 ]] || _cache_invalid ${cachename#_} ) \ 209 | && ! _retrieve_cache ${cachename#_}; then 210 | _message "Searching for ${searchterm}..." 211 | result=(${${${(f)"$(_call_program commands docker $docker_options search $searchterm)"}%% *}[2,-1]}) 212 | _store_cache ${cachename#_} result 213 | fi 214 | _wanted dockersearch expl 'available images' compadd -a result 215 | } 216 | 217 | __docker_get_log_options() { 218 | [[ $PREFIX = -* ]] && return 1 219 | 220 | integer ret=1 221 | local log_driver=${opt_args[--log-driver]:-"all"} 222 | local -a awslogs_options fluentd_options gelf_options journald_options json_file_options syslog_options splunk_options 223 | 224 | awslogs_options=("awslogs-region" "awslogs-group" "awslogs-stream") 225 | fluentd_options=("env" "fluentd-address" "fluentd-async-connect" "fluentd-buffer-limit" "fluentd-retry-wait" "fluentd-max-retries" "labels" "tag") 226 | gcplogs_options=("env" "gcp-log-cmd" "gcp-project" "labels") 227 | gelf_options=("env" "gelf-address" "gelf-compression-level" "gelf-compression-type" "labels" "tag") 228 | journald_options=("env" "labels" "tag") 229 | json_file_options=("env" "labels" "max-file" "max-size") 230 | syslog_options=("syslog-address" "syslog-format" "syslog-tls-ca-cert" "syslog-tls-cert" "syslog-tls-key" "syslog-tls-skip-verify" "syslog-facility" "tag") 231 | splunk_options=("env" "labels" "splunk-caname" "splunk-capath" "splunk-index" "splunk-insecureskipverify" "splunk-source" "splunk-sourcetype" "splunk-token" "splunk-url" "tag") 232 | 233 | [[ $log_driver = (awslogs|all) ]] && _describe -t awslogs-options "awslogs options" awslogs_options "$@" && ret=0 234 | [[ $log_driver = (fluentd|all) ]] && _describe -t fluentd-options "fluentd options" fluentd_options "$@" && ret=0 235 | [[ $log_driver = (gcplogs|all) ]] && _describe -t gcplogs-options "gcplogs options" gcplogs_options "$@" && ret=0 236 | [[ $log_driver = (gelf|all) ]] && _describe -t gelf-options "gelf options" gelf_options "$@" && ret=0 237 | [[ $log_driver = (journald|all) ]] && _describe -t journald-options "journald options" journald_options "$@" && ret=0 238 | [[ $log_driver = (json-file|all) ]] && _describe -t json-file-options "json-file options" json_file_options "$@" && ret=0 239 | [[ $log_driver = (syslog|all) ]] && _describe -t syslog-options "syslog options" syslog_options "$@" && ret=0 240 | [[ $log_driver = (splunk|all) ]] && _describe -t splunk-options "splunk options" splunk_options "$@" && ret=0 241 | 242 | return ret 243 | } 244 | 245 | __docker_log_options() { 246 | [[ $PREFIX = -* ]] && return 1 247 | integer ret=1 248 | 249 | if compset -P '*='; then 250 | case "${${words[-1]%=*}#*=}" in 251 | (syslog-format) 252 | syslog_format_opts=('rfc3164' 'rfc5424' 'rfc5424micro') 253 | _describe -t syslog-format-opts "Syslog format Options" syslog_format_opts && ret=0 254 | ;; 255 | *) 256 | _message 'value' && ret=0 257 | ;; 258 | esac 259 | else 260 | __docker_get_log_options -qS "=" && ret=0 261 | fi 262 | 263 | return ret 264 | } 265 | 266 | __docker_complete_detach_keys() { 267 | [[ $PREFIX = -* ]] && return 1 268 | integer ret=1 269 | 270 | compset -P "*," 271 | keys=(${:-{a-z}}) 272 | ctrl_keys=(${:-ctrl-{{a-z},{@,'[','\\','^',']',_}}}) 273 | _describe -t detach_keys "[a-z]" keys -qS "," && ret=0 274 | _describe -t detach_keys-ctrl "'ctrl-' + 'a-z @ [ \\\\ ] ^ _'" ctrl_keys -qS "," && ret=0 275 | } 276 | 277 | __docker_complete_pid() { 278 | [[ $PREFIX = -* ]] && return 1 279 | integer ret=1 280 | local -a opts vopts 281 | 282 | opts=('host') 283 | vopts=('container') 284 | 285 | if compset -P '*:'; then 286 | case "${${words[-1]%:*}#*=}" in 287 | (container) 288 | __docker_runningcontainers && ret=0 289 | ;; 290 | *) 291 | _message 'value' && ret=0 292 | ;; 293 | esac 294 | else 295 | _describe -t pid-value-opts "PID Options with value" vopts -qS ":" && ret=0 296 | _describe -t pid-opts "PID Options" opts && ret=0 297 | fi 298 | 299 | return ret 300 | } 301 | 302 | __docker_complete_ps_filters() { 303 | [[ $PREFIX = -* ]] && return 1 304 | integer ret=1 305 | 306 | if compset -P '*='; then 307 | case "${${words[-1]%=*}#*=}" in 308 | (ancestor) 309 | __docker_images && ret=0 310 | ;; 311 | (before|since) 312 | __docker_containers && ret=0 313 | ;; 314 | (id) 315 | __docker_containers_ids && ret=0 316 | ;; 317 | (name) 318 | __docker_containers_names && ret=0 319 | ;; 320 | (network) 321 | __docker_networks && ret=0 322 | ;; 323 | (status) 324 | status_opts=('created' 'dead' 'exited' 'paused' 'restarting' 'running') 325 | _describe -t status-filter-opts "Status Filter Options" status_opts && ret=0 326 | ;; 327 | (volume) 328 | __docker_volumes && ret=0 329 | ;; 330 | *) 331 | _message 'value' && ret=0 332 | ;; 333 | esac 334 | else 335 | opts=('ancestor' 'before' 'exited' 'id' 'label' 'name' 'network' 'since' 'status' 'volume') 336 | _describe -t filter-opts "Filter Options" opts -qS "=" && ret=0 337 | fi 338 | 339 | return ret 340 | } 341 | 342 | __docker_complete_search_filters() { 343 | [[ $PREFIX = -* ]] && return 1 344 | integer ret=1 345 | declare -a boolean_opts opts 346 | 347 | boolean_opts=('true' 'false') 348 | opts=('is-automated' 'is-official' 'stars') 349 | 350 | if compset -P '*='; then 351 | case "${${words[-1]%=*}#*=}" in 352 | (is-automated|is-official) 353 | _describe -t boolean-filter-opts "filter options" boolean_opts && ret=0 354 | ;; 355 | *) 356 | _message 'value' && ret=0 357 | ;; 358 | esac 359 | else 360 | _describe -t filter-opts "filter options" opts -qS "=" && ret=0 361 | fi 362 | 363 | return ret 364 | } 365 | 366 | __docker_complete_images_filters() { 367 | [[ $PREFIX = -* ]] && return 1 368 | integer ret=1 369 | declare -a boolean_opts opts 370 | 371 | boolean_opts=('true' 'false') 372 | opts=('before' 'dangling' 'label' 'since') 373 | 374 | if compset -P '*='; then 375 | case "${${words[-1]%=*}#*=}" in 376 | (before|since) 377 | __docker_images && ret=0 378 | ;; 379 | (dangling) 380 | _describe -t boolean-filter-opts "filter options" boolean_opts && ret=0 381 | ;; 382 | *) 383 | _message 'value' && ret=0 384 | ;; 385 | esac 386 | else 387 | _describe -t filter-opts "Filter Options" opts -qS "=" && ret=0 388 | fi 389 | 390 | return ret 391 | } 392 | 393 | __docker_complete_events_filter() { 394 | [[ $PREFIX = -* ]] && return 1 395 | integer ret=1 396 | declare -a opts 397 | 398 | opts=('container' 'daemon' 'event' 'image' 'label' 'network' 'type' 'volume') 399 | 400 | if compset -P '*='; then 401 | case "${${words[-1]%=*}#*=}" in 402 | (container) 403 | __docker_containers && ret=0 404 | ;; 405 | (daemon) 406 | emulate -L zsh 407 | setopt extendedglob 408 | local -a daemon_opts 409 | daemon_opts=( 410 | ${(f)${${"$(_call_program commands docker $docker_options info)"##*$'\n'Name: }%%$'\n'^ *}} 411 | ${${(f)${${"$(_call_program commands docker $docker_options info)"##*$'\n'ID: }%%$'\n'^ *}}//:/\\:} 412 | ) 413 | _describe -t daemon-filter-opts "daemon filter options" daemon_opts && ret=0 414 | ;; 415 | (event) 416 | local -a event_opts 417 | event_opts=('attach' 'commit' 'connect' 'copy' 'create' 'delete' 'destroy' 'detach' 'die' 'disconnect' 'exec_create' 'exec_detach' 418 | 'exec_start' 'export' 'import' 'kill' 'mount' 'oom' 'pause' 'pull' 'push' 'reload' 'rename' 'resize' 'restart' 'start' 'stop' 'tag' 419 | 'top' 'unmount' 'unpause' 'untag' 'update') 420 | _describe -t event-filter-opts "event filter options" event_opts && ret=0 421 | ;; 422 | (image) 423 | __docker_images && ret=0 424 | ;; 425 | (network) 426 | __docker_networks && ret=0 427 | ;; 428 | (type) 429 | local -a type_opts 430 | type_opts=('container' 'daemon' 'image' 'network' 'volume') 431 | _describe -t type-filter-opts "type filter options" type_opts && ret=0 432 | ;; 433 | (volume) 434 | __docker_volumes && ret=0 435 | ;; 436 | *) 437 | _message 'value' && ret=0 438 | ;; 439 | esac 440 | else 441 | _describe -t filter-opts "filter options" opts -qS "=" && ret=0 442 | fi 443 | 444 | return ret 445 | } 446 | 447 | __docker_network_complete_ls_filters() { 448 | [[ $PREFIX = -* ]] && return 1 449 | integer ret=1 450 | 451 | if compset -P '*='; then 452 | case "${${words[-1]%=*}#*=}" in 453 | (driver) 454 | __docker_plugins Network && ret=0 455 | ;; 456 | (id) 457 | __docker_networks_ids && ret=0 458 | ;; 459 | (name) 460 | __docker_networks_names && ret=0 461 | ;; 462 | (type) 463 | type_opts=('builtin' 'custom') 464 | _describe -t type-filter-opts "Type Filter Options" type_opts && ret=0 465 | ;; 466 | *) 467 | _message 'value' && ret=0 468 | ;; 469 | esac 470 | else 471 | opts=('driver' 'id' 'label' 'name' 'type') 472 | _describe -t filter-opts "Filter Options" opts -qS "=" && ret=0 473 | fi 474 | 475 | return ret 476 | } 477 | 478 | __docker_get_networks() { 479 | [[ $PREFIX = -* ]] && return 1 480 | integer ret=1 481 | local line s 482 | declare -a lines networks 483 | 484 | type=$1; shift 485 | 486 | lines=(${(f)"$(_call_program commands docker $docker_options network ls)"}) 487 | 488 | # Parse header line to find columns 489 | local i=1 j=1 k header=${lines[1]} 490 | declare -A begin end 491 | while (( j < ${#header} - 1 )); do 492 | i=$(( j + ${${header[$j,-1]}[(i)[^ ]]} - 1 )) 493 | j=$(( i + ${${header[$i,-1]}[(i) ]} - 1 )) 494 | k=$(( j + ${${header[$j,-1]}[(i)[^ ]]} - 2 )) 495 | begin[${header[$i,$((j-1))]}]=$i 496 | end[${header[$i,$((j-1))]}]=$k 497 | done 498 | end[${header[$i,$((j-1))]}]=-1 499 | lines=(${lines[2,-1]}) 500 | 501 | # Network ID 502 | if [[ $type = (ids|all) ]]; then 503 | for line in $lines; do 504 | s="${line[${begin[NETWORK ID]},${end[NETWORK ID]}]%% ##}" 505 | s="$s:${(l:7:: :::)${${line[${begin[DRIVER]},${end[DRIVER]}]}%% ##}}" 506 | networks=($networks $s) 507 | done 508 | fi 509 | 510 | # Names 511 | if [[ $type = (names|all) ]]; then 512 | for line in $lines; do 513 | s="${line[${begin[NAME]},${end[NAME]}]%% ##}" 514 | s="$s:${(l:7:: :::)${${line[${begin[DRIVER]},${end[DRIVER]}]}%% ##}}" 515 | networks=($networks $s) 516 | done 517 | fi 518 | 519 | _describe -t networks-list "networks" networks "$@" && ret=0 520 | return ret 521 | } 522 | 523 | __docker_networks() { 524 | [[ $PREFIX = -* ]] && return 1 525 | __docker_get_networks all "$@" 526 | } 527 | 528 | __docker_networks_ids() { 529 | [[ $PREFIX = -* ]] && return 1 530 | __docker_get_networks ids "$@" 531 | } 532 | 533 | __docker_networks_names() { 534 | [[ $PREFIX = -* ]] && return 1 535 | __docker_get_networks names "$@" 536 | } 537 | 538 | __docker_network_commands() { 539 | local -a _docker_network_subcommands 540 | _docker_network_subcommands=( 541 | "connect:Connects a container to a network" 542 | "create:Creates a new network with a name specified by the user" 543 | "disconnect:Disconnects a container from a network" 544 | "inspect:Displays detailed information on a network" 545 | "ls:Lists all the networks created by the user" 546 | "rm:Deletes one or more networks" 547 | ) 548 | _describe -t docker-network-commands "docker network command" _docker_network_subcommands 549 | } 550 | 551 | __docker_network_subcommand() { 552 | local -a _command_args opts_help 553 | local expl help="--help" 554 | integer ret=1 555 | 556 | opts_help=("(: -)--help[Print usage]") 557 | 558 | case "$words[1]" in 559 | (connect) 560 | _arguments $(__docker_arguments) \ 561 | $opts_help \ 562 | "($help)*--alias=[Add network-scoped alias for the container]:alias: " \ 563 | "($help)--ip=[Container IPv4 address]:IPv4: " \ 564 | "($help)--ip6=[Container IPv6 address]:IPv6: " \ 565 | "($help)*--link=[Add a link to another container]:link:->link" \ 566 | "($help -)1:network:__docker_networks" \ 567 | "($help -)2:containers:__docker_containers" && ret=0 568 | 569 | case $state in 570 | (link) 571 | if compset -P "*:"; then 572 | _wanted alias expl "Alias" compadd -E "" && ret=0 573 | else 574 | __docker_runningcontainers -qS ":" && ret=0 575 | fi 576 | ;; 577 | esac 578 | ;; 579 | (create) 580 | _arguments $(__docker_arguments) -A '-*' \ 581 | $opts_help \ 582 | "($help)*--aux-address[Auxiliary IPv4 or IPv6 addresses used by network driver]:key=IP: " \ 583 | "($help -d --driver)"{-d=,--driver=}"[Driver to manage the Network]:driver:(null host bridge overlay)" \ 584 | "($help)*--gateway=[IPv4 or IPv6 Gateway for the master subnet]:IP: " \ 585 | "($help)--internal[Restricts external access to the network]" \ 586 | "($help)*--ip-range=[Allocate container ip from a sub-range]:IP/mask: " \ 587 | "($help)--ipam-driver=[IP Address Management Driver]:driver:(default)" \ 588 | "($help)*--ipam-opt=[Custom IPAM plugin options]:opt=value: " \ 589 | "($help)--ipv6[Enable IPv6 networking]" \ 590 | "($help)*--label=[Set metadata on a network]:label=value: " \ 591 | "($help)*"{-o=,--opt=}"[Driver specific options]:opt=value: " \ 592 | "($help)*--subnet=[Subnet in CIDR format that represents a network segment]:IP/mask: " \ 593 | "($help -)1:Network Name: " && ret=0 594 | ;; 595 | (disconnect) 596 | _arguments $(__docker_arguments) \ 597 | $opts_help \ 598 | "($help -)1:network:__docker_networks" \ 599 | "($help -)2:containers:__docker_containers" && ret=0 600 | ;; 601 | (inspect) 602 | _arguments $(__docker_arguments) \ 603 | $opts_help \ 604 | "($help -f --format)"{-f=,--format=}"[Format the output using the given go template]:template: " \ 605 | "($help -)*:network:__docker_networks" && ret=0 606 | ;; 607 | (ls) 608 | _arguments $(__docker_arguments) \ 609 | $opts_help \ 610 | "($help)--no-trunc[Do not truncate the output]" \ 611 | "($help)*"{-f=,--filter=}"[Provide filter values]:filter:->filter-options" \ 612 | "($help -q --quiet)"{-q,--quiet}"[Only display numeric IDs]" && ret=0 613 | case $state in 614 | (filter-options) 615 | __docker_network_complete_ls_filters && ret=0 616 | ;; 617 | esac 618 | ;; 619 | (rm) 620 | _arguments $(__docker_arguments) \ 621 | $opts_help \ 622 | "($help -)*:network:__docker_networks" && ret=0 623 | ;; 624 | (help) 625 | _arguments $(__docker_arguments) ":subcommand:__docker_network_commands" && ret=0 626 | ;; 627 | esac 628 | 629 | return ret 630 | } 631 | 632 | __docker_volume_complete_ls_filters() { 633 | [[ $PREFIX = -* ]] && return 1 634 | integer ret=1 635 | 636 | if compset -P '*='; then 637 | case "${${words[-1]%=*}#*=}" in 638 | (dangling) 639 | dangling_opts=('true' 'false') 640 | _describe -t dangling-filter-opts "Dangling Filter Options" dangling_opts && ret=0 641 | ;; 642 | (driver) 643 | __docker_plugins Volume && ret=0 644 | ;; 645 | (name) 646 | __docker_volumes && ret=0 647 | ;; 648 | *) 649 | _message 'value' && ret=0 650 | ;; 651 | esac 652 | else 653 | opts=('dangling' 'driver' 'name') 654 | _describe -t filter-opts "Filter Options" opts -qS "=" && ret=0 655 | fi 656 | 657 | return ret 658 | } 659 | 660 | __docker_volumes() { 661 | [[ $PREFIX = -* ]] && return 1 662 | integer ret=1 663 | declare -a lines volumes 664 | 665 | lines=(${(f)"$(_call_program commands docker $docker_options volume ls)"}) 666 | 667 | # Parse header line to find columns 668 | local i=1 j=1 k header=${lines[1]} 669 | declare -A begin end 670 | while (( j < ${#header} - 1 )); do 671 | i=$(( j + ${${header[$j,-1]}[(i)[^ ]]} - 1 )) 672 | j=$(( i + ${${header[$i,-1]}[(i) ]} - 1 )) 673 | k=$(( j + ${${header[$j,-1]}[(i)[^ ]]} - 2 )) 674 | begin[${header[$i,$((j-1))]}]=$i 675 | end[${header[$i,$((j-1))]}]=$k 676 | done 677 | end[${header[$i,$((j-1))]}]=-1 678 | lines=(${lines[2,-1]}) 679 | 680 | # Names 681 | local line s 682 | for line in $lines; do 683 | s="${line[${begin[VOLUME NAME]},${end[VOLUME NAME]}]%% ##}" 684 | s="$s:${(l:7:: :::)${${line[${begin[DRIVER]},${end[DRIVER]}]}%% ##}}" 685 | volumes=($volumes $s) 686 | done 687 | 688 | _describe -t volumes-list "volumes" volumes && ret=0 689 | return ret 690 | } 691 | 692 | __docker_volume_commands() { 693 | local -a _docker_volume_subcommands 694 | _docker_volume_subcommands=( 695 | "create:Create a volume" 696 | "inspect:Return low-level information on a volume" 697 | "ls:List volumes" 698 | "rm:Remove a volume" 699 | ) 700 | _describe -t docker-volume-commands "docker volume command" _docker_volume_subcommands 701 | } 702 | 703 | __docker_volume_subcommand() { 704 | local -a _command_args opts_help 705 | local expl help="--help" 706 | integer ret=1 707 | 708 | opts_help=("(: -)--help[Print usage]") 709 | 710 | case "$words[1]" in 711 | (create) 712 | _arguments $(__docker_arguments) \ 713 | $opts_help \ 714 | "($help -d --driver)"{-d=,--driver=}"[Volume driver name]:Driver name:(local)" \ 715 | "($help)*--label=[Set metadata for a volume]:label=value: " \ 716 | "($help)--name=[Volume name]" \ 717 | "($help)*"{-o=,--opt=}"[Driver specific options]:Driver option: " && ret=0 718 | ;; 719 | (inspect) 720 | _arguments $(__docker_arguments) \ 721 | $opts_help \ 722 | "($help -f --format)"{-f=,--format=}"[Format the output using the given go template]:template: " \ 723 | "($help -)1:volume:__docker_volumes" && ret=0 724 | ;; 725 | (ls) 726 | _arguments $(__docker_arguments) \ 727 | $opts_help \ 728 | "($help)*"{-f=,--filter=}"[Provide filter values]:filter:->filter-options" \ 729 | "($help -q --quiet)"{-q,--quiet}"[Only display volume names]" && ret=0 730 | case $state in 731 | (filter-options) 732 | __docker_volume_complete_ls_filters && ret=0 733 | ;; 734 | esac 735 | ;; 736 | (rm) 737 | _arguments $(__docker_arguments) \ 738 | $opts_help \ 739 | "($help -):volume:__docker_volumes" && ret=0 740 | ;; 741 | (help) 742 | _arguments $(__docker_arguments) ":subcommand:__docker_volume_commands" && ret=0 743 | ;; 744 | esac 745 | 746 | return ret 747 | } 748 | 749 | __docker_caching_policy() { 750 | oldp=( "$1"(Nmh+1) ) # 1 hour 751 | (( $#oldp )) 752 | } 753 | 754 | __docker_commands() { 755 | local cache_policy 756 | 757 | zstyle -s ":completion:${curcontext}:" cache-policy cache_policy 758 | if [[ -z "$cache_policy" ]]; then 759 | zstyle ":completion:${curcontext}:" cache-policy __docker_caching_policy 760 | fi 761 | 762 | if ( [[ ${+_docker_subcommands} -eq 0 ]] || _cache_invalid docker_subcommands) \ 763 | && ! _retrieve_cache docker_subcommands; 764 | then 765 | local -a lines 766 | lines=(${(f)"$(_call_program commands docker 2>&1)"}) 767 | _docker_subcommands=(${${${lines[$((${lines[(i)Commands:]} + 1)),${lines[(I) *]}]}## #}/ ##/:}) 768 | _docker_subcommands=($_docker_subcommands 'daemon:Enable daemon mode' 'help:Show help for a command') 769 | (( $#_docker_subcommands > 2 )) && _store_cache docker_subcommands _docker_subcommands 770 | fi 771 | _describe -t docker-commands "docker command" _docker_subcommands 772 | } 773 | 774 | __docker_subcommand() { 775 | local -a _command_args opts_help opts_build_create_run opts_build_create_run_update opts_create_run opts_create_run_update 776 | local expl help="--help" 777 | integer ret=1 778 | 779 | opts_help=("(: -)--help[Print usage]") 780 | opts_build_create_run=( 781 | "($help)--cgroup-parent=[Parent cgroup for the container]:cgroup: " 782 | "($help)--isolation=[Container isolation technology]:isolation:(default hyperv process)" 783 | "($help)--disable-content-trust[Skip image verification]" 784 | "($help)*--shm-size=[Size of '/dev/shm' (format is '')]:shm size: " 785 | "($help)*--ulimit=[ulimit options]:ulimit: " 786 | "($help)--userns=[Container user namespace]:user namespace:(host)" 787 | ) 788 | opts_build_create_run_update=( 789 | "($help)--cpu-shares=[CPU shares (relative weight)]:CPU shares:(0 10 100 200 500 800 1000)" 790 | "($help)--cpu-period=[Limit the CPU CFS (Completely Fair Scheduler) period]:CPU period: " 791 | "($help)--cpu-quota=[Limit the CPU CFS (Completely Fair Scheduler) quota]:CPU quota: " 792 | "($help)--cpuset-cpus=[CPUs in which to allow execution]:CPUs: " 793 | "($help)--cpuset-mems=[MEMs in which to allow execution]:MEMs: " 794 | "($help -m --memory)"{-m=,--memory=}"[Memory limit]:Memory limit: " 795 | "($help)--memory-swap=[Total memory limit with swap]:Memory limit: " 796 | ) 797 | opts_create_run=( 798 | "($help -a --attach)"{-a=,--attach=}"[Attach to stdin, stdout or stderr]:device:(STDIN STDOUT STDERR)" 799 | "($help)*--add-host=[Add a custom host-to-IP mapping]:host\:ip mapping: " 800 | "($help)*--blkio-weight-device=[Block IO (relative device weight)]:device:Block IO weight: " 801 | "($help)*--cap-add=[Add Linux capabilities]:capability: " 802 | "($help)*--cap-drop=[Drop Linux capabilities]:capability: " 803 | "($help)--cidfile=[Write the container ID to the file]:CID file:_files" 804 | "($help)*--device=[Add a host device to the container]:device:_files" 805 | "($help)*--device-read-bps=[Limit the read rate (bytes per second) from a device]:device:IO rate: " 806 | "($help)*--device-read-iops=[Limit the read rate (IO per second) from a device]:device:IO rate: " 807 | "($help)*--device-write-bps=[Limit the write rate (bytes per second) to a device]:device:IO rate: " 808 | "($help)*--device-write-iops=[Limit the write rate (IO per second) to a device]:device:IO rate: " 809 | "($help)*--dns=[Custom DNS servers]:DNS server: " 810 | "($help)*--dns-opt=[Custom DNS options]:DNS option: " 811 | "($help)*--dns-search=[Custom DNS search domains]:DNS domains: " 812 | "($help)*"{-e=,--env=}"[Environment variables]:environment variable: " 813 | "($help)--entrypoint=[Overwrite the default entrypoint of the image]:entry point: " 814 | "($help)*--env-file=[Read environment variables from a file]:environment file:_files" 815 | "($help)*--expose=[Expose a port from the container without publishing it]: " 816 | "($help)*--group-add=[Add additional groups to run as]:group:_groups" 817 | "($help -h --hostname)"{-h=,--hostname=}"[Container host name]:hostname:_hosts" 818 | "($help -i --interactive)"{-i,--interactive}"[Keep stdin open even if not attached]" 819 | "($help)--ip=[Container IPv4 address]:IPv4: " 820 | "($help)--ip6=[Container IPv6 address]:IPv6: " 821 | "($help)--ipc=[IPC namespace to use]:IPC namespace: " 822 | "($help)*--link=[Add link to another container]:link:->link" 823 | "($help)*"{-l=,--label=}"[Container metadata]:label: " 824 | "($help)--log-driver=[Default driver for container logs]:Logging driver:(awslogs etwlogs fluentd gcplogs gelf journald json-file none splunk syslog)" 825 | "($help)*--log-opt=[Log driver specific options]:log driver options:__docker_log_options" 826 | "($help)--mac-address=[Container MAC address]:MAC address: " 827 | "($help)--name=[Container name]:name: " 828 | "($help)--net=[Connect a container to a network]:network mode:(bridge none container host)" 829 | "($help)*--net-alias=[Add network-scoped alias for the container]:alias: " 830 | "($help)--oom-kill-disable[Disable OOM Killer]" 831 | "($help)--oom-score-adj[Tune the host's OOM preferences for containers (accepts -1000 to 1000)]" 832 | "($help)--pids-limit[Tune container pids limit (set -1 for unlimited)]" 833 | "($help -P --publish-all)"{-P,--publish-all}"[Publish all exposed ports]" 834 | "($help)*"{-p=,--publish=}"[Expose a container's port to the host]:port:_ports" 835 | "($help)--pid=[PID namespace to use]:PID namespace:__docker_complete_pid" 836 | "($help)--privileged[Give extended privileges to this container]" 837 | "($help)--read-only[Mount the container's root filesystem as read only]" 838 | "($help)*--security-opt=[Security options]:security option: " 839 | "($help)*--sysctl=-[sysctl options]:sysctl: " 840 | "($help -t --tty)"{-t,--tty}"[Allocate a pseudo-tty]" 841 | "($help -u --user)"{-u=,--user=}"[Username or UID]:user:_users" 842 | "($help)--tmpfs[mount tmpfs]" 843 | "($help)*-v[Bind mount a volume]:volume: " 844 | "($help)--volume-driver=[Optional volume driver for the container]:volume driver:(local)" 845 | "($help)*--volumes-from=[Mount volumes from the specified container]:volume: " 846 | "($help -w --workdir)"{-w=,--workdir=}"[Working directory inside the container]:directory:_directories" 847 | ) 848 | opts_create_run_update=( 849 | "($help)--blkio-weight=[Block IO (relative weight), between 10 and 1000]:Block IO weight:(10 100 500 1000)" 850 | "($help)--kernel-memory=[Kernel memory limit in bytes]:Memory limit: " 851 | "($help)--memory-reservation=[Memory soft limit]:Memory limit: " 852 | "($help)--restart=[Restart policy]:restart policy:(no on-failure always unless-stopped)" 853 | ) 854 | opts_attach_exec_run_start=( 855 | "($help)--detach-keys=[Escape key sequence used to detach a container]:sequence:__docker_complete_detach_keys" 856 | ) 857 | 858 | case "$words[1]" in 859 | (attach) 860 | _arguments $(__docker_arguments) \ 861 | $opts_help \ 862 | $opts_attach_exec_run_start \ 863 | "($help)--no-stdin[Do not attach stdin]" \ 864 | "($help)--sig-proxy[Proxy all received signals to the process (non-TTY mode only)]" \ 865 | "($help -):containers:__docker_runningcontainers" && ret=0 866 | ;; 867 | (build) 868 | _arguments $(__docker_arguments) \ 869 | $opts_help \ 870 | $opts_build_create_run \ 871 | $opts_build_create_run_update \ 872 | "($help)*--build-arg[Build-time variables]:=: " \ 873 | "($help -f --file)"{-f=,--file=}"[Name of the Dockerfile]:Dockerfile:_files" \ 874 | "($help)--force-rm[Always remove intermediate containers]" \ 875 | "($help)*--label=[Set metadata for an image]:label=value: " \ 876 | "($help)--no-cache[Do not use cache when building the image]" \ 877 | "($help)--pull[Attempt to pull a newer version of the image]" \ 878 | "($help -q --quiet)"{-q,--quiet}"[Suppress verbose build output]" \ 879 | "($help)--rm[Remove intermediate containers after a successful build]" \ 880 | "($help -t --tag)*"{-t=,--tag=}"[Repository, name and tag for the image]: :__docker_repositories_with_tags" \ 881 | "($help -):path or URL:_directories" && ret=0 882 | ;; 883 | (commit) 884 | _arguments $(__docker_arguments) \ 885 | $opts_help \ 886 | "($help -a --author)"{-a=,--author=}"[Author]:author: " \ 887 | "($help)*"{-c=,--change=}"[Apply Dockerfile instruction to the created image]:Dockerfile:_files" \ 888 | "($help -m --message)"{-m=,--message=}"[Commit message]:message: " \ 889 | "($help -p --pause)"{-p,--pause}"[Pause container during commit]" \ 890 | "($help -):container:__docker_containers" \ 891 | "($help -): :__docker_repositories_with_tags" && ret=0 892 | ;; 893 | (cp) 894 | _arguments $(__docker_arguments) \ 895 | $opts_help \ 896 | "($help -L --follow-link)"{-L,--follow-link}"[Always follow symbol link]" \ 897 | "($help -)1:container:->container" \ 898 | "($help -)2:hostpath:_files" && ret=0 899 | case $state in 900 | (container) 901 | if compset -P "*:"; then 902 | _files && ret=0 903 | else 904 | __docker_containers -qS ":" && ret=0 905 | fi 906 | ;; 907 | esac 908 | ;; 909 | (create) 910 | _arguments $(__docker_arguments) \ 911 | $opts_help \ 912 | $opts_build_create_run \ 913 | $opts_build_create_run_update \ 914 | $opts_create_run \ 915 | $opts_create_run_update \ 916 | "($help -): :__docker_images" \ 917 | "($help -):command: _command_names -e" \ 918 | "($help -)*::arguments: _normal" && ret=0 919 | 920 | case $state in 921 | (link) 922 | if compset -P "*:"; then 923 | _wanted alias expl "Alias" compadd -E "" && ret=0 924 | else 925 | __docker_runningcontainers -qS ":" && ret=0 926 | fi 927 | ;; 928 | esac 929 | 930 | ;; 931 | (daemon) 932 | _arguments $(__docker_arguments) \ 933 | $opts_help \ 934 | "($help)--api-cors-header=[CORS headers in the remote API]:CORS headers: " \ 935 | "($help)*--authorization-plugin=[Authorization plugins to load]" \ 936 | "($help -b --bridge)"{-b=,--bridge=}"[Attach containers to a network bridge]:bridge:_net_interfaces" \ 937 | "($help)--bip=[Network bridge IP]:IP address: " \ 938 | "($help)--cgroup-parent=[Parent cgroup for all containers]:cgroup: " \ 939 | "($help)--config-file=[Path to daemon configuration file]:Config File:_files" \ 940 | "($help)--containerd=[Path to containerd socket]:socket:_files -g \"*.sock\"" \ 941 | "($help -D --debug)"{-D,--debug}"[Enable debug mode]" \ 942 | "($help)--default-gateway[Container default gateway IPv4 address]:IPv4 address: " \ 943 | "($help)--default-gateway-v6[Container default gateway IPv6 address]:IPv6 address: " \ 944 | "($help)--cluster-store=[URL of the distributed storage backend]:Cluster Store:->cluster-store" \ 945 | "($help)--cluster-advertise=[Address of the daemon instance to advertise]:Instance to advertise (host\:port): " \ 946 | "($help)*--cluster-store-opt=[Cluster options]:Cluster options:->cluster-store-options" \ 947 | "($help)*--dns=[DNS server to use]:DNS: " \ 948 | "($help)*--dns-search=[DNS search domains to use]:DNS search: " \ 949 | "($help)*--dns-opt=[DNS options to use]:DNS option: " \ 950 | "($help)*--default-ulimit=[Default ulimit settings for containers]:ulimit: " \ 951 | "($help)--disable-legacy-registry[Do not contact legacy registries]" \ 952 | "($help)*--exec-opt=[Runtime execution options]:runtime execution options: " \ 953 | "($help)--exec-root=[Root directory for execution state files]:path:_directories" \ 954 | "($help)--fixed-cidr=[IPv4 subnet for fixed IPs]:IPv4 subnet: " \ 955 | "($help)--fixed-cidr-v6=[IPv6 subnet for fixed IPs]:IPv6 subnet: " \ 956 | "($help -G --group)"{-G=,--group=}"[Group for the unix socket]:group:_groups" \ 957 | "($help -g --graph)"{-g=,--graph=}"[Root of the Docker runtime]:path:_directories" \ 958 | "($help -H --host)"{-H=,--host=}"[tcp://host:port to bind/connect to]:host: " \ 959 | "($help)--icc[Enable inter-container communication]" \ 960 | "($help)*--insecure-registry=[Enable insecure registry communication]:registry: " \ 961 | "($help)--ip=[Default IP when binding container ports]" \ 962 | "($help)--ip-forward[Enable net.ipv4.ip_forward]" \ 963 | "($help)--ip-masq[Enable IP masquerading]" \ 964 | "($help)--iptables[Enable addition of iptables rules]" \ 965 | "($help)--ipv6[Enable IPv6 networking]" \ 966 | "($help -l --log-level)"{-l=,--log-level=}"[Logging level]:level:(debug info warn error fatal)" \ 967 | "($help)*--label=[Key=value labels]:label: " \ 968 | "($help)--log-driver=[Default driver for container logs]:Logging driver:(awslogs etwlogs fluentd gcplogs gelf journald json-file none splunk syslog)" \ 969 | "($help)*--log-opt=[Log driver specific options]:log driver options:__docker_log_options" \ 970 | "($help)--max-concurrent-downloads[Set the max concurrent downloads for each pull]" \ 971 | "($help)--max-concurrent-uploads[Set the max concurrent uploads for each push]" \ 972 | "($help)--mtu=[Network MTU]:mtu:(0 576 1420 1500 9000)" \ 973 | "($help -p --pidfile)"{-p=,--pidfile=}"[Path to use for daemon PID file]:PID file:_files" \ 974 | "($help)--raw-logs[Full timestamps without ANSI coloring]" \ 975 | "($help)*--registry-mirror=[Preferred Docker registry mirror]:registry mirror: " \ 976 | "($help -s --storage-driver)"{-s=,--storage-driver=}"[Storage driver to use]:driver:(aufs devicemapper btrfs zfs overlay)" \ 977 | "($help)--selinux-enabled[Enable selinux support]" \ 978 | "($help)*--storage-opt=[Storage driver options]:storage driver options: " \ 979 | "($help)--tls[Use TLS]" \ 980 | "($help)--tlscacert=[Trust certs signed only by this CA]:PEM file:_files -g \"*.(pem|crt)\"" \ 981 | "($help)--tlscert=[Path to TLS certificate file]:PEM file:_files -g \"*.(pem|crt)\"" \ 982 | "($help)--tlskey=[Path to TLS key file]:Key file:_files -g \"*.(pem|key)\"" \ 983 | "($help)--tlsverify[Use TLS and verify the remote]" \ 984 | "($help)--userns-remap=[User/Group setting for user namespaces]:user\:group:->users-groups" \ 985 | "($help)--userland-proxy[Use userland proxy for loopback traffic]" && ret=0 986 | 987 | case $state in 988 | (cluster-store) 989 | if compset -P '*://'; then 990 | _message 'host:port' && ret=0 991 | else 992 | store=('consul' 'etcd' 'zk') 993 | _describe -t cluster-store "Cluster Store" store -qS "://" && ret=0 994 | fi 995 | ;; 996 | (cluster-store-options) 997 | if compset -P '*='; then 998 | _files && ret=0 999 | else 1000 | opts=('discovery.heartbeat' 'discovery.ttl' 'kv.cacertfile' 'kv.certfile' 'kv.keyfile' 'kv.path') 1001 | _describe -t cluster-store-opts "Cluster Store Options" opts -qS "=" && ret=0 1002 | fi 1003 | ;; 1004 | (users-groups) 1005 | if compset -P '*:'; then 1006 | _groups && ret=0 1007 | else 1008 | _describe -t userns-default "default Docker user management" '(default)' && ret=0 1009 | _users && ret=0 1010 | fi 1011 | ;; 1012 | esac 1013 | ;; 1014 | (diff) 1015 | _arguments $(__docker_arguments) \ 1016 | $opts_help \ 1017 | "($help -)*:containers:__docker_containers" && ret=0 1018 | ;; 1019 | (events) 1020 | _arguments $(__docker_arguments) \ 1021 | $opts_help \ 1022 | "($help)*"{-f=,--filter=}"[Filter values]:filter:__docker_complete_events_filter" \ 1023 | "($help)--since=[Events created since this timestamp]:timestamp: " \ 1024 | "($help)--until=[Events created until this timestamp]:timestamp: " && ret=0 1025 | ;; 1026 | (exec) 1027 | local state 1028 | _arguments $(__docker_arguments) \ 1029 | $opts_help \ 1030 | $opts_attach_exec_run_start \ 1031 | "($help -d --detach)"{-d,--detach}"[Detached mode: leave the container running in the background]" \ 1032 | "($help -i --interactive)"{-i,--interactive}"[Keep stdin open even if not attached]" \ 1033 | "($help)--privileged[Give extended Linux capabilities to the command]" \ 1034 | "($help -t --tty)"{-t,--tty}"[Allocate a pseudo-tty]" \ 1035 | "($help -u --user)"{-u=,--user=}"[Username or UID]:user:_users" \ 1036 | "($help -):containers:__docker_runningcontainers" \ 1037 | "($help -)*::command:->anycommand" && ret=0 1038 | 1039 | case $state in 1040 | (anycommand) 1041 | shift 1 words 1042 | (( CURRENT-- )) 1043 | _normal && ret=0 1044 | ;; 1045 | esac 1046 | ;; 1047 | (export) 1048 | _arguments $(__docker_arguments) \ 1049 | $opts_help \ 1050 | "($help -o --output)"{-o=,--output=}"[Write to a file, instead of stdout]:output file:_files" \ 1051 | "($help -)*:containers:__docker_containers" && ret=0 1052 | ;; 1053 | (history) 1054 | _arguments $(__docker_arguments) \ 1055 | $opts_help \ 1056 | "($help -H --human)"{-H,--human}"[Print sizes and dates in human readable format]" \ 1057 | "($help)--no-trunc[Do not truncate output]" \ 1058 | "($help -q --quiet)"{-q,--quiet}"[Only show numeric IDs]" \ 1059 | "($help -)*: :__docker_images" && ret=0 1060 | ;; 1061 | (images) 1062 | _arguments $(__docker_arguments) \ 1063 | $opts_help \ 1064 | "($help -a --all)"{-a,--all}"[Show all images]" \ 1065 | "($help)--digests[Show digests]" \ 1066 | "($help)*"{-f=,--filter=}"[Filter values]:filter:->filter-options" \ 1067 | "($help)--format[Pretty-print containers using a Go template]:format: " \ 1068 | "($help)--no-trunc[Do not truncate output]" \ 1069 | "($help -q --quiet)"{-q,--quiet}"[Only show numeric IDs]" \ 1070 | "($help -): :__docker_repositories" && ret=0 1071 | 1072 | case $state in 1073 | (filter-options) 1074 | __docker_complete_images_filters && ret=0 1075 | ;; 1076 | esac 1077 | ;; 1078 | (import) 1079 | _arguments $(__docker_arguments) \ 1080 | $opts_help \ 1081 | "($help)*"{-c=,--change=}"[Apply Dockerfile instruction to the created image]:Dockerfile:_files" \ 1082 | "($help -m --message)"{-m=,--message=}"[Commit message for imported image]:message: " \ 1083 | "($help -):URL:(- http:// file://)" \ 1084 | "($help -): :__docker_repositories_with_tags" && ret=0 1085 | ;; 1086 | (info|version) 1087 | _arguments $(__docker_arguments) \ 1088 | $opts_help && ret=0 1089 | ;; 1090 | (inspect) 1091 | local state 1092 | _arguments $(__docker_arguments) \ 1093 | $opts_help \ 1094 | "($help -f --format)"{-f=,--format=}"[Format the output using the given go template]:template: " \ 1095 | "($help -s --size)"{-s,--size}"[Display total file sizes if the type is container]" \ 1096 | "($help)--type=[Return JSON for specified type]:type:(image container)" \ 1097 | "($help -)*: :->values" && ret=0 1098 | 1099 | case $state in 1100 | (values) 1101 | if [[ ${words[(r)--type=container]} == --type=container ]]; then 1102 | __docker_containers && ret=0 1103 | elif [[ ${words[(r)--type=image]} == --type=image ]]; then 1104 | __docker_images && ret=0 1105 | else 1106 | __docker_images && __docker_containers && ret=0 1107 | fi 1108 | ;; 1109 | esac 1110 | ;; 1111 | (kill) 1112 | _arguments $(__docker_arguments) \ 1113 | $opts_help \ 1114 | "($help -s --signal)"{-s=,--signal=}"[Signal to send]:signal:_signals" \ 1115 | "($help -)*:containers:__docker_runningcontainers" && ret=0 1116 | ;; 1117 | (load) 1118 | _arguments $(__docker_arguments) \ 1119 | $opts_help \ 1120 | "($help -i --input)"{-i=,--input=}"[Read from tar archive file]:archive file:_files -g \"*.((tar|TAR)(.gz|.GZ|.Z|.bz2|.lzma|.xz|)|(tbz|tgz|txz))(-.)\"" \ 1121 | "($help -q --quiet)"{-q,--quiet}"[Suppress the load output]" && ret=0 1122 | ;; 1123 | (login) 1124 | _arguments $(__docker_arguments) \ 1125 | $opts_help \ 1126 | "($help -p --password)"{-p=,--password=}"[Password]:password: " \ 1127 | "($help -u --user)"{-u=,--user=}"[Username]:username: " \ 1128 | "($help -)1:server: " && ret=0 1129 | ;; 1130 | (logout) 1131 | _arguments $(__docker_arguments) \ 1132 | $opts_help \ 1133 | "($help -)1:server: " && ret=0 1134 | ;; 1135 | (logs) 1136 | _arguments $(__docker_arguments) \ 1137 | $opts_help \ 1138 | "($help)--details[Show extra details provided to logs]" \ 1139 | "($help -f --follow)"{-f,--follow}"[Follow log output]" \ 1140 | "($help -s --since)"{-s=,--since=}"[Show logs since this timestamp]:timestamp: " \ 1141 | "($help -t --timestamps)"{-t,--timestamps}"[Show timestamps]" \ 1142 | "($help)--tail=[Output the last K lines]:lines:(1 10 20 50 all)" \ 1143 | "($help -)*:containers:__docker_containers" && ret=0 1144 | ;; 1145 | (network) 1146 | local curcontext="$curcontext" state 1147 | _arguments $(__docker_arguments) \ 1148 | $opts_help \ 1149 | "($help -): :->command" \ 1150 | "($help -)*:: :->option-or-argument" && ret=0 1151 | 1152 | case $state in 1153 | (command) 1154 | __docker_network_commands && ret=0 1155 | ;; 1156 | (option-or-argument) 1157 | curcontext=${curcontext%:*:*}:docker-${words[-1]}: 1158 | __docker_network_subcommand && ret=0 1159 | ;; 1160 | esac 1161 | ;; 1162 | (pause|unpause) 1163 | _arguments $(__docker_arguments) \ 1164 | $opts_help \ 1165 | "($help -)*:containers:__docker_runningcontainers" && ret=0 1166 | ;; 1167 | (port) 1168 | _arguments $(__docker_arguments) \ 1169 | $opts_help \ 1170 | "($help -)1:containers:__docker_runningcontainers" \ 1171 | "($help -)2:port:_ports" && ret=0 1172 | ;; 1173 | (ps) 1174 | _arguments $(__docker_arguments) \ 1175 | $opts_help \ 1176 | "($help -a --all)"{-a,--all}"[Show all containers]" \ 1177 | "($help)--before=[Show only container created before...]:containers:__docker_containers" \ 1178 | "($help)*"{-f=,--filter=}"[Filter values]:filter:__docker_complete_ps_filters" \ 1179 | "($help)--format[Pretty-print containers using a Go template]:format: " \ 1180 | "($help -l --latest)"{-l,--latest}"[Show only the latest created container]" \ 1181 | "($help)-n[Show n last created containers, include non-running one]:n:(1 5 10 25 50)" \ 1182 | "($help)--no-trunc[Do not truncate output]" \ 1183 | "($help -q --quiet)"{-q,--quiet}"[Only show numeric IDs]" \ 1184 | "($help -s --size)"{-s,--size}"[Display total file sizes]" \ 1185 | "($help)--since=[Show only containers created since...]:containers:__docker_containers" && ret=0 1186 | ;; 1187 | (pull) 1188 | _arguments $(__docker_arguments) \ 1189 | $opts_help \ 1190 | "($help -a --all-tags)"{-a,--all-tags}"[Download all tagged images]" \ 1191 | "($help)--disable-content-trust[Skip image verification]" \ 1192 | "($help -):name:__docker_search" && ret=0 1193 | ;; 1194 | (push) 1195 | _arguments $(__docker_arguments) \ 1196 | $opts_help \ 1197 | "($help)--disable-content-trust[Skip image signing]" \ 1198 | "($help -): :__docker_images" && ret=0 1199 | ;; 1200 | (rename) 1201 | _arguments $(__docker_arguments) \ 1202 | $opts_help \ 1203 | "($help -):old name:__docker_containers" \ 1204 | "($help -):new name: " && ret=0 1205 | ;; 1206 | (restart|stop) 1207 | _arguments $(__docker_arguments) \ 1208 | $opts_help \ 1209 | "($help -t --time)"{-t=,--time=}"[Number of seconds to try to stop for before killing the container]:seconds to before killing:(1 5 10 30 60)" \ 1210 | "($help -)*:containers:__docker_runningcontainers" && ret=0 1211 | ;; 1212 | (rm) 1213 | _arguments $(__docker_arguments) \ 1214 | $opts_help \ 1215 | "($help -f --force)"{-f,--force}"[Force removal]" \ 1216 | "($help -l --link)"{-l,--link}"[Remove the specified link and not the underlying container]" \ 1217 | "($help -v --volumes)"{-v,--volumes}"[Remove the volumes associated to the container]" \ 1218 | "($help -)*:containers:->values" && ret=0 1219 | case $state in 1220 | (values) 1221 | if [[ ${words[(r)-f]} == -f || ${words[(r)--force]} == --force ]]; then 1222 | __docker_containers && ret=0 1223 | else 1224 | __docker_stoppedcontainers && ret=0 1225 | fi 1226 | ;; 1227 | esac 1228 | ;; 1229 | (rmi) 1230 | _arguments $(__docker_arguments) \ 1231 | $opts_help \ 1232 | "($help -f --force)"{-f,--force}"[Force removal]" \ 1233 | "($help)--no-prune[Do not delete untagged parents]" \ 1234 | "($help -)*: :__docker_images" && ret=0 1235 | ;; 1236 | (run) 1237 | _arguments $(__docker_arguments) \ 1238 | $opts_help \ 1239 | $opts_build_create_run \ 1240 | $opts_build_create_run_update \ 1241 | $opts_create_run \ 1242 | $opts_create_run_update \ 1243 | $opts_attach_exec_run_start \ 1244 | "($help -d --detach)"{-d,--detach}"[Detached mode: leave the container running in the background]" \ 1245 | "($help)--health-cmd=[Command to run to check health]:command: " \ 1246 | "($help)--health-interval=[Time between running the check]:time: " \ 1247 | "($help)--health-retries=[Consecutive failures needed to report unhealthy]:retries:(1 2 3 4 5)" \ 1248 | "($help)--health-timeout=[Maximum time to allow one check to run]:time: " \ 1249 | "($help)--no-healthcheck[Disable any container-specified HEALTHCHECK]" \ 1250 | "($help)--rm[Remove intermediate containers when it exits]" \ 1251 | "($help)--sig-proxy[Proxy all received signals to the process (non-TTY mode only)]" \ 1252 | "($help)--stop-signal=[Signal to kill a container]:signal:_signals" \ 1253 | "($help -): :__docker_images" \ 1254 | "($help -):command: _command_names -e" \ 1255 | "($help -)*::arguments: _normal" && ret=0 1256 | 1257 | case $state in 1258 | (link) 1259 | if compset -P "*:"; then 1260 | _wanted alias expl "Alias" compadd -E "" && ret=0 1261 | else 1262 | __docker_runningcontainers -qS ":" && ret=0 1263 | fi 1264 | ;; 1265 | esac 1266 | 1267 | ;; 1268 | (save) 1269 | _arguments $(__docker_arguments) \ 1270 | $opts_help \ 1271 | "($help -o --output)"{-o=,--output=}"[Write to file]:file:_files" \ 1272 | "($help -)*: :__docker_images" && ret=0 1273 | ;; 1274 | (search) 1275 | _arguments $(__docker_arguments) \ 1276 | $opts_help \ 1277 | "($help)*"{-f=,--filter=}"[Filter values]:filter:->filter-options" \ 1278 | "($help)--limit=[Maximum returned search results]:limit:(1 5 10 25 50)" \ 1279 | "($help)--no-trunc[Do not truncate output]" \ 1280 | "($help -):term: " && ret=0 1281 | 1282 | case $state in 1283 | (filter-options) 1284 | __docker_complete_search_filters && ret=0 1285 | ;; 1286 | esac 1287 | ;; 1288 | (start) 1289 | _arguments $(__docker_arguments) \ 1290 | $opts_help \ 1291 | $opts_attach_exec_run_start \ 1292 | "($help -a --attach)"{-a,--attach}"[Attach container's stdout/stderr and forward all signals]" \ 1293 | "($help -i --interactive)"{-i,--interactive}"[Attach container's stding]" \ 1294 | "($help -)*:containers:__docker_stoppedcontainers" && ret=0 1295 | ;; 1296 | (stats) 1297 | _arguments $(__docker_arguments) \ 1298 | $opts_help \ 1299 | "($help -a --all)"{-a,--all}"[Show all containers (default shows just running)]" \ 1300 | "($help)--no-stream[Disable streaming stats and only pull the first result]" \ 1301 | "($help -)*:containers:__docker_runningcontainers" && ret=0 1302 | ;; 1303 | (tag) 1304 | _arguments $(__docker_arguments) \ 1305 | $opts_help \ 1306 | "($help -):source:__docker_images"\ 1307 | "($help -):destination:__docker_repositories_with_tags" && ret=0 1308 | ;; 1309 | (top) 1310 | _arguments $(__docker_arguments) \ 1311 | $opts_help \ 1312 | "($help -)1:containers:__docker_runningcontainers" \ 1313 | "($help -)*:: :->ps-arguments" && ret=0 1314 | case $state in 1315 | (ps-arguments) 1316 | _ps && ret=0 1317 | ;; 1318 | esac 1319 | 1320 | ;; 1321 | (update) 1322 | _arguments $(__docker_arguments) \ 1323 | $opts_help \ 1324 | $opts_create_run_update \ 1325 | $opts_build_create_run_update \ 1326 | "($help -)*: :->values" && ret=0 1327 | 1328 | case $state in 1329 | (values) 1330 | if [[ ${words[(r)--kernel-memory*]} = (--kernel-memory*) ]]; then 1331 | __docker_stoppedcontainers && ret=0 1332 | else 1333 | __docker_containers && ret=0 1334 | fi 1335 | ;; 1336 | esac 1337 | ;; 1338 | (volume) 1339 | local curcontext="$curcontext" state 1340 | _arguments $(__docker_arguments) \ 1341 | $opts_help \ 1342 | "($help -): :->command" \ 1343 | "($help -)*:: :->option-or-argument" && ret=0 1344 | 1345 | case $state in 1346 | (command) 1347 | __docker_volume_commands && ret=0 1348 | ;; 1349 | (option-or-argument) 1350 | curcontext=${curcontext%:*:*}:docker-${words[-1]}: 1351 | __docker_volume_subcommand && ret=0 1352 | ;; 1353 | esac 1354 | ;; 1355 | (wait) 1356 | _arguments $(__docker_arguments) \ 1357 | $opts_help \ 1358 | "($help -)*:containers:__docker_runningcontainers" && ret=0 1359 | ;; 1360 | (help) 1361 | _arguments $(__docker_arguments) ":subcommand:__docker_commands" && ret=0 1362 | ;; 1363 | esac 1364 | 1365 | return ret 1366 | } 1367 | 1368 | _docker() { 1369 | # Support for subservices, which allows for `compdef _docker docker-shell=_docker_containers`. 1370 | # Based on /usr/share/zsh/functions/Completion/Unix/_git without support for `ret`. 1371 | if [[ $service != docker ]]; then 1372 | _call_function - _$service 1373 | return 1374 | fi 1375 | 1376 | local curcontext="$curcontext" state line help="-h --help" 1377 | integer ret=1 1378 | typeset -A opt_args 1379 | 1380 | _arguments $(__docker_arguments) -C \ 1381 | "(: -)"{-h,--help}"[Print usage]" \ 1382 | "($help)--config[Location of client config files]:path:_directories" \ 1383 | "($help -D --debug)"{-D,--debug}"[Enable debug mode]" \ 1384 | "($help -H --host)"{-H=,--host=}"[tcp://host:port to bind/connect to]:host: " \ 1385 | "($help -l --log-level)"{-l=,--log-level=}"[Logging level]:level:(debug info warn error fatal)" \ 1386 | "($help)--tls[Use TLS]" \ 1387 | "($help)--tlscacert=[Trust certs signed only by this CA]:PEM file:_files -g "*.(pem|crt)"" \ 1388 | "($help)--tlscert=[Path to TLS certificate file]:PEM file:_files -g "*.(pem|crt)"" \ 1389 | "($help)--tlskey=[Path to TLS key file]:Key file:_files -g "*.(pem|key)"" \ 1390 | "($help)--tlsverify[Use TLS and verify the remote]" \ 1391 | "($help)--userland-proxy[Use userland proxy for loopback traffic]" \ 1392 | "($help -v --version)"{-v,--version}"[Print version information and quit]" \ 1393 | "($help -): :->command" \ 1394 | "($help -)*:: :->option-or-argument" && ret=0 1395 | 1396 | local host=${opt_args[-H]}${opt_args[--host]} 1397 | local config=${opt_args[--config]} 1398 | local docker_options="${host:+--host $host} ${config:+--config $config}" 1399 | 1400 | case $state in 1401 | (command) 1402 | __docker_commands && ret=0 1403 | ;; 1404 | (option-or-argument) 1405 | curcontext=${curcontext%:*:*}:docker-$words[1]: 1406 | __docker_subcommand && ret=0 1407 | ;; 1408 | esac 1409 | 1410 | return ret 1411 | } 1412 | 1413 | _docker "$@" 1414 | 1415 | # Local Variables: 1416 | # mode: Shell-Script 1417 | # sh-indentation: 4 1418 | # indent-tabs-mode: nil 1419 | # sh-basic-offset: 4 1420 | # End: 1421 | # vim: ft=zsh sw=4 ts=4 et 1422 | -------------------------------------------------------------------------------- /roles/docker/_docker-compose: -------------------------------------------------------------------------------- 1 | #compdef docker-compose 2 | 3 | # Description 4 | # ----------- 5 | # zsh completion for docker-compose 6 | # https://github.com/sdurrheimer/docker-compose-zsh-completion 7 | # ------------------------------------------------------------------------- 8 | # Version 9 | # ------- 10 | # 1.5.0 11 | # ------------------------------------------------------------------------- 12 | # Authors 13 | # ------- 14 | # * Steve Durrheimer 15 | # ------------------------------------------------------------------------- 16 | # Inspiration 17 | # ----------- 18 | # * @albers docker-compose bash completion script 19 | # * @felixr docker zsh completion script : https://github.com/felixr/docker-zsh-completion 20 | # ------------------------------------------------------------------------- 21 | 22 | __docker-compose_q() { 23 | docker-compose 2>/dev/null $compose_options "$@" 24 | } 25 | 26 | # All services defined in docker-compose.yml 27 | __docker-compose_all_services_in_compose_file() { 28 | local already_selected 29 | local -a services 30 | already_selected=$(echo $words | tr " " "|") 31 | __docker-compose_q config --services \ 32 | | grep -Ev "^(${already_selected})$" 33 | } 34 | 35 | # All services, even those without an existing container 36 | __docker-compose_services_all() { 37 | [[ $PREFIX = -* ]] && return 1 38 | integer ret=1 39 | services=$(__docker-compose_all_services_in_compose_file) 40 | _alternative "args:services:($services)" && ret=0 41 | 42 | return ret 43 | } 44 | 45 | # All services that have an entry with the given key in their docker-compose.yml section 46 | __docker-compose_services_with_key() { 47 | local already_selected 48 | local -a buildable 49 | already_selected=$(echo $words | tr " " "|") 50 | # flatten sections to one line, then filter lines containing the key and return section name. 51 | __docker-compose_q config \ 52 | | sed -n -e '/^services:/,/^[^ ]/p' \ 53 | | sed -n 's/^ //p' \ 54 | | awk '/^[a-zA-Z0-9]/{printf "\n"};{printf $0;next;}' \ 55 | | grep " \+$1:" \ 56 | | cut -d: -f1 \ 57 | | grep -Ev "^(${already_selected})$" 58 | } 59 | 60 | # All services that are defined by a Dockerfile reference 61 | __docker-compose_services_from_build() { 62 | [[ $PREFIX = -* ]] && return 1 63 | integer ret=1 64 | buildable=$(__docker-compose_services_with_key build) 65 | _alternative "args:buildable services:($buildable)" && ret=0 66 | 67 | return ret 68 | } 69 | 70 | # All services that are defined by an image 71 | __docker-compose_services_from_image() { 72 | [[ $PREFIX = -* ]] && return 1 73 | integer ret=1 74 | pullable=$(__docker-compose_services_with_key image) 75 | _alternative "args:pullable services:($pullable)" && ret=0 76 | 77 | return ret 78 | } 79 | 80 | __docker-compose_get_services() { 81 | [[ $PREFIX = -* ]] && return 1 82 | integer ret=1 83 | local kind 84 | declare -a running paused stopped lines args services 85 | 86 | docker_status=$(docker ps > /dev/null 2>&1) 87 | if [ $? -ne 0 ]; then 88 | _message "Error! Docker is not running." 89 | return 1 90 | fi 91 | 92 | kind=$1 93 | shift 94 | [[ $kind =~ (stopped|all) ]] && args=($args -a) 95 | 96 | lines=(${(f)"$(_call_program commands docker $docker_options ps $args)"}) 97 | services=(${(f)"$(_call_program commands docker-compose 2>/dev/null $compose_options ps -q)"}) 98 | 99 | # Parse header line to find columns 100 | local i=1 j=1 k header=${lines[1]} 101 | declare -A begin end 102 | while (( j < ${#header} - 1 )); do 103 | i=$(( j + ${${header[$j,-1]}[(i)[^ ]]} - 1 )) 104 | j=$(( i + ${${header[$i,-1]}[(i) ]} - 1 )) 105 | k=$(( j + ${${header[$j,-1]}[(i)[^ ]]} - 2 )) 106 | begin[${header[$i,$((j-1))]}]=$i 107 | end[${header[$i,$((j-1))]}]=$k 108 | done 109 | lines=(${lines[2,-1]}) 110 | 111 | # Container ID 112 | local line s name 113 | local -a names 114 | for line in $lines; do 115 | if [[ ${services[@]} == *"${line[${begin[CONTAINER ID]},${end[CONTAINER ID]}]%% ##}"* ]]; then 116 | names=(${(ps:,:)${${line[${begin[NAMES]},-1]}%% *}}) 117 | for name in $names; do 118 | s="${${name%_*}#*_}:${(l:15:: :::)${${line[${begin[CREATED]},${end[CREATED]}]/ ago/}%% ##}}" 119 | s="$s, ${line[${begin[CONTAINER ID]},${end[CONTAINER ID]}]%% ##}" 120 | s="$s, ${${${line[${begin[IMAGE]},${end[IMAGE]}]}/:/\\:}%% ##}" 121 | if [[ ${line[${begin[STATUS]},${end[STATUS]}]} = Exit* ]]; then 122 | stopped=($stopped $s) 123 | else 124 | if [[ ${line[${begin[STATUS]},${end[STATUS]}]} = *\(Paused\)* ]]; then 125 | paused=($paused $s) 126 | fi 127 | running=($running $s) 128 | fi 129 | done 130 | fi 131 | done 132 | 133 | [[ $kind =~ (running|all) ]] && _describe -t services-running "running services" running "$@" && ret=0 134 | [[ $kind =~ (paused|all) ]] && _describe -t services-paused "paused services" paused "$@" && ret=0 135 | [[ $kind =~ (stopped|all) ]] && _describe -t services-stopped "stopped services" stopped "$@" && ret=0 136 | 137 | return ret 138 | } 139 | 140 | __docker-compose_pausedservices() { 141 | [[ $PREFIX = -* ]] && return 1 142 | __docker-compose_get_services paused "$@" 143 | } 144 | 145 | __docker-compose_stoppedservices() { 146 | [[ $PREFIX = -* ]] && return 1 147 | __docker-compose_get_services stopped "$@" 148 | } 149 | 150 | __docker-compose_runningservices() { 151 | [[ $PREFIX = -* ]] && return 1 152 | __docker-compose_get_services running "$@" 153 | } 154 | 155 | __docker-compose_services() { 156 | [[ $PREFIX = -* ]] && return 1 157 | __docker-compose_get_services all "$@" 158 | } 159 | 160 | __docker-compose_caching_policy() { 161 | oldp=( "$1"(Nmh+1) ) # 1 hour 162 | (( $#oldp )) 163 | } 164 | 165 | __docker-compose_commands() { 166 | local cache_policy 167 | 168 | zstyle -s ":completion:${curcontext}:" cache-policy cache_policy 169 | if [[ -z "$cache_policy" ]]; then 170 | zstyle ":completion:${curcontext}:" cache-policy __docker-compose_caching_policy 171 | fi 172 | 173 | if ( [[ ${+_docker_compose_subcommands} -eq 0 ]] || _cache_invalid docker_compose_subcommands) \ 174 | && ! _retrieve_cache docker_compose_subcommands; 175 | then 176 | local -a lines 177 | lines=(${(f)"$(_call_program commands docker-compose 2>&1)"}) 178 | _docker_compose_subcommands=(${${${lines[$((${lines[(i)Commands:]} + 1)),${lines[(I) *]}]}## #}/ ##/:}) 179 | (( $#_docker_compose_subcommands > 0 )) && _store_cache docker_compose_subcommands _docker_compose_subcommands 180 | fi 181 | _describe -t docker-compose-commands "docker-compose command" _docker_compose_subcommands 182 | } 183 | 184 | __docker-compose_subcommand() { 185 | local opts_help opts_force_recreate opts_no_recreate opts_no_build opts_remove_orphans opts_timeout opts_no_color opts_no_deps 186 | 187 | opts_help='(: -)--help[Print usage]' 188 | opts_force_recreate="(--no-recreate)--force-recreate[Recreate containers even if their configuration and image haven't changed. Incompatible with --no-recreate.]" 189 | opts_no_recreate="(--force-recreate)--no-recreate[If containers already exist, don't recreate them. Incompatible with --force-recreate.]" 190 | opts_no_build="(--build)--no-build[Don't build an image, even if it's missing.]" 191 | opts_remove_orphans="--remove-orphans[Remove containers for services not defined in the Compose file]" 192 | opts_timeout=('(-t --timeout)'{-t,--timeout}"[Specify a shutdown timeout in seconds. (default: 10)]:seconds: ") 193 | opts_no_color='--no-color[Produce monochrome output.]' 194 | opts_no_deps="--no-deps[Don't start linked services.]" 195 | 196 | integer ret=1 197 | 198 | case "$words[1]" in 199 | (build) 200 | _arguments \ 201 | $opts_help \ 202 | '--force-rm[Always remove intermediate containers.]' \ 203 | '--no-cache[Do not use cache when building the image.]' \ 204 | '--pull[Always attempt to pull a newer version of the image.]' \ 205 | '*:services:__docker-compose_services_from_build' && ret=0 206 | ;; 207 | (bundle) 208 | _arguments \ 209 | $opts_help \ 210 | '--push-images[Automatically push images for any services which have a `build` option specified.]' \ 211 | '(--output -o)'{--output,-o}'[Path to write the bundle file to. Defaults to ".dab".]:file:_files' && ret=0 212 | ;; 213 | (config) 214 | _arguments \ 215 | $opts_help \ 216 | '(--quiet -q)'{--quiet,-q}"[Only validate the configuration, don't print anything.]" \ 217 | '--services[Print the service names, one per line.]' && ret=0 218 | ;; 219 | (create) 220 | _arguments \ 221 | $opts_help \ 222 | $opts_force_recreate \ 223 | $opts_no_recreate \ 224 | $opts_no_build \ 225 | "(--no-build)--build[Build images before creating containers.]" \ 226 | '*:services:__docker-compose_services_all' && ret=0 227 | ;; 228 | (down) 229 | _arguments \ 230 | $opts_help \ 231 | "--rmi[Remove images. Type must be one of: 'all': Remove all images used by any service. 'local': Remove only images that don't have a custom tag set by the \`image\` field.]:type:(all local)" \ 232 | '(-v --volumes)'{-v,--volumes}"[Remove named volumes declared in the \`volumes\` section of the Compose file and anonymous volumes attached to containers.]" \ 233 | $opts_remove_orphans && ret=0 234 | ;; 235 | (events) 236 | _arguments \ 237 | $opts_help \ 238 | '--json[Output events as a stream of json objects]' \ 239 | '*:services:__docker-compose_services_all' && ret=0 240 | ;; 241 | (exec) 242 | _arguments \ 243 | $opts_help \ 244 | '-d[Detached mode: Run command in the background.]' \ 245 | '--privileged[Give extended privileges to the process.]' \ 246 | '--user=[Run the command as this user.]:username:_users' \ 247 | '-T[Disable pseudo-tty allocation. By default `docker-compose exec` allocates a TTY.]' \ 248 | '--index=[Index of the container if there are multiple instances of a service \[default: 1\]]:index: ' \ 249 | '(-):running services:__docker-compose_runningservices' \ 250 | '(-):command: _command_names -e' \ 251 | '*::arguments: _normal' && ret=0 252 | ;; 253 | (help) 254 | _arguments ':subcommand:__docker-compose_commands' && ret=0 255 | ;; 256 | (kill) 257 | _arguments \ 258 | $opts_help \ 259 | '-s[SIGNAL to send to the container. Default signal is SIGKILL.]:signal:_signals' \ 260 | '*:running services:__docker-compose_runningservices' && ret=0 261 | ;; 262 | (logs) 263 | _arguments \ 264 | $opts_help \ 265 | '(-f --follow)'{-f,--follow}'[Follow log output]' \ 266 | $opts_no_color \ 267 | '--tail=[Number of lines to show from the end of the logs for each container.]:number of lines: ' \ 268 | '(-t --timestamps)'{-t,--timestamps}'[Show timestamps]' \ 269 | '*:services:__docker-compose_services_all' && ret=0 270 | ;; 271 | (pause) 272 | _arguments \ 273 | $opts_help \ 274 | '*:running services:__docker-compose_runningservices' && ret=0 275 | ;; 276 | (port) 277 | _arguments \ 278 | $opts_help \ 279 | '--protocol=[tcp or udp \[default: tcp\]]:protocol:(tcp udp)' \ 280 | '--index=[index of the container if there are multiple instances of a service \[default: 1\]]:index: ' \ 281 | '1:running services:__docker-compose_runningservices' \ 282 | '2:port:_ports' && ret=0 283 | ;; 284 | (ps) 285 | _arguments \ 286 | $opts_help \ 287 | '-q[Only display IDs]' \ 288 | '*:services:__docker-compose_services_all' && ret=0 289 | ;; 290 | (pull) 291 | _arguments \ 292 | $opts_help \ 293 | '--ignore-pull-failures[Pull what it can and ignores images with pull failures.]' \ 294 | '*:services:__docker-compose_services_from_image' && ret=0 295 | ;; 296 | (push) 297 | _arguments \ 298 | $opts_help \ 299 | '--ignore-push-failures[Push what it can and ignores images with push failures.]' \ 300 | '*:services:__docker-compose_services' && ret=0 301 | ;; 302 | (rm) 303 | _arguments \ 304 | $opts_help \ 305 | '(-f --force)'{-f,--force}"[Don't ask to confirm removal]" \ 306 | '-v[Remove any anonymous volumes attached to containers]' \ 307 | '*:stopped services:__docker-compose_stoppedservices' && ret=0 308 | ;; 309 | (run) 310 | _arguments \ 311 | $opts_help \ 312 | '-d[Detached mode: Run container in the background, print new container name.]' \ 313 | '*-e[KEY=VAL Set an environment variable (can be used multiple times)]:environment variable KEY=VAL: ' \ 314 | '--entrypoint[Overwrite the entrypoint of the image.]:entry point: ' \ 315 | '--name=[Assign a name to the container]:name: ' \ 316 | $opts_no_deps \ 317 | '(-p --publish)'{-p,--publish=}"[Publish a container's port(s) to the host]" \ 318 | '--rm[Remove container after run. Ignored in detached mode.]' \ 319 | "--service-ports[Run command with the service's ports enabled and mapped to the host.]" \ 320 | '-T[Disable pseudo-tty allocation. By default `docker-compose run` allocates a TTY.]' \ 321 | '(-u --user)'{-u,--user=}'[Run as specified username or uid]:username or uid:_users' \ 322 | '(-w --workdir)'{-w,--workdir=}'[Working directory inside the container]:workdir: ' \ 323 | '(-):services:__docker-compose_services' \ 324 | '(-):command: _command_names -e' \ 325 | '*::arguments: _normal' && ret=0 326 | ;; 327 | (scale) 328 | _arguments \ 329 | $opts_help \ 330 | $opts_timeout \ 331 | '*:running services:__docker-compose_runningservices' && ret=0 332 | ;; 333 | (start) 334 | _arguments \ 335 | $opts_help \ 336 | '*:stopped services:__docker-compose_stoppedservices' && ret=0 337 | ;; 338 | (stop|restart) 339 | _arguments \ 340 | $opts_help \ 341 | $opts_timeout \ 342 | '*:running services:__docker-compose_runningservices' && ret=0 343 | ;; 344 | (unpause) 345 | _arguments \ 346 | $opts_help \ 347 | '*:paused services:__docker-compose_pausedservices' && ret=0 348 | ;; 349 | (up) 350 | _arguments \ 351 | $opts_help \ 352 | '(--abort-on-container-exit)-d[Detached mode: Run containers in the background, print new container names. Incompatible with --abort-on-container-exit.]' \ 353 | $opts_no_color \ 354 | $opts_no_deps \ 355 | $opts_force_recreate \ 356 | $opts_no_recreate \ 357 | $opts_no_build \ 358 | "(--no-build)--build[Build images before starting containers.]" \ 359 | "(-d)--abort-on-container-exit[Stops all containers if any container was stopped. Incompatible with -d.]" \ 360 | '(-t --timeout)'{-t,--timeout}"[Use this timeout in seconds for container shutdown when attached or when containers are already running. (default: 10)]:seconds: " \ 361 | $opts_remove_orphans \ 362 | '*:services:__docker-compose_services_all' && ret=0 363 | ;; 364 | (version) 365 | _arguments \ 366 | $opts_help \ 367 | "--short[Shows only Compose's version number.]" && ret=0 368 | ;; 369 | (*) 370 | _message 'Unknown sub command' && ret=1 371 | ;; 372 | esac 373 | 374 | return ret 375 | } 376 | 377 | _docker-compose() { 378 | # Support for subservices, which allows for `compdef _docker docker-shell=_docker_containers`. 379 | # Based on /usr/share/zsh/functions/Completion/Unix/_git without support for `ret`. 380 | if [[ $service != docker-compose ]]; then 381 | _call_function - _$service 382 | return 383 | fi 384 | 385 | local curcontext="$curcontext" state line 386 | integer ret=1 387 | typeset -A opt_args 388 | 389 | _arguments -C \ 390 | '(- :)'{-h,--help}'[Get help]' \ 391 | '(-f --file)'{-f,--file}'[Specify an alternate docker-compose file (default: docker-compose.yml)]:file:_files -g "*.yml"' \ 392 | '(-p --project-name)'{-p,--project-name}'[Specify an alternate project name (default: directory name)]:project name:' \ 393 | '--verbose[Show more output]' \ 394 | '(- :)'{-v,--version}'[Print version and exit]' \ 395 | '(-H --host)'{-H,--host}'[Daemon socket to connect to]:host:' \ 396 | '--tls[Use TLS; implied by --tlsverify]' \ 397 | '--tlscacert=[Trust certs signed only by this CA]:ca path:' \ 398 | '--tlscert=[Path to TLS certificate file]:client cert path:' \ 399 | '--tlskey=[Path to TLS key file]:tls key path:' \ 400 | '--tlsverify[Use TLS and verify the remote]' \ 401 | "--skip-hostname-check[Don't check the daemon's hostname against the name specified in the client certificate (for example if your docker host is an IP address)]" \ 402 | '(-): :->command' \ 403 | '(-)*:: :->option-or-argument' && ret=0 404 | 405 | local -a relevant_compose_flags relevant_docker_flags compose_options docker_options 406 | 407 | relevant_compose_flags=( 408 | "--file" "-f" 409 | "--host" "-H" 410 | "--project-name" "-p" 411 | "--tls" 412 | "--tlscacert" 413 | "--tlscert" 414 | "--tlskey" 415 | "--tlsverify" 416 | "--skip-hostname-check" 417 | ) 418 | 419 | relevant_docker_flags=( 420 | "--host" "-H" 421 | "--tls" 422 | "--tlscacert" 423 | "--tlscert" 424 | "--tlskey" 425 | "--tlsverify" 426 | ) 427 | 428 | for k in "${(@k)opt_args}"; do 429 | if [[ -n "${relevant_docker_flags[(r)$k]}" ]]; then 430 | docker_options+=$k 431 | if [[ -n "$opt_args[$k]" ]]; then 432 | docker_options+=$opt_args[$k] 433 | fi 434 | fi 435 | if [[ -n "${relevant_compose_flags[(r)$k]}" ]]; then 436 | compose_options+=$k 437 | if [[ -n "$opt_args[$k]" ]]; then 438 | compose_options+=$opt_args[$k] 439 | fi 440 | fi 441 | done 442 | 443 | case $state in 444 | (command) 445 | __docker-compose_commands && ret=0 446 | ;; 447 | (option-or-argument) 448 | curcontext=${curcontext%:*:*}:docker-compose-$words[1]: 449 | __docker-compose_subcommand && ret=0 450 | ;; 451 | esac 452 | 453 | return ret 454 | } 455 | 456 | _docker-compose "$@" 457 | -------------------------------------------------------------------------------- /roles/docker/aliases.zsh: -------------------------------------------------------------------------------- 1 | alias d="docker " 2 | alias dlog="docker logs -f --tail 100 " 3 | alias dl="docker logs -f --tail 100 " 4 | alias ddf="docker system df" 5 | # Stop and remove a single container 6 | alias drm='docker rm -f ' 7 | # Stop and remove all running containers 8 | alias drm!='docker rm -f $(docker ps -a -q)' 9 | 10 | alias dc="docker compose" 11 | alias dcup="docker compose up -d " 12 | alias dcrun="docker compose run --rm " 13 | function dcdebug { 14 | docker compose kill $1 15 | docker compose run --service-ports $1 16 | } 17 | # Stop and recreate a container 18 | alias dcre="docker compose up -d --force-recreate --no-deps " 19 | alias dcl="docker compose logs -f --tail 100 " 20 | 21 | alias dcbomb!="docker compose -f deploy/docker-compose.infra.yml down -v --remove-orphans >/dev/null 2>&1" 22 | 23 | # Open bash in a container. Pass docker-compose name 24 | function dcbash { 25 | docker compose exec $1 /bin/bash 26 | } 27 | 28 | # Open bash in a container. Pass container name 29 | function dbash { 30 | docker exec -it $1 /bin/bash 31 | } 32 | -------------------------------------------------------------------------------- /roles/eza/aliases.zsh: -------------------------------------------------------------------------------- 1 | alias ls=eza 2 | alias tree='eza --tree' 3 | -------------------------------------------------------------------------------- /roles/eza/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: Install eza with Homebrew 2 | homebrew: name=eza state=present 3 | when: ansible_os_family == "Darwin" 4 | -------------------------------------------------------------------------------- /roles/fzf/_env.zsh: -------------------------------------------------------------------------------- 1 | # Use rg to respect .gitignore 2 | export FZF_DEFAULT_COMMAND='rg -g ""' 3 | -------------------------------------------------------------------------------- /roles/fzf/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: Install fzf with Homebrew 2 | homebrew: name=fzf state=present 3 | when: ansible_os_family == "Darwin" 4 | -------------------------------------------------------------------------------- /roles/git/README.md: -------------------------------------------------------------------------------- 1 | # git 2 | 3 | Installs and configures git. 4 | -------------------------------------------------------------------------------- /roles/git/aliases.zsh: -------------------------------------------------------------------------------- 1 | alias g="git" 2 | # Override gs from prezto 3 | alias gs="git status" 4 | alias ga="git add" 5 | alias gac="git add -A && git commit" 6 | -------------------------------------------------------------------------------- /roles/git/files/gitattributes_global.link: -------------------------------------------------------------------------------- 1 | # https://gist.github.com/tekin/12500956bd56784728e490d8cef9cb81 2 | *.c diff=cpp 3 | *.h diff=cpp 4 | *.c++ diff=cpp 5 | *.h++ diff=cpp 6 | *.cpp diff=cpp 7 | *.hpp diff=cpp 8 | *.cc diff=cpp 9 | *.hh diff=cpp 10 | *.m diff=objc 11 | *.mm diff=objc 12 | *.cs diff=csharp 13 | *.css diff=css 14 | *.html diff=html 15 | *.xhtml diff=html 16 | *.ex diff=elixir 17 | *.exs diff=elixir 18 | *.go diff=golang 19 | *.php diff=php 20 | *.pl diff=perl 21 | *.py diff=python 22 | *.md diff=markdown 23 | *.rb diff=ruby 24 | *.rake diff=ruby 25 | *.rs diff=rust 26 | *.lisp diff=lisp 27 | *.el diff=lisp 28 | -------------------------------------------------------------------------------- /roles/git/files/gitignore_global.link: -------------------------------------------------------------------------------- 1 | ########## Generated by gig 0.2.0 ########### 2 | 3 | ### macOS ### 4 | .DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | Icon 8 | 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear on external disk 14 | .Spotlight-V100 15 | .Trashes 16 | 17 | ### SublimeText ### 18 | # SublimeText project files 19 | *.sublime-workspace 20 | 21 | ## autoenv ## 22 | .env 23 | .autoenv 24 | .autoenv.zsh 25 | .ropeproject 26 | 27 | .ipynb_checkpoints 28 | 29 | .xmark.* 30 | 31 | 32 | # throwaway code 33 | .scratch 34 | 35 | # vim session 36 | .session 37 | 38 | # project-specific vimrc 39 | .vimrc 40 | 41 | # local konchrc files 42 | .konchrc.local 43 | 44 | .testmondata 45 | 46 | ## VS code 47 | .vscode 48 | 49 | ## mise 50 | 51 | # https://mise.jdx.dev/faq.html#i-don-t-want-to-put-a-mise-toml-tool-versions-file-into-my-project-since-git-shows-it-as-an-untracked-file 52 | mise.local.toml 53 | 54 | .aider* 55 | -------------------------------------------------------------------------------- /roles/git/tasks/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | ci: 2 | autoupdate_schedule: monthly 3 | repos: 4 | - repo: https://github.com/rbubley/mirrors-prettier 5 | rev: v3.4.2 6 | hooks: 7 | - id: prettier 8 | types: [yaml, markdown] 9 | -------------------------------------------------------------------------------- /roles/git/tasks/debian.yml: -------------------------------------------------------------------------------- 1 | - name: Install git with apt 2 | apt: name=git state=present 3 | become_method: sudo 4 | -------------------------------------------------------------------------------- /roles/git/tasks/mac.yml: -------------------------------------------------------------------------------- 1 | - name: Install git with Homebrew 2 | homebrew: name=git state=present 3 | -------------------------------------------------------------------------------- /roles/git/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - import_tasks: mac.yml 2 | when: ansible_os_family == "Darwin" 3 | - import_tasks: debian.yml 4 | when: ansible_os_family == "Debian" 5 | - import_tasks: redhat.yml 6 | when: ansible_os_family == "RedHat" 7 | 8 | - name: Link global gitignore file 9 | file: 10 | src: "{{ dotfiles_home }}/roles/git/files/gitignore_global.link" 11 | dest: "{{ dotfiles_user_home }}/.gitignore_global" 12 | state: link 13 | force: yes 14 | 15 | - name: Link gitattributes file 16 | file: 17 | src: "{{ dotfiles_home }}/roles/git/files/gitattributes_global.link" 18 | dest: "{{ dotfiles_user_home }}/.gitattributes_global" 19 | state: link 20 | force: yes 21 | 22 | - name: Check if gitconfig exists 23 | stat: path="{{dotfiles_user_home}}/.gitconfig" 24 | register: gitconfig_stat 25 | 26 | - name: Back up gitconfig 27 | command: mv ~/.gitconfig ~/.gitconfig.bak 28 | args: 29 | creates: "{{dotfiles_user_home}}/.gitconfig.bak" 30 | when: gitconfig_stat.stat.exists 31 | 32 | - name: Make sure gitconfig is up to date 33 | template: 34 | src: "gitconfig.j2" 35 | dest: "{{dotfiles_user_home}}/.gitconfig" 36 | -------------------------------------------------------------------------------- /roles/git/tasks/redhat.yml: -------------------------------------------------------------------------------- 1 | - name: Install git with yum 2 | yum: name=git state=present 3 | become_method: sudo 4 | -------------------------------------------------------------------------------- /roles/git/templates/gitconfig.j2: -------------------------------------------------------------------------------- 1 | [user] 2 | name = {{ full_name }} 3 | email = {{ git_email }} 4 | {% if ansible_os_family == 'Darwin' %} 5 | [credential] 6 | helper = osxkeychain 7 | {% endif %} 8 | [alias] 9 | a = add 10 | ac = !git add -A && git commit 11 | s = status 12 | st = stash 13 | co = checkout 14 | cob = checkout -b 15 | cp = cherry-pick 16 | c = checkout 17 | ci = commit 18 | noff = merge --no-ff 19 | l = log --graph --decorate --oneline --abbrev-commit --all 20 | h = log --graph --decorate --oneline --abbrev-commit 21 | plr = pull --rebase 22 | amend = commit --amend 23 | wip = !git add -A && git commit -m "WIP" --no-verify 24 | br = branch 25 | rn = branch -m 26 | delete-tag="!f() { git push --delete ${2-origin} ${1}; git tag -d ${1}; }; f" 27 | up = !git pull --rebase --prune $@ && git submodule update --init --recursive 28 | 29 | # diff-so-fancy 30 | # https://github.com/so-fancy/diff-so-fancy/#usage 31 | df = "!f() { [ -z \"$GIT_PREFIX\" ] || cd \"$GIT_PREFIX\" && git diff --color \"$@\" | diff-so-fancy | less --tabs=4 -RFX; }; f" 32 | dfs = df --staged 33 | # Get changes for a single commit 34 | dfc = "!dfc() { git df $1^ $1; }; dfc" 35 | 36 | please = push --force-with-lease 37 | # publish current branch 38 | publish = "!f() { git push -u ${1:-origin} $(git rev-parse --abbrev-ref HEAD); }; f" 39 | pub = publish 40 | ship = "!f() { git add -A && git commit -m \"$1\" && git push; }; f" 41 | 42 | # Nukes a branch locally and on the origin remote. 43 | nuke = "!f() { git branch -D $1 && git push origin :$1; }; f" 44 | 45 | # Remove local branches that have been removed upstream 46 | cleanup = "!git fetch --all -p && git branch -vv | grep \": gone]\" | awk '{ print $1 }' | xargs -n 1 git branch -D" 47 | 48 | # Sync branches and cleanup local branches (depends on above alias) 49 | sup = "!gh repo sync && git checkout $(git remote show origin | grep 'HEAD branch' | sed 's/.*: //') && git cleanup" 50 | 51 | # http://gggritso.com/human-git-aliases 52 | unstage = reset -q HEAD -- 53 | uns = unstage 54 | discard = checkout -- 55 | dis = discard 56 | uncommit = reset --mixed HEAD~ 57 | unc = uncommit 58 | 59 | url = "!f() { sha=$(git rev-parse ${1:-HEAD}); gh browse $sha -n; }; f" 60 | 61 | # Copy current branch name to clipboard (macOS only) 62 | cb = "!git rev-parse --abbrev-ref HEAD | tr -d '\n' | pbcopy" 63 | 64 | # Slightly quicker way to credit an author on the latest commit. 65 | # Usage: git credit "Steven Loria" sloria1@gmail.com 66 | credit = "!f() { git commit --amend --author \"$1 <$2>\" -C HEAD }; f" 67 | 68 | # Set up your branch to track a remote branch. Assumes you mean `origin/$branch-name`. 69 | track = "!f() { branch=$(git rev-parse --abbrev-ref HEAD); git branch $branch --set-upstream-to origin/$branch }; f" 70 | 71 | [color] 72 | diff = auto 73 | status = auto 74 | branch = auto 75 | ui = true 76 | [core] 77 | excludesfile = ~/.gitignore_global 78 | attributesfile = ~/.gitattributes_global 79 | editor = vim 80 | [apply] 81 | whitespace = nowarn 82 | [mergetool] 83 | keepBackup = false 84 | [difftool] 85 | prompt = false 86 | [pull] 87 | rebase = true 88 | [push] 89 | autoSetupRemote = false 90 | [filter "lfs"] 91 | clean = git-lfs clean -- %f 92 | smudge = git-lfs smudge -- %f 93 | process = git-lfs filter-process 94 | required = true 95 | [github] 96 | user = {{ git_user }} 97 | 98 | [init] 99 | defaultBranch = main 100 | -------------------------------------------------------------------------------- /roles/gsed/path.zsh: -------------------------------------------------------------------------------- 1 | # Make sed point to gnu-sed 2 | export PATH="$(brew --prefix)/opt/gnu-sed/libexec/gnubin:$PATH" 3 | -------------------------------------------------------------------------------- /roles/gsed/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # gnu-sed is needed by all-repos 2 | # https://github.com/asottile/all-repos#all-repos-sed-options-expression-filenames 3 | - name: Install GNU sed with Homebrew 4 | homebrew: name=gnu-sed state=present 5 | when: ansible_os_family == "Darwin" 6 | -------------------------------------------------------------------------------- /roles/jrnl/README.md: -------------------------------------------------------------------------------- 1 | # jrnl 2 | 3 | Installs [jrnl](http://jrnl.sh/index.html), a command-line journalling app. 4 | -------------------------------------------------------------------------------- /roles/jrnl/files/jrnl.yaml: -------------------------------------------------------------------------------- 1 | colors: 2 | body: none 3 | date: none 4 | tags: none 5 | title: none 6 | default_hour: 9 7 | default_minute: 0 8 | editor: vim 9 | encrypt: false 10 | highlight: true 11 | indent_character: "|" 12 | journals: 13 | default: 14 | encrypt: true 15 | journal: ~/iCloud/journals/.journal.txt 16 | til: 17 | encrypt: false 18 | journal: ~/Dropbox/.til.txt 19 | work: 20 | encrypt: true 21 | journal: ~/iCloud/journals/.work.txt 22 | linewrap: 79 23 | tagsymbols: "@" 24 | template: false 25 | timeformat: "%Y-%m-%d %H:%M" 26 | version: v4.2.1 27 | -------------------------------------------------------------------------------- /roles/jrnl/meta/main.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - { role: python } 3 | -------------------------------------------------------------------------------- /roles/jrnl/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: Install jrnl with uv 2 | command: "uv tool install jrnl" 3 | # TODO: Make idempotent 4 | tags: 5 | - jrnl 6 | 7 | - name: Symlink jrnl config file 8 | file: 9 | src: "{{ dotfiles_home }}/roles/jrnl/files/jrnl.yaml" 10 | dest: "{{ dotfiles_user_home}}/.config/jrnl/jrnl.yaml" 11 | state: link 12 | tags: 13 | - jrnl 14 | -------------------------------------------------------------------------------- /roles/k9s/aliases.zsh: -------------------------------------------------------------------------------- 1 | alias k9s="EDITOR=vim k9s" 2 | -------------------------------------------------------------------------------- /roles/k9s/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: Install k9s with Homebrew 2 | homebrew: name=k9s state=present 3 | when: ansible_os_family == "Darwin" 4 | -------------------------------------------------------------------------------- /roles/kubernetes/aliases.zsh: -------------------------------------------------------------------------------- 1 | # Usage: kubewatch 2 | # kubewatch stage-3 3 | function kubewatch() { 4 | if [ $# -eq 0 ]; then 5 | watch -n 1 "kubectl get pods --all-namespaces" 6 | else 7 | watch -n 1 "kubectl get pods --all-namespaces | grep $1" 8 | fi 9 | } 10 | 11 | # Usage: kubepods 12 | # kubepods stage-3 13 | function kubepods() { 14 | if [ $# -eq 0 ]; then 15 | kubectl get pods --all-namespaces 16 | else 17 | kubectl get pods --all-namespaces | grep $1 18 | fi 19 | } 20 | 21 | # Usage: kubebash stage-3 web uwsgi 22 | # kubebash stage-3 postgres 23 | function kubebash() { 24 | namespace=$1 25 | namere=$2 26 | name=$(kubectl get pods -n $namespace | grep $namere | head -1 | grep -o '^\S\+') 27 | if [[ $# -gt 2 ]]; then 28 | container=$3 29 | echo 'Entering the' $container 'container on' $name 'in namespace' $namespace 30 | kubectl --namespace $namespace exec -it $name -c $container bash 31 | else 32 | echo 'Entering the default container on' $name 'in namespace' $namespace 33 | kubectl --namespace $namespace exec -it $name bash 34 | fi 35 | } 36 | 37 | # Usage: kubelogs stage-3 web uwsgi 38 | # kubelogs stage-3 postgres 39 | function kubelogs() { 40 | namespace=$1 41 | namere=$2 42 | name=$(kubectl get pods -n $namespace | grep $namere | head -1 | grep -o '^\S\+') 43 | if [[ $# -gt 2 ]]; then 44 | container=$3 45 | echo 'Tailing logs from the' $container 'container on' $name 'in namespace' $namespace 46 | kubectl --namespace $namespace logs -f --tail 100 $name -c $container 47 | else 48 | echo 'Tailing logs from the default container on' $name 'in namespace' $namespace 49 | kubectl --namespace $namespace logs -f --tail 100 $name 50 | fi 51 | } 52 | -------------------------------------------------------------------------------- /roles/kubernetes/tasks/mac.yml: -------------------------------------------------------------------------------- 1 | - name: Homebrew ensure kubernetes-cli installed 2 | homebrew: name=kubernetes-cli state=present 3 | -------------------------------------------------------------------------------- /roles/kubernetes/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - import_tasks: mac.yml 2 | when: ansible_os_family == "Darwin" 3 | -------------------------------------------------------------------------------- /roles/lctl/_lctl: -------------------------------------------------------------------------------- 1 | #compdef lctl 2 | 3 | _lctl() { 4 | local -a commands agents short_agents 5 | 6 | commands=( 7 | 'cat:Display contents' 8 | 'edit:Edit file' 9 | 'file:Show file' 10 | 'listdisabled:List disabled agents' 11 | 'log:Show log' 12 | 'logfiles:Show log files' 13 | 'reload:Reload agent' 14 | 'tail:Tail log' 15 | 'bootout:Boot out agent' 16 | 'bootstrap:Bootstrap agent' 17 | 'disable:Disable agent' 18 | 'enable:Enable agent' 19 | 'kickstart:Kickstart agent' 20 | 'kill:Kill agent' 21 | 'list:List agents' 22 | 'print:Print information' 23 | ) 24 | 25 | _arguments -C \ 26 | '1: :->cmds' \ 27 | '2: :->args' && return 0 28 | 29 | case "$state" in 30 | cmds) 31 | _describe -t commands 'commands' commands 32 | ;; 33 | args) 34 | case $words[2] in 35 | listdisabled) 36 | return 0 37 | ;; 38 | *) 39 | agents=($HOME/Library/LaunchAgents/*.plist(:t:r)) 40 | short_agents=() 41 | 42 | for agent in $agents; do 43 | short_agents+=${agent#*.*.} 44 | done 45 | 46 | if [[ -n "$PREFIX" ]]; then 47 | short_agents+=($agents) 48 | fi 49 | 50 | _values 'agents' $short_agents 51 | ;; 52 | esac 53 | ;; 54 | esac 55 | } 56 | 57 | _lctl "$@" 58 | -------------------------------------------------------------------------------- /roles/lctl/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: Download lctl to ~/.local/bin/lctl 2 | get_url: 3 | url: https://raw.githubusercontent.com/newtonne/lctl/refs/heads/master/lctl.sh 4 | dest: "{{ dotfiles_user_home }}/.local/bin/lctl" 5 | mode: "0755" 6 | -------------------------------------------------------------------------------- /roles/macos/aliases.zsh: -------------------------------------------------------------------------------- 1 | # sha56 - get the sha256 hash of a file 2 | function sha256() { 3 | shasum -a 256 $1 | head -1 | grep -o '^\S\+' 4 | } 5 | 6 | # b64 - base64 encode a file 7 | function b64() { 8 | cat $1 | openssl base64 | tr -d '\n'; 9 | } 10 | -------------------------------------------------------------------------------- /roles/macos/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | icloud_enabled: false 3 | mac_mas_packages: [] 4 | -------------------------------------------------------------------------------- /roles/macos/files/set-defaults.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # set reasonable macOS defaults 4 | # inspired by : https://github.com/mathiasbynens/dotfiles 5 | # more can be found here : https://gist.github.com/brandonb927/3195465 6 | 7 | if [ "$(uname -s)" != "Darwin" ]; then 8 | exit 0 9 | fi 10 | 11 | set +e 12 | 13 | echo " › Use AirDrop over every interface. srsly this should be a default." 14 | defaults write com.apple.NetworkBrowser BrowseAllInterfaces 1 15 | 16 | echo " › show the ~/Library folder" 17 | chflags nohidden ~/Library 18 | 19 | echo " › disable smart quotes and smart dashes as they're annoying when typing code" 20 | defaults write NSGlobalDomain NSAutomaticQuoteSubstitutionEnabled -bool false 21 | defaults write NSGlobalDomain NSAutomaticDashSubstitutionEnabled -bool false 22 | 23 | echo " › Show path bar" 24 | defaults write com.apple.finder ShowPathbar -bool true 25 | 26 | echo " › Autohide Dock" 27 | defaults write com.apple.dock autohide -bool true && killall Dock 28 | 29 | echo " › Enable key repeat in VSCodeVim" 30 | defaults write com.microsoft.VSCode ApplePressAndHoldEnabled -bool false 31 | -------------------------------------------------------------------------------- /roles/macos/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: Set system defaults 2 | script: set-defaults.sh 3 | changed_when: false 4 | 5 | - name: Ensure iCloud Drive is linked to ~/iCloud 6 | file: 7 | src: "{{dotfiles_user_home}}/Library/Mobile Documents/com~apple~CloudDocs" 8 | dest: "{{dotfiles_user_home}}/iCloud" 9 | state: link 10 | when: icloud_enabled|bool 11 | 12 | - name: Install mac-specific homebrew packages 13 | homebrew: name={{item}} state=present 14 | with_items: "{{mac_homebrew_packages}}" 15 | 16 | - name: Install Mac apps with homebrew cask 17 | homebrew_cask: name={{item}} state=present 18 | with_items: "{{mac_cask_packages}}" 19 | 20 | - name: Install mas 21 | homebrew: name=mas state=present 22 | when: mac_mas_packages|length > 0 23 | tags: mas 24 | 25 | - name: Install Mac-App-Store-only apps with mas 26 | command: mas install {{item.id}} 27 | args: 28 | creates: "/Applications/{{item.name}}.app" 29 | with_items: "{{mac_mas_packages}}" 30 | when: mac_mas_packages|length > 0 31 | tags: mas 32 | -------------------------------------------------------------------------------- /roles/mise/README.md: -------------------------------------------------------------------------------- 1 | # mise 2 | 3 | Installs [mise](https://mise.jdx.dev/) 4 | for managing project specific node versions, installing project-specific CLIs, 5 | and [running tasks](https://mise.jdx.dev/tasks/). 6 | -------------------------------------------------------------------------------- /roles/mise/activate.zsh: -------------------------------------------------------------------------------- 1 | eval "$(mise activate zsh)" 2 | -------------------------------------------------------------------------------- /roles/mise/files/config.toml: -------------------------------------------------------------------------------- 1 | [tools] 2 | node = "22" 3 | 4 | [settings] 5 | idiomatic_version_file_enable_tools = ["node"] 6 | -------------------------------------------------------------------------------- /roles/mise/files/config.toml.link: -------------------------------------------------------------------------------- 1 | [settings] 2 | idiomatic_version_file_enable_tools = ["node"] 3 | -------------------------------------------------------------------------------- /roles/mise/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: Install mise with homebrew 2 | homebrew: name=mise state=present 3 | 4 | - name: Create mise config directory 5 | file: 6 | path: "{{ '~/.config/mise' | expanduser }}" 7 | state: directory 8 | mode: '0755' 9 | 10 | - name: Copy mise config file 11 | copy: 12 | src: "{{ dotfiles_home }}/roles/mise/files/config.toml" 13 | dest: "{{ '~/.config/mise/config.toml' | expanduser }}" 14 | -------------------------------------------------------------------------------- /roles/ollama/README.md: -------------------------------------------------------------------------------- 1 | # ollama 2 | 3 | Install ollama and run it via launchd 4 | 5 | Finding the pid: 6 | 7 | ``` 8 | launchctl list | rg ollama 9 | ``` 10 | 11 | Tailing logs: 12 | 13 | ``` 14 | tail -f /opt/homebrew/var/log/ollama.log 15 | ``` 16 | 17 | # updating 18 | 19 | ``` 20 | brew upgrade ollama 21 | ``` 22 | -------------------------------------------------------------------------------- /roles/ollama/_env.zsh: -------------------------------------------------------------------------------- 1 | export OLLAMA_HOST=0.0.0.0 2 | -------------------------------------------------------------------------------- /roles/ollama/files/com.sloria.ollama.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | KeepAlive 6 | 7 | Label 8 | 9 | com.sloria.ollama 10 | LimitLoadToSessionType 11 | 12 | Aqua 13 | Background 14 | LoginWindow 15 | StandardIO 16 | System 17 | 18 | ProgramArguments 19 | 20 | /opt/homebrew/opt/ollama/bin/ollama 21 | serve 22 | 23 | 24 | EnvironmentVariables 25 | 26 | OLLAMA_HOST 27 | 0.0.0.0 28 | OLLAMA_CONTEXT_LENGTH 29 | 32768 30 | 31 | RunAtLoad 32 | 33 | StandardErrorPath 34 | /opt/homebrew/var/log/ollama.log 35 | StandardOutPath 36 | /opt/homebrew/var/log/ollama.log 37 | WorkingDirectory 38 | /opt/homebrew/var 39 | 40 | 41 | -------------------------------------------------------------------------------- /roles/ollama/tasks/mac.yml: -------------------------------------------------------------------------------- 1 | - name: Install ollama with Homebrew 2 | homebrew: name=ollama state=present 3 | 4 | # XXX: Can't use brew services start ollama 5 | # because it doesn't set OLLAMA_HOST 6 | # https://github.com/ollama/ollama/issues/3581 7 | - name: Symlink plist file to ~/Library/LaunchAgents 8 | file: 9 | src: "{{ dotfiles_home }}/roles/ollama/files/com.sloria.ollama.plist" 10 | dest: "{{ dotfiles_user_home }}/Library/LaunchAgents/com.sloria.ollama.plist" 11 | state: link 12 | 13 | - name: Load ollama service with launchctl 14 | command: launchctl load ~/Library/LaunchAgents/com.sloria.ollama.plist 15 | -------------------------------------------------------------------------------- /roles/ollama/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - import_tasks: mac.yml 2 | when: ansible_os_family == "Darwin" 3 | 4 | # NOTE: Not truly idempotent 5 | - name: Pull ollama models 6 | command: ollama pull {{ item }} 7 | with_items: "{{ ollama_models }}" 8 | -------------------------------------------------------------------------------- /roles/package_manager/README.md: -------------------------------------------------------------------------------- 1 | # Package Managers 2 | 3 | Updates package manager repositories and upgrades all installed packages. 4 | -------------------------------------------------------------------------------- /roles/package_manager/defaults/main.yml: -------------------------------------------------------------------------------- 1 | package_update: yes 2 | package_upgrade: yes 3 | -------------------------------------------------------------------------------- /roles/package_manager/tasks/debian.yml: -------------------------------------------------------------------------------- 1 | - name: Update apt cache 2 | apt: update_cache=yes 3 | when: package_update 4 | 5 | - name: Upgrade apt packages 6 | apt: upgrade=yes 7 | when: package_upgrade 8 | -------------------------------------------------------------------------------- /roles/package_manager/tasks/mac.yml: -------------------------------------------------------------------------------- 1 | - name: Update homebrew 2 | homebrew: update_homebrew=yes 3 | when: package_update 4 | 5 | - name: Upgrade homebrew packages 6 | homebrew: upgrade_all=yes 7 | when: package_upgrade 8 | -------------------------------------------------------------------------------- /roles/package_manager/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - import_tasks: redhat.yml 2 | when: ansible_os_family == "RedHat" 3 | 4 | - import_tasks: debian.yml 5 | when: ansible_os_family == "Debian" 6 | 7 | - import_tasks: mac.yml 8 | when: ansible_os_family == "Darwin" 9 | -------------------------------------------------------------------------------- /roles/package_manager/tasks/redhat.yml: -------------------------------------------------------------------------------- 1 | - name: Upgrade yum packages 2 | yum: name=* state=present 3 | when: package_upgrade 4 | -------------------------------------------------------------------------------- /roles/python/README.md: -------------------------------------------------------------------------------- 1 | # python 2 | 3 | Installs [uv](https://docs.astral.sh/uv/), which is used for managing python installation and packages. Also adds a number of helpful aliases and functions for developing in python. 4 | -------------------------------------------------------------------------------- /roles/python/_env.zsh: -------------------------------------------------------------------------------- 1 | export PYTHONBREAKPOINT=ipdb.set_trace 2 | -------------------------------------------------------------------------------- /roles/python/aliases.zsh: -------------------------------------------------------------------------------- 1 | alias py="python" 2 | alias ipy="ipython" 3 | alias serve="uvx --python 3.13 python -m http.server" 4 | alias pt="pytest" 5 | 6 | alias pipgrep="pip freeze | grep -i " 7 | 8 | alias mkcli="uv init --app --package" 9 | -------------------------------------------------------------------------------- /roles/python/completion.zsh: -------------------------------------------------------------------------------- 1 | # uv shell completion: https://docs.astral.sh/uv/getting-started/installation/#shell-autocompletion 2 | eval "$(uv generate-shell-completion zsh)" 3 | -------------------------------------------------------------------------------- /roles/python/final.zsh: -------------------------------------------------------------------------------- 1 | # For local tools/scripts 2 | export PATH="$HOME/.local/bin:$PATH" 3 | -------------------------------------------------------------------------------- /roles/python/functions.zsh: -------------------------------------------------------------------------------- 1 | # Remove python compiled byte-code in either current directory or in a 2 | # list of specified directories 3 | function pyclean() { 4 | ZSH_PYCLEAN_PLACES=${*:-'.'} 5 | find ${ZSH_PYCLEAN_PLACES} -type f -name "*.py[co]" -delete 6 | find ${ZSH_PYCLEAN_PLACES} -type d -name "__pycache__" -delete 7 | } 8 | 9 | # Generate fake data, e.g. `fake name`, `fake url`, `fake email` 10 | function fake() { 11 | result=$(PYTHONIOENCODING=UTF-8 uv tool run faker -s="" $1) 12 | echo -n "$result" 13 | } 14 | -------------------------------------------------------------------------------- /roles/python/tasks/mac.yml: -------------------------------------------------------------------------------- 1 | - name: Install uv 2 | homebrew: name=uv state=present 3 | -------------------------------------------------------------------------------- /roles/python/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - import_tasks: mac.yml 2 | when: ansible_os_family == "Darwin" 3 | -------------------------------------------------------------------------------- /roles/rg/README.md: -------------------------------------------------------------------------------- 1 | # ripgrep 2 | 3 | Installs [ripgrep](https://github.com/BurntSushi/ripgrep), a super-fast ag/grep/ack alternative. 4 | 5 | To add ripgrep in Debian or Ubuntu, make sure that the following variables reference the current ripgrep version. 6 | 7 | - rg_version 8 | - rg_dpkg_file 9 | -------------------------------------------------------------------------------- /roles/rg/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | rg_release_url: https://github.com/BurntSushi/ripgrep/releases/download 3 | rg_version: 0.10.0 4 | rg_dpkg_file: ripgrep_0.10.0_amd64.deb 5 | -------------------------------------------------------------------------------- /roles/rg/tasks/debian.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Check if ripgrep is installed 3 | command: dpkg-query -W ripgrep 4 | register: rg_check_deb 5 | failed_when: rg_check_deb.rc > 1 6 | changed_when: rg_check_deb.rc == 1 7 | 8 | - name: Install ripgrep with a .deb file 9 | apt: 10 | deb: "{{ rg_release_url }}/{{ rg_version }}/{{ rg_dpkg_file }}" 11 | become: yes 12 | become_user: root 13 | when: rg_check_deb.rc == 1 14 | 15 | - name: Check if ripgrep is up to date 16 | shell: rg --version | awk NR==1'{print $2}' 17 | register: rg_check_ver 18 | when: rg_check_deb.rc == 1 19 | 20 | - set_fact: rg_ver="{{ rg_check_ver }}" 21 | - set_fact: rg_installed_ver="{{ rg_version }}" 22 | 23 | - name: Update ripgrep 24 | apt: 25 | deb: "{{ rg_release_url }}/{{ rg_version }}/{{ rg_dpkg_file }}" 26 | become: yes 27 | become_user: root 28 | when: rg_ver != rg_installed_ver 29 | -------------------------------------------------------------------------------- /roles/rg/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - import_tasks: debian.yml 2 | when: ansible_os_family == "Debian" 3 | 4 | - name: Install ripgrep with homebrew 5 | homebrew: name=ripgrep state=present 6 | when: ansible_os_family == "Darwin" 7 | # TODO: RedHat 8 | -------------------------------------------------------------------------------- /roles/rust/path.zsh: -------------------------------------------------------------------------------- 1 | . "$HOME/.cargo/env" 2 | -------------------------------------------------------------------------------- /roles/rust/tasks/main.yml: -------------------------------------------------------------------------------- 1 | - name: Ensure rustup is installed 2 | command: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 3 | args: 4 | creates: "{{ dotfiles_user_home }}/.cargo/bin/rustup" 5 | -------------------------------------------------------------------------------- /roles/vim/README.md: -------------------------------------------------------------------------------- 1 | # vim 2 | 3 | Installs vim, [vim-plug](https://github.com/junegunn/vim-plug), and symlinks [.vimrc](https://github.com/sloria/dotfiles/blob/master/roles/vim/files/vimrc). 4 | 5 | ## Want to install without using ansible? 6 | 7 | See: https://github.com/sloria/dotfiles#what-if-i-only-want-your-vim 8 | 9 | ## Some useful bindings 10 | 11 | ### Essentials 12 | 13 | Leader is `Space`. 14 | 15 | - ``: Write file (who has time to type `:w`?). 16 | - ``: Quit. 17 | - ``: Vertical split. 18 | - ``: Go to file (default binding). 19 | - ``: Go to symbol (method, function, etc.) in file. 20 | - ``: Toggle comment. 21 | - ``: Open filebrowser. 22 | - `` and ``: Go to beginning/end of line. 23 | - ``: Open up vimrc. 24 | - ``: Select whole file. 25 | - ``: Move around windows. 26 | - `` (Backspace): Strip trailing whitespace. 27 | - `,`: Expand an [Emmet](http://emmet.io/) abbreviation (default binding) 28 | 29 | ### Search 30 | 31 | - `f`: Search current project (works with visual selection). 32 | - `n`: Search current word under cursor. 33 | - `t`: Toggle search window. 34 | 35 | ### Buffers 36 | 37 | - `[b` and `]b`: Previous/next buffer (default bindings of vim-unimpaired) 38 | - `X`: Delete current buffer without closing window. 39 | 40 | ### Running tests (Python, JS, Clojure, Ruby) 41 | 42 | - ``: Run nearest test. 43 | - ``: Run test file. 44 | - ``: Run last test. 45 | 46 | ### Linting 47 | 48 | - `[e` `]e`: Go to previous/next error. 49 | - ``: Open loclist, which contains list of lint errors. 50 | - ``: Format file (e.g. using `prettier` to format JS). 51 | 52 | ### IDE 53 | 54 | - `gd`: Go to definition. 55 | 56 | ### Git 57 | 58 | - ``: Open git status. 59 | - ``: git blame 60 | - ``: Stage hunk. 61 | - ``: Unstage hunk. 62 | - `]h` and `[h`: Go to next/previous hunk. 63 | - ``: git Browse (go to corresponding file or selected lines on GitHub) 64 | -------------------------------------------------------------------------------- /roles/vim/defaults/main.yml: -------------------------------------------------------------------------------- 1 | # NOTE: if this is false, you'll need to run :PluginInstall in vim to 2 | # install all plugins 3 | vim_install_plugins: no 4 | -------------------------------------------------------------------------------- /roles/vim/files/javascript.snippets: -------------------------------------------------------------------------------- 1 | 2 | snippet me "module.exports" b 3 | module.exports = $1; 4 | endsnippet 5 | 6 | snippet constr "constructor" b 7 | constructor() { 8 | super(); 9 | $0 10 | } 11 | endsnippet 12 | 13 | snippet ce "console.error" b 14 | console.error($1); 15 | endsnippet 16 | 17 | # ----------------------------------------------------------------------------- 18 | 19 | # Relay 20 | 21 | snippet irelay "import Relay" 22 | import { createFragmentContainer, graphql } from 'react-relay'; 23 | endsnippet 24 | 25 | snippet frag "GraphQL fragment" b 26 | ${1:thing}: graphql\` 27 | fragment `!v expand('%:t:r')`_$1 on ${2:`!p snip.rv = t[1].capitalize()`} { 28 | ${3:id} 29 | } 30 | \`, 31 | endsnippet 32 | 33 | snippet cfc "createFragmentContainer" b 34 | export default createFragmentContainer(`!v expand('%:t:r')`, { 35 | ${1:thing}: graphql\` 36 | fragment `!v expand('%:t:r')`_$1 on ${2:`!p snip.rv = t[1].capitalize()`} { 37 | ${3:id} 38 | } 39 | \`, 40 | }) 41 | endsnippet 42 | 43 | snippet relayboiler "Relay fragment container component with TS" b 44 | import React from 'react'; 45 | import { FormattedMessage } from 'react-intl'; 46 | 47 | import { createFragmentContainer, graphql } from 'react-relay'; 48 | import { $2_$1 as `!p snip.rv = t[1].capitalize()` } from './__generated__/$2_$1.graphql'; 49 | 50 | interface Props { 51 | $1: `!p snip.rv = t[1].capitalize()`; 52 | } 53 | 54 | function ${2:`!v expand('%:t:r')`}({ ${1:thing} }: Props) { 55 | return ( 56 |
57 | ${3:} 58 |
59 | ); 60 | } 61 | 62 | export default createFragmentContainer( 63 | $2, 64 | graphql\` 65 | fragment $2_$1 on `!p snip.rv = t[1].capitalize()` { 66 | id 67 | } 68 | \`, 69 | ); 70 | endsnippet 71 | 72 | snippet irt "Import relay type" 73 | import { `!p snip.rv = ''.join(x for x in re.sub('\.js$', '', snip.basename or 'ModuleName').split('_'))`_$1 as `!p snip.rv = t[1].capitalize()` } from './__generated__/`!p snip.rv = ''.join(x for x in re.sub('\.js$', '', snip.basename or 'ModuleName').split('_'))`_$1.graphql'; 74 | endsnippet 75 | 76 | snippet irprops "Relay type with props" 77 | import { `!p snip.rv = ''.join(x for x in re.sub('\.js$', '', snip.basename or 'ModuleName').split('_'))`_$1 as `!p snip.rv = t[1].capitalize()` } from './__generated__/`!p snip.rv = ''.join(x for x in re.sub('\.js$', '', snip.basename or 'ModuleName').split('_'))`_$1.graphql'; 78 | 79 | interface Props { 80 | $1: `!p snip.rv = t[1].capitalize()`; 81 | } 82 | endsnippet 83 | 84 | # ----------------------------------------------------------------------------- 85 | 86 | # react-intl 87 | 88 | snippet iintl "Import react-intl" 89 | import { FormattedMessage } from 'react-intl'; 90 | endsnippet 91 | 92 | snippet fm "FormattedMessage" 93 | 94 | endsnippet 95 | 96 | # ----------------------------------------------------------------------------- 97 | 98 | # React 99 | 100 | snippet ss "setState" b 101 | this.setState({ $1 }); 102 | endsnippet 103 | 104 | snippet ir "Import React" 105 | import React from "react"; 106 | endsnippet 107 | 108 | snippet ipt "Import prop-types" 109 | import t from "prop-types"; 110 | endsnippet 111 | 112 | snippet iprops "interface Props" 113 | interface Props { 114 | ${1:name}: ${2:type}; 115 | } 116 | endsnippet 117 | 118 | snippet rfc "React Functional Component" b 119 | const ${1:`!v expand('%:t:r')`} = (${2:{...props}}) => { 120 | return ( 121 |
122 | $3 123 |
124 | ); 125 | } 126 | $1.defaultProps = { 127 | }; 128 | $1.propTypes = { 129 | }; 130 | endsnippet 131 | 132 | snippet rfc! "React Functional Component (with imports)" b 133 | import React from "react"; 134 | import t from "prop-types"; 135 | 136 | const ${1:`!v expand('%:t:r')`} = (${2:{...props}}) => { 137 | return ( 138 |
139 | $3 140 |
141 | ); 142 | } 143 | $1.defaultProps = { 144 | }; 145 | $1.propTypes = { 146 | }; 147 | 148 | export default $1; 149 | endsnippet 150 | 151 | snippet rccc "createClass" b 152 | export const ${1:`!p snip.rv = ''.join(x for x in re.sub('\.js$', '', snip.basename or 'ModuleName').split('_'))`} = React.createClass({ 153 | render() { 154 | return ( 155 | $0 156 | ); 157 | } 158 | }); 159 | endsnippet 160 | 161 | snippet rcc "React.Component" b 162 | export default class ${1:`!p snip.rv = ''.join(x for x in re.sub('\.js$', '', snip.basename or 'ModuleName').split('_'))`} extends React.Component { 163 | render() { 164 | return ( 165 | $0 166 | ); 167 | } 168 | } 169 | endsnippet 170 | 171 | snippet importreact "import React" b 172 | import React from 'react'; 173 | import PropTypes as PT from 'prop-types'; 174 | endsnippet 175 | 176 | snippet cdm "componentDidMount" b 177 | componentDidMount() { 178 | $0 179 | } 180 | endsnippet 181 | 182 | snippet cdu "componentDidUpdate" b 183 | componentDidUpdate(prevProps, prevState) { 184 | $0 185 | } 186 | endsnippet 187 | 188 | snippet cwm "componentWillMount" b 189 | componentWillMount() { 190 | $0 191 | } 192 | endsnippet 193 | 194 | snippet cwrp "componentWillReceiveProps" b 195 | componentWillReceiveProps(nextProps) { 196 | $0 197 | } 198 | endsnippet 199 | 200 | snippet cwum "componentWillUnmount" b 201 | componentWillUnmount() { 202 | $0 203 | } 204 | endsnippet 205 | 206 | snippet cwu "componentWillUpdate" b 207 | componentWillUpdate(nextProps, nextState) { 208 | $0 209 | } 210 | endsnippet 211 | 212 | snippet gdp "getDefaultProps" b 213 | getDefaultProps() { 214 | return { 215 | $0 216 | }; 217 | } 218 | endsnippet 219 | 220 | snippet gis "getInitialState" b 221 | getInitialState() { 222 | return { 223 | $0 224 | }; 225 | } 226 | endsnippet 227 | 228 | snippet pt "propTypes" b 229 | static propTypes = { 230 | $0 231 | } 232 | endsnippet 233 | 234 | snippet scu "shouldComponentUpdate" b 235 | shouldComponentUpdate(nextProps, nextState) { 236 | return ${1:true}; 237 | } 238 | endsnippet 239 | 240 | # ----------------------------------------------------------------------------- 241 | 242 | # Mocha testing 243 | snippet desc 244 | describe('${1:feature}', () => { 245 | ${2} 246 | }); 247 | endsnippet 248 | 249 | snippet desca 250 | describe('${1:feature}', async () => { 251 | ${2} 252 | }); 253 | endsnippet 254 | 255 | snippet descf 256 | describe('${1:feature}', function() { 257 | ${2} 258 | }); 259 | endsnippet 260 | 261 | snippet it 262 | it('${1:should do something}', () => { 263 | ${2} 264 | }); 265 | endsnippet 266 | 267 | snippet ita 268 | it('${1:should do something}', async () => { 269 | ${2} 270 | }); 271 | endsnippet 272 | 273 | snippet itd 274 | it('${1:should do something}', (done) => { 275 | ${2} 276 | done(); 277 | }); 278 | endsnippet 279 | 280 | snippet itf 281 | it('${1:should do something}', function(done) { 282 | ${2} 283 | done() 284 | }); 285 | endsnippet 286 | 287 | snippet bef 288 | before(() => { 289 | ${1} 290 | }); 291 | endsnippet 292 | 293 | snippet beff 294 | before(function() { 295 | ${1} 296 | }); 297 | endsnippet 298 | 299 | snippet af 300 | after(() => { 301 | ${1} 302 | }); 303 | endsnippet 304 | 305 | snippet aff 306 | after(function() { 307 | ${1} 308 | }); 309 | endsnippet 310 | 311 | snippet befe 312 | beforeEach(() => { 313 | ${1} 314 | }); 315 | endsnippet 316 | 317 | snippet befef 318 | beforeEach(function() { 319 | ${1} 320 | }); 321 | endsnippet 322 | 323 | snippet afe 324 | afterEach(() => { 325 | ${1} 326 | }); 327 | endsnippet 328 | 329 | snippet afef 330 | afterEach(function() { 331 | ${1} 332 | }); 333 | endsnippet 334 | 335 | # ----------------------------------------------------------------------------- 336 | 337 | # Selenium testing 338 | 339 | snippet ats "await takeScreenshot" 340 | await takeScreenshot($1); 341 | endsnippet 342 | 343 | snippet asl "await browser.sleep" 344 | await browser.sleep(${1:200}); 345 | endsnippet 346 | 347 | snippet apr "await empty promise" 348 | await new Promise(() => {}); 349 | endsnippet 350 | -------------------------------------------------------------------------------- /roles/vim/files/python.snippets: -------------------------------------------------------------------------------- 1 | # Breakpoints 2 | # vim-snippets puts these on 2 lines. I prefer a single line. 3 | snippet pdb 4 | __import__("pdb").set_trace() 5 | endsnippet 6 | 7 | snippet ipdb 8 | __import__("ipdb").set_trace() 9 | endsnippet 10 | 11 | snippet lipdb 12 | from ipdb import launch_ipdb_on_exception 13 | with launch_ipdb_on_exception(): 14 | ${1} 15 | endsnippet 16 | 17 | snippet rdb 18 | from celery.contrib import rdb; rdb.set_trace() 19 | endsnippet 20 | 21 | # Logging 22 | 23 | snippet glog 24 | import logging 25 | logger = logging.getLogger(__name__) 26 | endsnippet 27 | 28 | snippet ldeb 29 | logger.debug('${1}') 30 | endsnippet 31 | 32 | snippet linfo 33 | logger.info('${1}') 34 | endsnippet 35 | 36 | snippet lerr 37 | logger.error('${1}') 38 | endsnippet 39 | 40 | snippet lwarn 41 | logger.warn('${1}') 42 | endsnippet 43 | 44 | # Nose testing 45 | 46 | snippet _== 47 | assert_equal(${1}, ${2}) 48 | endsnippet 49 | 50 | snippet _!= 51 | assert_not_equal(${1}, ${2}) 52 | endsnippet 53 | 54 | snippet _in 55 | assert_in(${1:obj}, ${2:container}) 56 | endsnippet 57 | 58 | snippet _raises 59 | assert_raises(${1:exc}) 60 | endsnippet 61 | 62 | snippet _true 63 | assert_true(${1}) 64 | endsnippet 65 | 66 | snippet _false 67 | assert_false(${1}) 68 | endsnippet 69 | 70 | # Pytest testing 71 | 72 | snippet fixture 73 | @pytest.fixture() 74 | def ${1:name}(${2}): 75 | return ${3} 76 | endsnippet 77 | 78 | snippet parametrize 79 | @pytest.mark.parametrize('${1:name}', 80 | ( 81 | ${2}, 82 | )) 83 | endsnippet 84 | 85 | snippet yfixture 86 | @pytest.yield_fixture() 87 | def ${1:name}(${2}): 88 | yield ${3} 89 | endsnippet 90 | 91 | snippet a== 92 | assert ${1} == ${2} 93 | endsnippet 94 | 95 | snippet a!= 96 | assert ${1} != ${2} 97 | endsnippet 98 | 99 | snippet atype 100 | assert type(${1}) is ${2} 101 | endsnippet 102 | 103 | snippet ain 104 | assert ${1:obj} in ${2:container} 105 | endsnippet 106 | 107 | snippet a!in 108 | assert ${1:obj} not in ${2:container} 109 | endsnippet 110 | 111 | snippet araises 112 | with pytest.raises(${1:exc}) as excinfo: 113 | ${2} 114 | endsnippet 115 | 116 | snippet atrue 117 | assert ${1} is True 118 | endsnippet 119 | 120 | snippet afalse 121 | assert ${1} is False 122 | endsnippet 123 | 124 | # typing 125 | 126 | snippet top 127 | typing.Optional[${1}] 128 | endsnippet 129 | 130 | snippet topt 131 | typing.Optional[${1}] 132 | endsnippet 133 | 134 | snippet tli 135 | typing.List 136 | endsnippet 137 | 138 | snippet tdi 139 | typing.Dict[${1}, ${2}] 140 | endsnippet 141 | 142 | snippet tse 143 | typing.Sequence 144 | endsnippet 145 | 146 | snippet tma 147 | typing.Mapping[${1}, ${2}] 148 | endsnippet 149 | 150 | snippet tca 151 | typing.Callable 152 | endsnippet 153 | 154 | snippet tno 155 | typing.NoReturn 156 | endsnippet 157 | 158 | snippet tty 159 | typing.Type[${1}] 160 | endsnippet 161 | 162 | snippet tun 163 | typing.Union[${1}] 164 | endsnippet 165 | 166 | snippet tan 167 | typing.Any 168 | endsnippet 169 | 170 | snippet tany 171 | typing.Any 172 | endsnippet 173 | -------------------------------------------------------------------------------- /roles/vim/files/rst.snippets: -------------------------------------------------------------------------------- 1 | 2 | snippet code 3 | .. code-block:: ${1:python} 4 | 5 | ${2:code} 6 | endsnippet 7 | 8 | snippet linki 9 | \`${1:link_variable_name} <${2}>\`_ 10 | endsnippet 11 | 12 | snippet ref 13 | :ref:\`${1:Reference} <${2:ref}>\` 14 | endsnippet 15 | -------------------------------------------------------------------------------- /roles/vim/files/vimrc: -------------------------------------------------------------------------------- 1 | " Spacebar is a much better leader than \ or , 2 | let mapleader = "\" 3 | 4 | """"" PLUGINS """"" 5 | call plug#begin() 6 | " ESSENTIALS 7 | Plug 'andymass/vim-matchup' " enhanced % (NOTE: must come before vim-sensible) 8 | Plug 'tpope/vim-sensible' " Sensible defaults 9 | Plug 'rstacruz/vim-opinion' " More sensible defaults 10 | Plug 'ervandew/supertab' " Tab complete everything 11 | Plug 'ctrlpvim/ctrlp.vim' " Fuzzy-matching go-to file 12 | nnoremap :CtrlPBuffer 13 | map :CtrlPBufTag 14 | " Make ctrlp faster 15 | let g:ctrlp_user_command = ['.git/', 'git --git-dir=%s/.git ls-files -oc --exclude-standard'] 16 | if has('python') || has('python3') 17 | " Faster and more accurate fuzzy-matching 18 | Plug 'felikz/ctrlp-py-matcher' 19 | let g:ctrlp_match_func = { 'match': 'pymatcher#PyMatch' } 20 | endif 21 | " rg-powered search with in-place editing 22 | Plug 'dyng/ctrlsf.vim' 23 | let g:ctrlsf_ackprg = 'rg' 24 | let g:ctrlsf_auto_focus = {'at': 'start'} " Automatically focus search results 25 | nmap f :CtrlSF '' 26 | nmap n CtrlSFCwordPath 27 | nnoremap t :CtrlSFToggle 28 | Plug 'tpope/vim-rsi' " unix keybindings in insert mode 29 | Plug 'tpope/vim-repeat' " make more actions repeatable with . 30 | Plug 'tpope/vim-surround' " motions for handling surrounding characters 31 | Plug 'tpope/vim-unimpaired' " useful bracket maps and option toggling 32 | " Toggle comment with space-/ 33 | Plug 'tpope/vim-commentary' " for code comments 34 | nmap / CommentaryLine 35 | vmap / Commentary 36 | " Buffers 37 | Plug 'moll/vim-bbye' " delete buffer without closing window 38 | nnoremap X :Bdelete 39 | Plug 'vim-scripts/BufOnly.vim' " delete all but current buffer 40 | 41 | Plug 'scrooloose/nerdtree', {'on': ['NERDTreeToggle', 'NERDTreeFind']} 42 | nnoremap d :NERDTreeToggle 43 | nnoremap D :NERDTreeFind 44 | let NERDTreeIgnore = ['\.pyc', '__pycache__', '.egg-info[[dir]]', 'pip-wheel-metadata[[dir]]'] 45 | 46 | Plug 'w0rp/ale' " Async linting 47 | nmap [s (ale_previous_wrap) 48 | nmap ]s (ale_next_wrap) 49 | nmap = (ale_fix) 50 | let g:ale_pattern_options = { 51 | \ '.*\.md$': {'ale_enabled': 0}, 52 | \ '.*\.markdown$': {'ale_enabled': 0}, 53 | \ '.*\.rst$': {'ale_enabled': 0}, 54 | \ '.*\.txt$': {'ale_enabled': 0}, 55 | \ '.*\.tex$': {'ale_enabled': 0}, 56 | \} 57 | nmap - :ALEToggleBuffer 58 | let g:ale_fix_on_save = 1 59 | " nnoremap + :let g:ale_fix_on_save = !g:ale_fix_on_save 60 | nnoremap + :call ToggleFixOnSave() 61 | function! ToggleFixOnSave() 62 | let g:ale_fix_on_save = !g:ale_fix_on_save 63 | echo g:ale_fix_on_save == 1 ? "ale_fix_on_save enabled" : "ale_fix_on_save disabled" 64 | endfunction 65 | " Quickly open the loclist to see syntax errors 66 | nmap ' :lopen 67 | let g:ale_maximum_file_size = 500000 " Don't lint large files (> 500KB), it can slow things down 68 | let g:ale_linters = {} 69 | let g:ale_linters.javascript = ['eslint', 'tsserver'] 70 | let g:ale_linters.typescript = ['eslint', 'tsserver'] 71 | let g:ale_linters.python = ['ruff'] 72 | let g:ale_linters.html = [] 73 | let g:ale_fixers = {} 74 | let g:ale_fixers.javascript = ['prettier'] 75 | let g:ale_fixers.typescript = ['prettier'] 76 | let g:ale_fixers.python = ['ruff', 'ruff_format'] 77 | let g:ale_fixers.css = ['prettier'] 78 | let g:ale_completion_enabled = 1 79 | " Prevent completion from autoinserting. See :help ale-completion-completopt-bug 80 | set completeopt=menu,menuone,noselect,noinsert 81 | nmap gd (ale_go_to_definition) 82 | " NICE TO HAVE 83 | Plug 'AndrewRadev/splitjoin.vim' " Language-specific split/join with gS and gJ 84 | let g:splitjoin_python_brackets_on_separate_lines = 1 85 | let g:splitjoin_trailing_comma = 1 86 | Plug 'jszakmeister/vim-togglecursor' " change cursor shape when entering insert mode 87 | " Snippets 88 | if version >= 704 && has('python') || has('python3') | Plug 'SirVer/ultisnips' | endif 89 | let g:UltiSnipsJumpForwardTrigger="" 90 | let g:UltiSnipsJumpBackwardTrigger="" 91 | Plug 'honza/vim-snippets' 92 | Plug 'fcpg/vim-spotlightify' " Highlight and show number of matches when searching 93 | Plug 'wellle/targets.vim' " because cin), etc. is awesome 94 | Plug 'tpope/vim-dispatch' " So we can run tests asynchronously 95 | Plug 'janko-m/vim-test' " For running tests 96 | let test#python#runner = 'pytest' 97 | nmap tt :TestNearest 98 | nmap tT :TestNearest --snapshot-update 99 | nmap tf :TestFile 100 | nmap tF :TestFile --snapshot-update 101 | nmap tl :TestLast 102 | nmap tL :TestLast --snapshot-update 103 | let test#strategy = "dispatch" 104 | " -s for ipdb support; disable cacheprovider so we don't break 'py.test --lf' 105 | let test#python#pytest#options = '-s -p no:cacheprovider' 106 | 107 | Plug 'mattn/emmet-vim' " Write HTML fast 108 | " When in javascript, expand to 'className' (for jsx support) 109 | let g:user_emmet_settings = { 110 | \ 'javascript': {'extends': 'jsx'}, 111 | \ 'javascript.jsx': {'extends': 'jsx'} 112 | \ } 113 | Plug 'jiangmiao/auto-pairs' " autoclose parens, quotes, etc. 114 | autocmd FileType python let b:AutoPairs = AutoPairsDefine({'f"': '"', "f'": "'"}) 115 | " Open scratch buffer with space-tab (automatically set syntax to markdown) 116 | nnoremap :Scratch 117 | Plug 'tpope/vim-sleuth' " Detect indent settings 118 | Plug 'machakann/vim-highlightedyank' " Highlight yank 119 | if !exists('##TextYankPost') | map y (highlightedyank) | endif 120 | " GIT 121 | Plug 'airblade/vim-gitgutter' 122 | " Set gitgutter's bindings manually to avoid clashes 123 | let g:gitgutter_map_keys = 0 124 | nmap gh (GitGutterStageHunk) 125 | nmap gH (GitGutterUndoHunk) 126 | nmap [h (GitGutterPrevHunk) 127 | nmap ]h (GitGutterNextHunk) 128 | set updatetime=200 " faster updates 129 | Plug 'tpope/vim-fugitive' " git integration 130 | Plug 'tpope/vim-rhubarb' " For :Gbrowse 131 | map gs :Git 132 | map gb :Git blame 133 | " Open current file on Github 134 | map gB :GBrowse 135 | " Open currently selected lines on Github 136 | vmap gB :GBrowse 137 | map gr :GRead 138 | map gw :GWrite 139 | Plug 'majutsushi/tagbar', {'on': 'Tagbar'} 140 | " Open tagbar 141 | map \ :Tagbar 142 | let g:tagbar_autofocus = 1 143 | " COLOR 144 | Plug 'sloria/vim-hybrid' " hybrid with easier-to-read line numbers 145 | 146 | " LANGUAGE-SPECIFIC 147 | Plug 'sheerun/vim-polyglot' " syntax files for most languages 148 | let g:jsx_ext_required = 0 149 | let g:markdown_fenced_languages = ['javascript', 'python', 'clojure', 'ruby'] 150 | " --- Python --- 151 | Plug 'Vimjas/vim-python-pep8-indent' " Proper python indenting 152 | " --- CSS --- 153 | Plug 'chrisbra/Colorizer' " Highlight CSS colors 154 | let g:colorizer_auto_filetype='css,html' 155 | 156 | call plug#end() 157 | filetype plugin indent on 158 | """ end plugins """ 159 | 160 | """ BASE CUSTOMIZATIONS """ 161 | " NOTE: Many base customizations come from vim-sensible and vim-opinion 162 | set encoding=utf-8 163 | set relativenumber 164 | set autoread " reload files when changed on disk, i.e. via `git checkout` 165 | set clipboard^=unnamedplus,unnamed " Make "yanks" work with system clipboard 166 | set exrc secure " Project-specific vimrcs 167 | 168 | " Indents 169 | set autoindent 170 | set expandtab " expand tabs by default (overloadable per file type later) 171 | set tabstop=4 softtabstop=4 shiftwidth=4 172 | set shiftround " use multiple of shiftwidth when indenting with '<' and '>' 173 | 174 | " No bells 175 | set noerrorbells visualbell t_vb= 176 | 177 | """ VISUAL SETTINGS """ 178 | if &term =~ '256color' | set t_ut= | endif 179 | set background=dark | colorscheme hybrid-sl 180 | 181 | " Show trailing whitespace 182 | set list listchars=tab:▸\ ,trail:▫ 183 | 184 | set cursorline " have a line indicate cursor location 185 | set previewheight=25 " Larger preview height 186 | 187 | " Set minimum window size to 79x5. 188 | set winwidth=79 winheight=5 winminheight=5 189 | 190 | " Patterns to ignore for expand(), ctrlp, etc. 191 | set wildignore+=*.zip,*.tar.gz,*.tar.bz2,*.rar,*.tar.xz,*.swp,*~,._*,*.pyc,*__pycache__*,*.egg-info 192 | 193 | """ SHORTCUTS """ 194 | " Quickly edit vimrc 195 | nmap , :e $MYVIMRC 196 | " Reload vimrc 197 | noremap V :source $MYVIMRC 198 | " Search and replace, using : as a separator instead of / 199 | noremap sr :%s:::cg 200 | " Switch between files 201 | nnoremap b :e# 202 | " Remove trailing whitespace with Backspace 203 | nnoremap :%s/\s\+$//:let @/='' 204 | " select last pasted text 205 | nnoremap gp `[v`] 206 | " Quickly write/quit 207 | nnoremap w :w 208 | nnoremap q :q 209 | " Quickly open netrw 210 | nnoremap e :e. 211 | " Quick split 212 | nnoremap v vw 213 | " Quick select whole file 214 | map a ggVG 215 | " Quickly save session 216 | nnoremap S :mksession! .session 217 | " Make D delete to end of line 218 | nnoremap D d$ 219 | " Make Y yank to end of line 220 | nnoremap Y y$ 221 | " Go to beginning/end of line 222 | noremap h ^ 223 | noremap l $ 224 | " Execute macro 225 | nnoremap Q @q 226 | " Move vertically over wrapped lines 227 | nmap j gj 228 | nmap k gk 229 | " Set cwd to current file 230 | nnoremap cd :lcd %:p:h 231 | " Split lines (opposite of J) 232 | nnoremap S i 233 | nnoremap N "=strftime("%F")P 234 | inoremap n =strftime("%F") 235 | 236 | augroup configgroup 237 | autocmd! 238 | " Make sure Vim returns to the same line when you reopen a file. 239 | autocmd BufReadPost * if line("'\"") > 0 && line("'\"") <= line("$") | execute 'normal! g`"zvzz' | endif 240 | 241 | " Automatically adjust quickfix window depending on how much text there is 242 | autocmd FileType qf call AdjustWindowHeight(3, 20) 243 | function! AdjustWindowHeight(minheight, maxheight) 244 | exe max([min([line("$"), a:maxheight]), a:minheight]) . "wincmd _" 245 | endfunction 246 | 247 | """ Languages 248 | " prose (hard wrap and autoformat paragraphs) 249 | autocmd BufRead,BufNewFile jrnl*.txt,editor*.txt set filetype=markdown 250 | autocmd BufRead,BufNewFile *.mdx set filetype=markdown 251 | autocmd BufRead,BufNewFile jrnl*.txt,editor*.txt,*.md,*.rst setlocal nolist wrap linebreak formatoptions+=ntl textwidth=72 wrapmargin=0 252 | autocmd BufRead,BufNewFile .eslintrc set filetype=json 253 | autocmd BufRead,BufNewFile .babelrc set filetype=json5 254 | " commit messages 255 | autocmd Filetype gitcommit setlocal nolist textwidth=72 256 | augroup END 257 | 258 | " GUI settings, e.g. MacVim 259 | set guifont=Hack:h12 260 | " Hide scrollbars and menu 261 | set guioptions-=T guioptions-=R guioptions-=r guioptions-=m guioptions-=l guioptions-=L 262 | set keyprotocol=ghostty:none 263 | -------------------------------------------------------------------------------- /roles/vim/meta/main.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - { role: rg } 3 | -------------------------------------------------------------------------------- /roles/vim/tasks/debian.yml: -------------------------------------------------------------------------------- 1 | - name: Install vim with apt 2 | apt: name=vim state=present 3 | become_method: sudo 4 | -------------------------------------------------------------------------------- /roles/vim/tasks/mac.yml: -------------------------------------------------------------------------------- 1 | - name: Install vim with homebrew 2 | homebrew: name=vim state=present 3 | 4 | - name: Install exuberant-ctags (needed for TagBar plugin) 5 | homebrew: name=ctags-exuberant state=present 6 | -------------------------------------------------------------------------------- /roles/vim/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Installation 2 | - import_tasks: debian.yml 3 | when: ansible_os_family == "Debian" 4 | - import_tasks: redhat.yml 5 | when: ansible_os_family == "RedHat" 6 | - import_tasks: mac.yml 7 | when: ansible_os_family == "Darwin" 8 | 9 | - name: Install python-language-server (used by ale) 10 | command: "uv tool install python-language-server" 11 | # TODO: Make idempotent 12 | 13 | # Plugin manager 14 | - name: Makes sure autoload directory exists 15 | file: path="{{dotfiles_user_home}}/.vim/autoload" state=directory 16 | 17 | - name: Install vim-plug 18 | get_url: 19 | url: https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim 20 | dest: "{{dotfiles_user_home}}/.vim/autoload/plug.vim" 21 | 22 | # Snippets 23 | - name: Makes sure UltiSnips directory exists 24 | file: path="{{dotfiles_user_home}}/.vim/UltiSnips" state=directory 25 | 26 | - name: Symlink all snippet files 27 | file: 28 | src: "{{ dotfiles_home }}/roles/vim/files/{{item}}" 29 | dest: "{{ dotfiles_user_home}}/.vim/UltiSnips/{{item}}" 30 | state: link 31 | with_items: 32 | - "python.snippets" 33 | - "rst.snippets" 34 | - "javascript.snippets" 35 | 36 | # Configuration 37 | - name: Check if vimrc exists 38 | stat: path="{{dotfiles_user_home}}/.vimrc" 39 | register: vimrc_stat 40 | failed_when: False 41 | 42 | - name: Backup vimrc 43 | command: mv ~/.vimrc ~/.vimrc.bak 44 | args: 45 | creates: "{{dotfiles_user_home}}/.vimrc.bak" 46 | when: vimrc_stat.stat.exists 47 | 48 | - name: Symlink vimrc 49 | file: 50 | src: "{{ dotfiles_home }}/roles/vim/files/vimrc" 51 | dest: "{{dotfiles_user_home}}/.vimrc" 52 | state: link 53 | 54 | - name: Install plugins 55 | command: vim +PlugInstall +qall 56 | when: vim_install_plugins|bool 57 | -------------------------------------------------------------------------------- /roles/vim/tasks/redhat.yml: -------------------------------------------------------------------------------- 1 | - name: Install vim with yum 2 | yum: name=vim state=present 3 | become_method: sudo 4 | -------------------------------------------------------------------------------- /roles/z/enable.zsh: -------------------------------------------------------------------------------- 1 | # I used to use autojump, so "j" is in muscle memory 2 | export _Z_CMD=j 3 | . $ZSH/roles/z/z.sh 4 | -------------------------------------------------------------------------------- /roles/z/z.sh: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2009 rupa deadwyler. Licensed under the WTFPL license, Version 2 2 | 3 | # maintains a jump-list of the directories you actually use 4 | # 5 | # INSTALL: 6 | # * put something like this in your .bashrc/.zshrc: 7 | # . /path/to/z.sh 8 | # * cd around for a while to build up the db 9 | # * PROFIT!! 10 | # * optionally: 11 | # set $_Z_CMD in .bashrc/.zshrc to change the command (default z). 12 | # set $_Z_DATA in .bashrc/.zshrc to change the datafile (default ~/.z). 13 | # set $_Z_MAX_SCORE lower to age entries out faster (default 9000). 14 | # set $_Z_NO_RESOLVE_SYMLINKS to prevent symlink resolution. 15 | # set $_Z_NO_PROMPT_COMMAND if you're handling PROMPT_COMMAND yourself. 16 | # set $_Z_EXCLUDE_DIRS to an array of directories to exclude. 17 | # set $_Z_OWNER to your username if you want use z while sudo with $HOME kept 18 | # 19 | # USE: 20 | # * z foo # cd to most frecent dir matching foo 21 | # * z foo bar # cd to most frecent dir matching foo and bar 22 | # * z -r foo # cd to highest ranked dir matching foo 23 | # * z -t foo # cd to most recently accessed dir matching foo 24 | # * z -l foo # list matches instead of cd 25 | # * z -e foo # echo the best match, don't cd 26 | # * z -c foo # restrict matches to subdirs of $PWD 27 | # * z -x # remove the current directory from the datafile 28 | # * z -h # show a brief help message 29 | 30 | [ -d "${_Z_DATA:-$HOME/.z}" ] && { 31 | echo "ERROR: z.sh's datafile (${_Z_DATA:-$HOME/.z}) is a directory." 32 | } 33 | 34 | _z() { 35 | 36 | local datafile="${_Z_DATA:-$HOME/.z}" 37 | 38 | # if symlink, dereference 39 | [ -h "$datafile" ] && datafile=$(readlink "$datafile") 40 | 41 | # bail if we don't own ~/.z and $_Z_OWNER not set 42 | [ -z "$_Z_OWNER" -a -f "$datafile" -a ! -O "$datafile" ] && return 43 | 44 | _z_dirs () { 45 | [ -f "$datafile" ] || return 46 | 47 | local line 48 | while read line; do 49 | # only count directories 50 | [ -d "${line%%\|*}" ] && echo "$line" 51 | done < "$datafile" 52 | return 0 53 | } 54 | 55 | # add entries 56 | if [ "$1" = "--add" ]; then 57 | shift 58 | 59 | # $HOME and / aren't worth matching 60 | [ "$*" = "$HOME" -o "$*" = '/' ] && return 61 | 62 | # don't track excluded directory trees 63 | if [ ${#_Z_EXCLUDE_DIRS[@]} -gt 0 ]; then 64 | local exclude 65 | for exclude in "${_Z_EXCLUDE_DIRS[@]}"; do 66 | case "$*" in "$exclude"*) return;; esac 67 | done 68 | fi 69 | 70 | # maintain the data file 71 | local tempfile="$datafile.$RANDOM" 72 | local score=${_Z_MAX_SCORE:-9000} 73 | _z_dirs | \awk -v path="$*" -v now="$(\date +%s)" -v score=$score -F"|" ' 74 | BEGIN { 75 | rank[path] = 1 76 | time[path] = now 77 | } 78 | $2 >= 1 { 79 | # drop ranks below 1 80 | if( $1 == path ) { 81 | rank[$1] = $2 + 1 82 | time[$1] = now 83 | } else { 84 | rank[$1] = $2 85 | time[$1] = $3 86 | } 87 | count += $2 88 | } 89 | END { 90 | if( count > score ) { 91 | # aging 92 | for( x in rank ) print x "|" 0.99*rank[x] "|" time[x] 93 | } else for( x in rank ) print x "|" rank[x] "|" time[x] 94 | } 95 | ' 2>/dev/null >| "$tempfile" 96 | # do our best to avoid clobbering the datafile in a race condition. 97 | if [ $? -ne 0 -a -f "$datafile" ]; then 98 | \env rm -f "$tempfile" 99 | else 100 | [ "$_Z_OWNER" ] && chown $_Z_OWNER:"$(id -ng $_Z_OWNER)" "$tempfile" 101 | \env mv -f "$tempfile" "$datafile" || \env rm -f "$tempfile" 102 | fi 103 | 104 | # tab completion 105 | elif [ "$1" = "--complete" -a -s "$datafile" ]; then 106 | _z_dirs | \awk -v q="$2" -F"|" ' 107 | BEGIN { 108 | q = substr(q, 3) 109 | if( q == tolower(q) ) imatch = 1 110 | gsub(/ /, ".*", q) 111 | } 112 | { 113 | if( imatch ) { 114 | if( tolower($1) ~ q ) print $1 115 | } else if( $1 ~ q ) print $1 116 | } 117 | ' 2>/dev/null 118 | 119 | else 120 | # list/go 121 | local echo fnd last list opt typ 122 | while [ "$1" ]; do case "$1" in 123 | --) while [ "$1" ]; do shift; fnd="$fnd${fnd:+ }$1";done;; 124 | -*) opt=${1:1}; while [ "$opt" ]; do case ${opt:0:1} in 125 | c) fnd="^$PWD $fnd";; 126 | e) echo=1;; 127 | h) echo "${_Z_CMD:-z} [-cehlrtx] args" >&2; return;; 128 | l) list=1;; 129 | r) typ="rank";; 130 | t) typ="recent";; 131 | x) \sed -i -e "\:^${PWD}|.*:d" "$datafile";; 132 | esac; opt=${opt:1}; done;; 133 | *) fnd="$fnd${fnd:+ }$1";; 134 | esac; last=$1; [ "$#" -gt 0 ] && shift; done 135 | [ "$fnd" -a "$fnd" != "^$PWD " ] || list=1 136 | 137 | # if we hit enter on a completion just go there 138 | case "$last" in 139 | # completions will always start with / 140 | /*) [ -z "$list" -a -d "$last" ] && builtin cd "$last" && return;; 141 | esac 142 | 143 | # no file yet 144 | [ -f "$datafile" ] || return 145 | 146 | local cd 147 | cd="$( < <( _z_dirs ) \awk -v t="$(\date +%s)" -v list="$list" -v typ="$typ" -v q="$fnd" -F"|" ' 148 | function frecent(rank, time) { 149 | # relate frequency and time 150 | dx = t - time 151 | return int(10000 * rank * (3.75/((0.0001 * dx + 1) + 0.25))) 152 | } 153 | function output(matches, best_match, common) { 154 | # list or return the desired directory 155 | if( list ) { 156 | if( common ) { 157 | printf "%-10s %s\n", "common:", common > "/dev/stderr" 158 | } 159 | cmd = "sort -n >&2" 160 | for( x in matches ) { 161 | if( matches[x] ) { 162 | printf "%-10s %s\n", matches[x], x | cmd 163 | } 164 | } 165 | } else { 166 | if( common && !typ ) best_match = common 167 | print best_match 168 | } 169 | } 170 | function common(matches) { 171 | # find the common root of a list of matches, if it exists 172 | for( x in matches ) { 173 | if( matches[x] && (!short || length(x) < length(short)) ) { 174 | short = x 175 | } 176 | } 177 | if( short == "/" ) return 178 | for( x in matches ) if( matches[x] && index(x, short) != 1 ) { 179 | return 180 | } 181 | return short 182 | } 183 | BEGIN { 184 | gsub(" ", ".*", q) 185 | hi_rank = ihi_rank = -9999999999 186 | } 187 | { 188 | if( typ == "rank" ) { 189 | rank = $2 190 | } else if( typ == "recent" ) { 191 | rank = $3 - t 192 | } else rank = frecent($2, $3) 193 | if( $1 ~ q ) { 194 | matches[$1] = rank 195 | } else if( tolower($1) ~ tolower(q) ) imatches[$1] = rank 196 | if( matches[$1] && matches[$1] > hi_rank ) { 197 | best_match = $1 198 | hi_rank = matches[$1] 199 | } else if( imatches[$1] && imatches[$1] > ihi_rank ) { 200 | ibest_match = $1 201 | ihi_rank = imatches[$1] 202 | } 203 | } 204 | END { 205 | # prefer case sensitive 206 | if( best_match ) { 207 | output(matches, best_match, common(matches)) 208 | exit 209 | } else if( ibest_match ) { 210 | output(imatches, ibest_match, common(imatches)) 211 | exit 212 | } 213 | exit(1) 214 | } 215 | ')" 216 | 217 | if [ "$?" -eq 0 ]; then 218 | if [ "$cd" ]; then 219 | if [ "$echo" ]; then echo "$cd"; else builtin cd "$cd"; fi 220 | fi 221 | else 222 | return $? 223 | fi 224 | fi 225 | } 226 | 227 | alias ${_Z_CMD:-z}='_z 2>&1' 228 | 229 | [ "$_Z_NO_RESOLVE_SYMLINKS" ] || _Z_RESOLVE_SYMLINKS="-P" 230 | 231 | if type compctl >/dev/null 2>&1; then 232 | # zsh 233 | [ "$_Z_NO_PROMPT_COMMAND" ] || { 234 | # populate directory list, avoid clobbering any other precmds. 235 | if [ "$_Z_NO_RESOLVE_SYMLINKS" ]; then 236 | _z_precmd() { 237 | (_z --add "${PWD:a}" &) 238 | : $RANDOM 239 | } 240 | else 241 | _z_precmd() { 242 | (_z --add "${PWD:A}" &) 243 | : $RANDOM 244 | } 245 | fi 246 | [[ -n "${precmd_functions[(r)_z_precmd]}" ]] || { 247 | precmd_functions[$(($#precmd_functions+1))]=_z_precmd 248 | } 249 | } 250 | _z_zsh_tab_completion() { 251 | # tab completion 252 | local compl 253 | read -l compl 254 | reply=(${(f)"$(_z --complete "$compl")"}) 255 | } 256 | compctl -U -K _z_zsh_tab_completion _z 257 | elif type complete >/dev/null 2>&1; then 258 | # bash 259 | # tab completion 260 | complete -o filenames -C '_z --complete "$COMP_LINE"' ${_Z_CMD:-z} 261 | [ "$_Z_NO_PROMPT_COMMAND" ] || { 262 | # populate directory list. avoid clobbering other PROMPT_COMMANDs. 263 | grep "_z --add" <<< "$PROMPT_COMMAND" >/dev/null || { 264 | PROMPT_COMMAND="$PROMPT_COMMAND"$'\n''(_z --add "$(command pwd '$_Z_RESOLVE_SYMLINKS' 2>/dev/null)" 2>/dev/null &);' 265 | } 266 | } 267 | fi 268 | -------------------------------------------------------------------------------- /roles/zsh/README.md: -------------------------------------------------------------------------------- 1 | # zsh 2 | 3 | Installs zsh configured with [prezto](https://github.com/sorin-ionescu/prezto). 4 | 5 | Symlinks `.zprezto` and `.zshrc` which is necessary for special files (e.g. `*.zsh`) files to work correctly. 6 | -------------------------------------------------------------------------------- /roles/zsh/_env.zsh: -------------------------------------------------------------------------------- 1 | export TERM=xterm-256color 2 | export EDITOR='vim' 3 | export VISUAL='code' 4 | export GPG_TTY=$(tty) 5 | export LC_ALL=en_US.UTF-8 6 | 7 | # Settings for various CLIs I use 8 | export PED_EDITOR='vim' 9 | export KONCH_EDITOR='vim' 10 | export FAM_SOURCE="$HOME/iCloud/fam" 11 | export FAM_EDITOR="vim" 12 | export AWS_CLI_AUTO_PROMPT=on-partial 13 | -------------------------------------------------------------------------------- /roles/zsh/_path.zsh: -------------------------------------------------------------------------------- 1 | # Prepend ~/dotfiles/bin to PATH 2 | export PATH=${PATH}:$ZSH/bin 3 | -------------------------------------------------------------------------------- /roles/zsh/aliases.zsh: -------------------------------------------------------------------------------- 1 | alias cl="clear" 2 | alias c="clear" 3 | alias pg='ps -ef | grep' 4 | alias pkill!="pkill -9 -f " 5 | alias dil='doitlive' 6 | alias dilp='doitlive play' 7 | 8 | alias reload!='. ~/.zshrc' 9 | alias vi="vim" 10 | alias v="vim" 11 | # resize images 12 | alias resize="mogrify -resize" 13 | 14 | alias btm="btm --process_memory_as_value" 15 | 16 | # Usage: qr https://example.com 17 | # Useful for e.g. deploy preview URLs, ngrok URLs, etc 18 | # Requires qrtool: brew install qrtool 19 | alias qr="qrtool encode -t terminal" 20 | -------------------------------------------------------------------------------- /roles/zsh/config.zsh: -------------------------------------------------------------------------------- 1 | # Disable autocorrect 2 | DISABLE_CORRECTION="true" 3 | unsetopt correct 4 | unsetopt correct_all 5 | # Don't auto-cd into directories without typing cd 6 | # because can annoyingly put you into source directories for CLI projects 7 | unsetopt AUTO_CD 8 | -------------------------------------------------------------------------------- /roles/zsh/defaults/main.yml: -------------------------------------------------------------------------------- 1 | zsh_prezto: yes 2 | -------------------------------------------------------------------------------- /roles/zsh/files/install_prezto.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | # Prezto installation 3 | # see https://github.com/sorin-ionescu/prezto 4 | 5 | git clone --recursive https://github.com/sorin-ionescu/prezto.git "${ZDOTDIR:-$HOME}/.zprezto" 6 | 7 | setopt EXTENDED_GLOB 8 | for rcfile in "${ZDOTDIR:-$HOME}"/.zprezto/runcoms/^README.md(.N); do 9 | ln -sf "$rcfile" "${ZDOTDIR:-$HOME}/.${rcfile:t}" 10 | done 11 | -------------------------------------------------------------------------------- /roles/zsh/files/zpreztorc.link: -------------------------------------------------------------------------------- 1 | # 2 | # Sets Prezto options. 3 | # 4 | # Authors: 5 | # Sorin Ionescu 6 | # 7 | 8 | # 9 | # General 10 | # 11 | 12 | # Set case-sensitivity for completion, history lookup, etc. 13 | # zstyle ':prezto:*:*' case-sensitive 'yes' 14 | 15 | # Color output (auto set to 'no' on dumb terminals). 16 | zstyle ':prezto:*:*' color 'yes' 17 | 18 | # Set the Zsh modules to load (man zshmodules). 19 | # zstyle ':prezto:load' zmodule 'attr' 'stat' 20 | 21 | # Set the Zsh functions to load (man zshcontrib). 22 | # zstyle ':prezto:load' zfunction 'zargs' 'zmv' 23 | 24 | # Set the Prezto modules to load (browse modules). 25 | # The order matters. 26 | zstyle ':prezto:load' pmodule \ 27 | 'environment' \ 28 | 'terminal' \ 29 | 'editor' \ 30 | 'history' \ 31 | 'directory' \ 32 | 'spectrum' \ 33 | 'utility' \ 34 | 'completion' \ 35 | 'prompt' \ 36 | 'git' \ 37 | 'python' \ 38 | 'autosuggestions' 39 | # 40 | # Editor 41 | # 42 | 43 | # Set the key mapping style to 'emacs' or 'vi'. 44 | zstyle ':prezto:module:editor' key-bindings 'emacs' 45 | 46 | # Auto convert .... to ../.. 47 | # zstyle ':prezto:module:editor' dot-expansion 'yes' 48 | 49 | # 50 | # Git 51 | # 52 | 53 | # Ignore submodules when they are 'dirty', 'untracked', 'all', or 'none'. 54 | # zstyle ':prezto:module:git:status:ignore' submodules 'all' 55 | 56 | # 57 | # GNU Utility 58 | # 59 | 60 | # Set the command prefix on non-GNU systems. 61 | # zstyle ':prezto:module:gnu-utility' prefix 'g' 62 | 63 | # 64 | # History Substring Search 65 | # 66 | 67 | # Set the query found color. 68 | # zstyle ':prezto:module:history-substring-search:color' found '' 69 | 70 | # Set the query not found color. 71 | # zstyle ':prezto:module:history-substring-search:color' not-found '' 72 | 73 | # Set the search globbing flags. 74 | # zstyle ':prezto:module:history-substring-search' globbing-flags '' 75 | 76 | # 77 | # Pacman 78 | # 79 | 80 | # Set the Pacman frontend. 81 | # zstyle ':prezto:module:pacman' frontend 'yaourt' 82 | 83 | # 84 | # Prompt 85 | # 86 | 87 | # Set the prompt theme to load. 88 | # Setting it to 'random' loads a random theme. 89 | # Auto set to 'off' on dumb terminals. 90 | zstyle ':prezto:module:prompt' theme 'pure' 91 | 92 | # 93 | # Python 94 | # 95 | 96 | # Automatically activate/deactivate virtualenvs when .venv exists 97 | zstyle ':prezto:module:python:virtualenv' auto-switch 'yes' 98 | 99 | # 100 | # Ruby 101 | # 102 | 103 | # Auto switch the Ruby version on directory change. 104 | # zstyle ':prezto:module:ruby:chruby' auto-switch 'yes' 105 | 106 | # 107 | # Screen 108 | # 109 | 110 | # Auto start a session when Zsh is launched in a local terminal. 111 | # zstyle ':prezto:module:screen:auto-start' local 'yes' 112 | 113 | # Auto start a session when Zsh is launched in a SSH connection. 114 | # zstyle ':prezto:module:screen:auto-start' remote 'yes' 115 | 116 | # 117 | # SSH 118 | # 119 | 120 | # Set the SSH identities to load into the agent. 121 | # zstyle ':prezto:module:ssh:load' identities 'id_rsa' 'id_rsa2' 'id_github' 122 | 123 | # 124 | # Syntax Highlighting 125 | # 126 | 127 | # Set syntax highlighters. 128 | # By default, only the main highlighter is enabled. 129 | # zstyle ':prezto:module:syntax-highlighting' highlighters \ 130 | # 'main' \ 131 | # 'brackets' \ 132 | # 'pattern' \ 133 | # 'line' \ 134 | # 'cursor' \ 135 | # 'root' 136 | # 137 | # Set syntax highlighting styles. 138 | # zstyle ':prezto:module:syntax-highlighting' styles \ 139 | # 'builtin' 'bg=blue' \ 140 | # 'command' 'bg=blue' \ 141 | # 'function' 'bg=blue' 142 | # 143 | # Set syntax pattern styles. 144 | # zstyle ':prezto:module:syntax-highlighting' pattern \ 145 | # 'rm*-rf*' 'fg=white,bold,bg=red' 146 | 147 | # 148 | # Terminal 149 | # 150 | 151 | # Auto set the tab and window titles. 152 | # zstyle ':prezto:module:terminal' auto-title 'yes' 153 | 154 | # Set the window title format. 155 | # zstyle ':prezto:module:terminal:window-title' format '%n@%m: %s' 156 | 157 | # Set the tab title format. 158 | # zstyle ':prezto:module:terminal:tab-title' format '%m: %s' 159 | 160 | # 161 | # Tmux 162 | # 163 | 164 | # Auto start a session when Zsh is launched in a local terminal. 165 | # zstyle ':prezto:module:tmux:auto-start' local 'yes' 166 | 167 | # Auto start a session when Zsh is launched in a SSH connection. 168 | # zstyle ':prezto:module:tmux:auto-start' remote 'yes' 169 | 170 | # Integrate with iTerm2. 171 | # zstyle ':prezto:module:tmux:iterm' integrate 'yes' 172 | -------------------------------------------------------------------------------- /roles/zsh/files/zshrc.link: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | # Initialize homebrew 4 | if [[ $(uname -m) == 'arm64' ]]; then 5 | eval $(/opt/homebrew/bin/brew shellenv) 6 | fi 7 | 8 | # shortcut to this dotfiles path is $ZSH 9 | export ZSH=$HOME/dotfiles 10 | 11 | # all of our zsh files 12 | typeset -U config_files 13 | config_files=($ZSH/**/*.zsh) 14 | 15 | # load the path files 16 | for file in ${(M)config_files:#*/path.zsh} 17 | do 18 | source $file 19 | done 20 | 21 | # Source Prezto. 22 | if [[ -s "${ZDOTDIR:-$HOME}/.zprezto/init.zsh" ]]; then 23 | source "${ZDOTDIR:-$HOME}/.zprezto/init.zsh" 24 | fi 25 | 26 | # load everything but the path and completion files 27 | for file in ${${${config_files:#*/path.zsh}:#*/completion.zsh}:#*/final.zsh} 28 | do 29 | source $file 30 | done 31 | 32 | 33 | # initialize autocomplete here, otherwise functions won't be loaded 34 | autoload -U compinit 35 | compinit 36 | 37 | # load every completion after autocomplete loads 38 | for file in ${(M)config_files:#*/completion.zsh} 39 | do 40 | source $file 41 | done 42 | 43 | for file in ${(M)config_files:#*/final.zsh} 44 | do 45 | source $file 46 | done 47 | 48 | unset config_files 49 | 50 | # use .localrc for SUPER SECRET CRAP that you don't 51 | # want in your public, versioned repo. 52 | if [[ -a ~/.localrc ]] 53 | then 54 | source ~/.localrc 55 | fi 56 | -------------------------------------------------------------------------------- /roles/zsh/files/zshrc_minimal: -------------------------------------------------------------------------------- 1 | # Set up the prompt 2 | 3 | autoload -Uz promptinit 4 | promptinit 5 | prompt redhat 6 | 7 | setopt histignorealldups sharehistory 8 | 9 | export ZSH=$HOME/dotfiles 10 | 11 | # Use emacs keybindings even if our EDITOR is set to vi 12 | bindkey -e 13 | 14 | # Keep 1000 lines of history within the shell and save it to ~/.zsh_history: 15 | HISTSIZE=1000 16 | SAVEHIST=1000 17 | HISTFILE=~/.zsh_history 18 | 19 | # Use modern completion system 20 | autoload -Uz compinit 21 | compinit 22 | 23 | zstyle ':completion:*' auto-description 'specify: %d' 24 | zstyle ':completion:*' completer _expand _complete _correct _approximate 25 | zstyle ':completion:*' format 'Completing %d' 26 | zstyle ':completion:*' group-name '' 27 | zstyle ':completion:*' menu select=2 28 | eval "$(dircolors -b)" 29 | zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS} 30 | zstyle ':completion:*' list-colors '' 31 | zstyle ':completion:*' list-prompt %SAt %p: Hit TAB for more, or the character to insert%s 32 | zstyle ':completion:*' matcher-list '' 'm:{a-z}={A-Z}' 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=* l:|=*' 33 | zstyle ':completion:*' menu select=long 34 | zstyle ':completion:*' select-prompt %SScrolling active: current selection at %p%s 35 | zstyle ':completion:*' use-compctl false 36 | zstyle ':completion:*' verbose true 37 | 38 | zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#)*=0=01;31' 39 | zstyle ':completion:*:kill:*' command 'ps -u $USER -o pid,%cpu,tty,cputime,cmd' 40 | 41 | # Path 42 | # shortcut to this dotfiles path is $ZSH 43 | export PATH=$PATH:$ZSH/bin 44 | 45 | # Envvars 46 | export EDITOR=vim 47 | export VISUAL=vim 48 | 49 | # Aliases 50 | alias c=clear 51 | alias l='ls -1A' 52 | alias g=git 53 | alias v=vim 54 | alias reload!='source ~/.zshrc' 55 | alias e=$EDITOR 56 | alias pg='ps -ef | grep' 57 | # Syntax-highlighted cat (requires python-pygments) 58 | alias dog="pygmentize -g" 59 | 60 | # Enable z script 61 | source ~/dotfiles/roles/z/enable.zsh 62 | 63 | # use .localrc for SUPER SECRET CRAP that you don't 64 | # want in your public, versioned repo. 65 | if [[ -a ~/.localrc ]] 66 | then 67 | source ~/.localrc 68 | fi 69 | -------------------------------------------------------------------------------- /roles/zsh/fpath.zsh: -------------------------------------------------------------------------------- 1 | #add each topic folder to fpath so that they can add functions and completion scripts 2 | for topic_folder ($ZSH/roles/*) if [ -d $topic_folder ]; then fpath=($topic_folder $fpath); fi; 3 | -------------------------------------------------------------------------------- /roles/zsh/functions.zsh: -------------------------------------------------------------------------------- 1 | # credit: http://nparikh.org/notes/zshrc.txt 2 | # Usage: extract 3 | # Description: extracts archived files / mounts disk images 4 | # Note: .dmg/hdiutil is Mac OS X-specific. 5 | extract () { 6 | if [ -f $1 ]; then 7 | case $1 in 8 | *.tar.bz2) tar -jxvf $1 ;; 9 | *.tar.gz) tar -zxvf $1 ;; 10 | *.bz2) bunzip2 $1 ;; 11 | *.dmg) hdiutil mount $1 ;; 12 | *.gz) gunzip $1 ;; 13 | *.tar) tar -xvf $1 ;; 14 | *.tbz2) tar -jxvf $1 ;; 15 | *.tgz) tar -zxvf $1 ;; 16 | *.zip) unzip $1 ;; 17 | *.ZIP) unzip $1 ;; 18 | *.pax) cat $1 | pax -r ;; 19 | *.pax.Z) uncompress $1 --stdout | pax -r ;; 20 | *.Z) uncompress $1 ;; 21 | *) echo "'$1' cannot be extracted/mounted via extract()" ;; 22 | esac 23 | else 24 | echo "'$1' is not a valid file" 25 | fi 26 | } 27 | 28 | # get gzipped size 29 | function gz() { 30 | echo "orig size (bytes): " 31 | cat "$1" | wc -c 32 | echo "gzipped size (bytes): " 33 | gzip -c "$1" | wc -c 34 | } 35 | 36 | # credit: http://ku1ik.com/2012/05/04/scratch-dir.html 37 | # Creates a new scratch directory and cds to it 38 | function scratch { 39 | cur_dir="$HOME/scratch" 40 | new_dir="$HOME/tmp/scratch-`date +'%s'`" 41 | mkdir -p $new_dir 42 | ln -nfs $new_dir $cur_dir 43 | cd $cur_dir 44 | echo "New scratch dir ready for grinding ;>" 45 | } 46 | 47 | # Allow returning to Vim by pressing Ctrl+Z 48 | fancy-ctrl-z () { 49 | if [[ $#BUFFER -eq 0 ]]; then 50 | BUFFER="fg" 51 | zle accept-line 52 | else 53 | zle push-input 54 | zle clear-screen 55 | fi 56 | } 57 | zle -N fancy-ctrl-z 58 | bindkey '^Z' fancy-ctrl-z 59 | 60 | function countfiles() { 61 | find "$1" -type f | wc -l 62 | } 63 | -------------------------------------------------------------------------------- /roles/zsh/tasks/debian.yml: -------------------------------------------------------------------------------- 1 | - name: Make sure zsh is installed 2 | apt: name=zsh state=present 3 | become_method: sudo 4 | -------------------------------------------------------------------------------- /roles/zsh/tasks/mac.yml: -------------------------------------------------------------------------------- 1 | # macOS zsh installation and setup 2 | 3 | - name: Make sure zsh is installed 4 | homebrew: name=zsh state=present 5 | 6 | # Fix broken /etc/zshenv, which runs path_helper 7 | # We rename it to prevent unwanted reordering of $PATH 8 | # https://github.com/sorin-ionescu/prezto/issues/381 9 | # https://github.com/thoughtbot/dotfiles/pull/426#issue-109716011 10 | - name: Fix broken /etc/zshenv 11 | command: creates="/etc/zprofile" mv /etc/zshenv /etc/zprofile 12 | become_method: sudo 13 | -------------------------------------------------------------------------------- /roles/zsh/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # Installation and setup 2 | - import_tasks: debian.yml 3 | when: ansible_os_family == "Debian" 4 | - import_tasks: redhat.yml 5 | when: ansible_os_family == "RedHat" 6 | - import_tasks: mac.yml 7 | when: ansible_os_family == "Darwin" 8 | 9 | # Configuration 10 | - name: Check if zshrc already exists 11 | stat: path="{{dotfiles_user_home}}/.zshrc" 12 | register: zshrc_stat 13 | 14 | - name: Back up zshrc if it exists 15 | command: mv ~/.zshrc ~/.zshrc.bak 16 | args: 17 | creates: "{{dotfiles_user_home}}/.zshrc.bak" 18 | when: zshrc_stat.stat.exists 19 | 20 | # Ensure the dotfiles repository gets cloned in remote hosts, like my mac mini, but not on localhost 21 | - name: Clone dotfiles repository 22 | git: 23 | repo: https://github.com/sloria/dotfiles.git 24 | dest: "{{ dotfiles_user_home }}/dotfiles" 25 | clone: yes 26 | when: inventory_hostname != 'localhost' 27 | 28 | - import_tasks: prezto.yml 29 | when: zsh_prezto 30 | 31 | - name: Copy minimal zshrc 32 | copy: src=zshrc_minimal dest={{dotfiles_user_home}}/.zshrc 33 | when: not zsh_prezto 34 | -------------------------------------------------------------------------------- /roles/zsh/tasks/prezto.yml: -------------------------------------------------------------------------------- 1 | # Prezto 2 | - name: Install prezto 3 | script: install_prezto.sh creates="{{ '~/.zprezto' | expanduser}}" 4 | 5 | - name: Link zpreztorc file 6 | file: 7 | src: "{{ dotfiles_home }}/roles/zsh/files/zpreztorc.link" 8 | dest: "{{ '~/.zpreztorc' | expanduser }}" 9 | state: link 10 | 11 | - name: Link zshrc file 12 | file: 13 | src: "{{ dotfiles_home }}/roles/zsh/files/zshrc.link" 14 | dest: "{{ '~/.zshrc' | expanduser }}" 15 | state: link 16 | -------------------------------------------------------------------------------- /roles/zsh/tasks/redhat.yml: -------------------------------------------------------------------------------- 1 | - name: Make sure zsh is installed 2 | yum: name=zsh state=present 3 | become_method: sudo 4 | # TODO: Set zsh as login shell 5 | --------------------------------------------------------------------------------