diff --git a/.gitattributes b/.gitattributes index 9ea3b43..3be3428 100644 --- a/.gitattributes +++ b/.gitattributes @@ -85,6 +85,7 @@ LICENSE text NEWS text readme text *README* text +# Files literally named "TODO", not a todo list item TODO text # Templates @@ -122,7 +123,8 @@ package.json text eol=lf package-lock.json text eol=lf -diff pnpm-lock.yaml text eol=lf -diff .prettierrc text -yarn.lock text -diff +# Ensure yarn.lock shows textual diffs +yarn.lock text eol=lf *.toml text *.yaml text *.yml text @@ -251,3 +253,4 @@ install text eol=lf diff=shell *.snippets text eol=lf *.theme text eol=lf *.yamlfmt text eol=lf +*.bats text eol=lf diff=shell diff --git a/.github/AGENTS.md b/.github/AGENTS.md new file mode 100644 index 0000000..9cd2369 --- /dev/null +++ b/.github/AGENTS.md @@ -0,0 +1,30 @@ +# Guidelines for AI contributors + +These instructions help language models work with this repository. + +## Setup + +1. Run `npm install` to get linting tools and the Bats test framework. + +## Formatting + +- Format code and docs with Prettier and markdownlint: + +```bash +npm run fix:prettier +npm run fix:markdown +``` + +- Shell scripts should pass `shellcheck`. + +## Testing + +- When code changes, run `npm test` to execute Bats tests. +- If only comments or documentation change, tests may be skipped. + +## Commits and PRs + +- Use Semantic Commit messages: `type(scope): summary`. +- Keep PR titles in the same format. + + diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 67a8d0a..0a8d364 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -60,7 +60,7 @@ representative at an online or offline event. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at -ismo@ivuorinen.net. +. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the @@ -116,7 +116,7 @@ the community. This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. +. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). @@ -124,5 +124,5 @@ enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. +. Translations are available at +. diff --git a/.github/README.md b/.github/README.md index 1c43b81..4e0510d 100644 --- a/.github/README.md +++ b/.github/README.md @@ -43,6 +43,12 @@ see what interesting stuff you've done with it. Sharing is caring. | `local/bin` | Helper scripts that I've collected or wrote. | | `scripts` | Setup scripts. | +### Host specific configuration + +Configurations under `hosts/` are applied only when running on the +matching machine. Each host folder contains its own `install.conf.yaml` that +is processed by Dotbot during installation. + ### dotfile folders | Repo | Destination | Description | @@ -58,6 +64,21 @@ see what interesting stuff you've done with it. Sharing is caring. Running `dfm` gives you a list of available commands. +#### Documentation generation + +`dfm docs` generates Markdown documentation under the `docs/` directory. The +subcommands are: + +```bash +dfm docs alias # regenerate alias table +dfm docs folders # document interesting folders +dfm docs keybindings # update keybinding docs for tmux, nvim and others +dfm docs all # run every docs task +``` + +The `docs/` folder contains generated cheat sheets, keybindings and other +reference files. New documentation can be added without modifying this README. + ## Configuration The folder structure follows [XDG Base Directory Specification][xdg] where possible. @@ -73,6 +94,31 @@ The folder structure follows [XDG Base Directory Specification][xdg] where possi Please see [docs/folders.md][docs-folders] for more information. +## Managing submodules + +This repository uses Git submodules for external dependencies. After cloning, +run: + +```bash +git submodule update --init --recursive +``` + +To pull submodule updates later use: + +```bash +git submodule update --remote --merge +``` + +The helper script `add-submodules.sh` documents how each submodule is added and +configured. Submodules are automatically updated by the +[update-submodules.yml](.github/workflows/update-submodules.yml) workflow. + +## Testing + +Shell scripts under `local/bin` are validated with [Bats](https://github.com/bats-core/bats-core). +Run `yarn test` to execute every test file. Bats is installed as a development +dependency, so run `yarn install` first if needed. + [dfm]: https://github.com/ivuorinen/dotfiles/blob/main/local/bin/dfm [docs-folders]: https://github.com/ivuorinen/dotfiles/blob/main/docs/folders.md [xdg]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html diff --git a/config/op/plugins/used_items/gh.json b/config/op/plugins/used_items/gh.json index 9eff365..53e152d 100644 --- a/config/op/plugins/used_items/gh.json +++ b/config/op/plugins/used_items/gh.json @@ -1 +1,7 @@ -[{"account_id":"S5Z2DMNFKJEZBPCWRHRWC4DCGI","vault_id":"injcin7obv3jdet3r2u3kfihfy","item_id":"f6vinbnc6l7ngdzvlw66ayewlq"}] \ No newline at end of file +[ + { + "account_id": "S5Z2DMNFKJEZBPCWRHRWC4DCGI", + "vault_id": "injcin7obv3jdet3r2u3kfihfy", + "item_id": "f6vinbnc6l7ngdzvlw66ayewlq" + } +] diff --git a/hosts/README.md b/hosts/README.md new file mode 100644 index 0000000..230c4a7 --- /dev/null +++ b/hosts/README.md @@ -0,0 +1,11 @@ +# Host specific directories + +Host folders contain machine specific overrides and an `install.conf.yaml` file that Dotbot processes during setup. + +Current hosts: + +- **air** – personal computer +- **lakka** – remote server +- **s** – work laptop +- **tunkki** – local server +- **v** – work desktop diff --git a/local/bin/a.md b/local/bin/a.md new file mode 100644 index 0000000..17b8099 --- /dev/null +++ b/local/bin/a.md @@ -0,0 +1,29 @@ +# a + +Encrypt or decrypt files and directories using `age` and your GitHub SSH keys. + +## Usage + +```bash +a encrypt +a decrypt +``` + +Options: + +- `-v`, `--verbose` – show log output + +Environment variables: + +- `AGE_KEYSFILE` – location of the keys file +- `AGE_KEYSSOURCE` – URL to fetch keys if missing +- `AGE_LOGFILE` – log file path + +## Example + +```bash +a encrypt secret.txt +a decrypt secret.txt.age +``` + + diff --git a/local/bin/ad.md b/local/bin/ad.md new file mode 100644 index 0000000..5af77aa --- /dev/null +++ b/local/bin/ad.md @@ -0,0 +1,19 @@ +# ad + +Decrypt a file encrypted with `age` using your GitHub SSH keys. + +## Usage + +```bash +ad +``` + +Uses `AGE_KEYSFILE` and `AGE_KEYSSOURCE` if keys are missing. + +## Example + +```bash +ad secret.txt.age +``` + + diff --git a/local/bin/ae.md b/local/bin/ae.md new file mode 100644 index 0000000..5cbe640 --- /dev/null +++ b/local/bin/ae.md @@ -0,0 +1,19 @@ +# ae + +Encrypt a file with `age` using your GitHub SSH keys. + +## Usage + +```bash +ae +``` + +Uses `AGE_KEYSFILE` and `AGE_KEYSSOURCE` if keys are missing. + +## Example + +```bash +ae secret.txt +``` + + diff --git a/local/bin/dfm.md b/local/bin/dfm.md new file mode 100644 index 0000000..f6e7a93 --- /dev/null +++ b/local/bin/dfm.md @@ -0,0 +1,26 @@ +# dfm + +Dotfiles manager and installation helper. Provides wrappers for many +setup tasks defined in this repository. + +## Usage + +```bash +dfm [options] +``` + +Common commands include: + +- `install` – install tools or run platform specific setup +- `brew` – manage Homebrew packages +- `docs` – regenerate markdown documentation + +Set `VERBOSE=1` to see debug output. + +### Example + +```bash +dfm install all +``` + + diff --git a/local/bin/fzf-tmux.md b/local/bin/fzf-tmux.md new file mode 100644 index 0000000..0049c06 --- /dev/null +++ b/local/bin/fzf-tmux.md @@ -0,0 +1,21 @@ +# fzf-tmux + +Wrapper around [`fzf`](https://github.com/junegunn/fzf) that opens the +interface inside a tmux pane or popup. + +## Usage + +```bash +fzf-tmux [layout options] [--] [fzf options] +``` + +Layout flags like `-p` or `-d` control popup and split behaviour. Use +`--` to pass arguments directly to `fzf`. + +### Example + +```bash +fzf-tmux -p 80%,60% -- --reverse +``` + + diff --git a/local/bin/fzf.md b/local/bin/fzf.md new file mode 100644 index 0000000..84cc0e0 --- /dev/null +++ b/local/bin/fzf.md @@ -0,0 +1,16 @@ +# fzf + +Binary of the fuzzy finder [fzf](https://github.com/junegunn/fzf). +Use `fzf` as you would normally; this wrapper ships the prebuilt +binary in the dotfiles. + +## Usage + +```bash +fzf [options] +``` + +Refer to the upstream `fzf` documentation for all available +flags and features. + + diff --git a/local/bin/git-attributes.md b/local/bin/git-attributes.md new file mode 100644 index 0000000..e159927 --- /dev/null +++ b/local/bin/git-attributes.md @@ -0,0 +1,25 @@ +# git-attributes + +Checks that every tracked file has a matching pattern in `.gitattributes`. +Can optionally suggest or write missing rules. + +## Usage + +```bash +git-attributes [options] +``` + +Options include: + +- `-v, --verbose` – show progress information +- `-e, --exit` – exit with non-zero status if missing rules +- `-p, --pattern ` – pattern to check (default: `text: auto`) +- `-w, --write` – append suggestions to `.gitattributes` + +### Example + +```bash +git-attributes -v --write +``` + + diff --git a/local/bin/iterm2_shell_integration.zsh.md b/local/bin/iterm2_shell_integration.zsh.md new file mode 100644 index 0000000..8f1a01b --- /dev/null +++ b/local/bin/iterm2_shell_integration.zsh.md @@ -0,0 +1,15 @@ +# iterm2_shell_integration.zsh + +Official iTerm2 shell integration script for zsh. Source this file to +enable prompt tracking and command notifications in iTerm2. + +## Usage + +```bash +source iterm2_shell_integration.zsh +``` + +No parameters are required. The script modifies your prompt to work +with iTerm2 features such as badges and profile switching. + + diff --git a/local/bin/msgr.md b/local/bin/msgr.md new file mode 100644 index 0000000..b6e2158 --- /dev/null +++ b/local/bin/msgr.md @@ -0,0 +1,20 @@ +# msgr + +Helper library for printing colorized log messages from shell scripts. + +## Usage + +```bash +msgr "message" [extra] +``` + +Message types include `ok`, `warn`, `err`, `run` and many more. The +script is primarily sourced by other scripts. + +### Example + +```bash +msgr ok "Installation complete" +``` + + diff --git a/local/bin/php-switcher.md b/local/bin/php-switcher.md new file mode 100644 index 0000000..7e3bed8 --- /dev/null +++ b/local/bin/php-switcher.md @@ -0,0 +1,23 @@ +# php-switcher + +Switch between Homebrew-installed PHP versions or list installed versions. + +## Usage + +```bash +php-switcher |--auto [options] +``` + +Options: + +- `--installed` – list versions installed via Homebrew +- `--current` – print currently active PHP version +- `--auto` – read version from `.php-version` in current directory + +### Example + +```bash +php-switcher 8.3 +``` + + diff --git a/local/bin/pushover b/local/bin/pushover index f71e2e6..7c081ca 100755 --- a/local/bin/pushover +++ b/local/bin/pushover @@ -56,22 +56,31 @@ __pushover_send_message() response="$(eval "${curl_cmd}")" printf "%s\n" "$response" - # TODO: Parse response - r="${?}" - if [ "${r}" -ne 0 ]; then - printf "%s: Failed to send message\n" "${0}" >&2 + + # Parse response status. Expect JSON like: {"status":1,"request":"..."} + if echo "$response" | grep -q '"status"[[:space:]]*:[[:space:]]*1'; then + r=0 + else + r=1 fi - return "${r}" + if [ "$r" -ne 0 ]; then + # Extract possible error message from JSON + err=$(echo "$response" | grep -o '"errors".*' | sed 's/"errors"[:,\[]//g' | tr -d '[]"') + [ -n "$err" ] && printf "%s: %s\n" "$0" "$err" >&2 + printf "%s: Failed to send message\n" "$0" >&2 + fi + + return "$r" } -CURL="$(which curl)" +CURL="$(command -v curl)" PUSHOVER_URL="https://api.pushover.net/1/messages.json" TOKEN=$PUSHOVER_TOKEN USER=$PUSHOVER_USER CURL_OPTS="" -devices="${devices} ${device}" -optstring="c:d:D:e:f:p:r:t:T:s:u:U:a:h" +devices="" +optstring="c:d:D:e:p:r:t:T:s:u:U:a:h" OPTIND=1 while getopts ${optstring} c; do @@ -97,7 +106,7 @@ while getopts ${optstring} c; do t) title="${OPTARG}" ;; - k) + T) TOKEN="${OPTARG}" ;; s) diff --git a/local/bin/pushover.md b/local/bin/pushover.md new file mode 100644 index 0000000..9fd5cac --- /dev/null +++ b/local/bin/pushover.md @@ -0,0 +1,25 @@ +# pushover + +Send notifications via the Pushover API. + +## Usage + +```bash +pushover -T -U [-t title] [-p priority] message +``` + +Common options: + +- `-c ` – callback URL +- `-d ` – target device +- `-s ` – notification sound name +- `-T ` – application token (or `PUSHOVER_TOKEN` env) +- `-U ` – user key (or `PUSHOVER_USER` env) + +## Example + +```bash +pushover -T $TOKEN -U $USER -t "Build" "Finished successfully" +``` + + diff --git a/local/bin/t.md b/local/bin/t.md new file mode 100644 index 0000000..b01b245 --- /dev/null +++ b/local/bin/t.md @@ -0,0 +1,23 @@ +# t + +Launch or switch to a tmux session based on a directory selected with +`fzf`. Inspired by scripts from ThePrimeagen and Jess Archer. + +## Usage + +```bash +t +``` + +Environment variables: + +- `T_ROOT` – base directory to search (default: `~/Code`) +- `T_MAX_DEPTH` – recursion depth for directory search + +### Example + +```bash +T_ROOT=~/projects t +``` + + diff --git a/local/bin/x-backup-folder.md b/local/bin/x-backup-folder.md new file mode 100644 index 0000000..9fa7e81 --- /dev/null +++ b/local/bin/x-backup-folder.md @@ -0,0 +1,20 @@ +# x-backup-folder + +Create a compressed archive of a folder with a timestamped name. + +## Usage + +```bash +x-backup-folder [archive-name] +``` + +- `folder` – directory to back up +- `archive-name` – optional prefix for the generated tar.gz + +## Example + +```bash +x-backup-folder ~/Documents Notes +``` + + diff --git a/local/bin/x-backup-mysql-with-prefix.md b/local/bin/x-backup-mysql-with-prefix.md new file mode 100644 index 0000000..66733bd --- /dev/null +++ b/local/bin/x-backup-mysql-with-prefix.md @@ -0,0 +1,21 @@ +# x-backup-mysql-with-prefix + +Dump MySQL tables matching a prefix to a timestamped file. + +## Usage + +```bash +x-backup-mysql-with-prefix [database] +``` + +- `prefix` – table prefix to match (e.g. `wp_`) +- `name` – file name prefix +- `database` – database name (default: `wordpress`) + +## Example + +```bash +x-backup-mysql-with-prefix wp_ blog +``` + + diff --git a/local/bin/x-change-alacritty-theme.md b/local/bin/x-change-alacritty-theme.md new file mode 100644 index 0000000..9e1a29c --- /dev/null +++ b/local/bin/x-change-alacritty-theme.md @@ -0,0 +1,20 @@ +# x-change-alacritty-theme + +Adapted from + +## Usage + +```bash +x-change-alacritty-theme +``` + +Switches Alacritty's theme by copying a theme file under +`~/.config/alacritty/`. + +### Example + +```bash +x-change-alacritty-theme night +``` + + diff --git a/local/bin/x-clean-vendordirs.md b/local/bin/x-clean-vendordirs.md new file mode 100644 index 0000000..792594f --- /dev/null +++ b/local/bin/x-clean-vendordirs.md @@ -0,0 +1,19 @@ +# x-clean-vendordirs + +Remove `vendor` and `node_modules` directories recursively. + +## Usage + +```bash +x-clean-vendordirs [directory] +``` + +- `directory` – root directory to clean (default: current directory) + +## Example + +```bash +x-clean-vendordirs ~/projects +``` + + diff --git a/local/bin/x-compare-versions.py.md b/local/bin/x-compare-versions.py.md new file mode 100644 index 0000000..bb84ad3 --- /dev/null +++ b/local/bin/x-compare-versions.py.md @@ -0,0 +1,14 @@ +# x-compare-versions.py + +Compare version strings using Python's packaging library. + +## Usage + +```bash +echo "1.2.3 >= 1.0.0" | x-compare-versions.py +``` + +The script reads comparison expressions from standard input and exits +with status 0 if all comparisons are true. + + diff --git a/local/bin/x-dc.md b/local/bin/x-dc.md new file mode 100644 index 0000000..ec88024 --- /dev/null +++ b/local/bin/x-dc.md @@ -0,0 +1,19 @@ +# x-dc + +Create a directory if it does not exist. + +## Usage + +```bash +x-dc +``` + +Set `VERBOSE=1` to see log messages. + +## Example + +```bash +x-dc ~/tmp/mydir +``` + + diff --git a/local/bin/x-dfm-docs-xterm-keybindings.md b/local/bin/x-dfm-docs-xterm-keybindings.md new file mode 100644 index 0000000..8fc00e9 --- /dev/null +++ b/local/bin/x-dfm-docs-xterm-keybindings.md @@ -0,0 +1,14 @@ +# x-dfm-docs-xterm-keybindings + +Generate `docs/tmux-keybindings.md` using tmux's key list. + +## Usage + +```bash +x-dfm-docs-xterm-keybindings +``` + +No parameters are needed. The script writes the file under `docs/` and +overwrites any existing version. + + diff --git a/local/bin/x-env-list.md b/local/bin/x-env-list.md new file mode 100644 index 0000000..04c93e9 --- /dev/null +++ b/local/bin/x-env-list.md @@ -0,0 +1,21 @@ +# x-env-list + +Lists environment variables grouped by their prefix. Sensitive values +are hidden by default. + +## Usage + +```bash +x-env-list [options] +``` + +Use `--json` for machine readable output or specify +`X_ENV_GROUPING` with a YAML file to override the default groups. + +### Example + +```bash +X_ENV_GROUPING=~/env-groups.yaml x-env-list --json +``` + + diff --git a/local/bin/x-foreach.md b/local/bin/x-foreach.md new file mode 100644 index 0000000..5976828 --- /dev/null +++ b/local/bin/x-foreach.md @@ -0,0 +1,20 @@ +# x-foreach + +Run a command in each directory produced by another command. + +## Usage + +```bash +x-foreach "" "" +``` + +- `list-cmd` – command that outputs directories +- `cmd` – command to run inside each directory + +## Example + +```bash +x-foreach "ls -d */" "git status" +``` + + diff --git a/local/bin/x-gh-get-latest-release-targz.md b/local/bin/x-gh-get-latest-release-targz.md new file mode 100644 index 0000000..d4cc297 --- /dev/null +++ b/local/bin/x-gh-get-latest-release-targz.md @@ -0,0 +1,19 @@ +# x-gh-get-latest-release-targz + +Fetch the tarball URL of the latest GitHub release or download it directly. + +## Usage + +```bash +x-gh-get-latest-release-targz [--get] +``` + +- `--get` – download and extract the tarball instead of printing the URL + +## Example + +```bash +x-gh-get-latest-release-targz ivuorinen/dotfiles --get +``` + + diff --git a/local/bin/x-git-largest-files.py.md b/local/bin/x-git-largest-files.py.md new file mode 100644 index 0000000..6652584 --- /dev/null +++ b/local/bin/x-git-largest-files.py.md @@ -0,0 +1,21 @@ +# x-git-largest-files.py + +Lists the largest files in a git repository. + +```bash +x-git-largest-files.py [options] +``` + +Options: + +- `-c NUM` – number of files to show (default: 10) +- `--files-exceeding N` – list files larger than N KB +- `-p` – sort by on-disk size instead of pack size + +## Example + +```bash +x-git-largest-files.py -c 5 +``` + + diff --git a/local/bin/x-have.md b/local/bin/x-have.md new file mode 100644 index 0000000..7cf62a6 --- /dev/null +++ b/local/bin/x-have.md @@ -0,0 +1,18 @@ +# x-have + +Check if a command exists on the system. Exits with status 0 if found +and 1 otherwise. + +## Usage + +```bash +x-have +``` + +### Example + +```bash +x-have git && echo "git installed" +``` + + diff --git a/local/bin/x-hr.md b/local/bin/x-hr.md new file mode 100644 index 0000000..c52907a --- /dev/null +++ b/local/bin/x-hr.md @@ -0,0 +1,19 @@ +# x-hr + +Print a horizontal rule. Useful for visually separating log output. + +## Usage + +```bash +x-hr [character] +``` + +If no character is given a red `-` is used. + +### Example + +```bash +x-hr "=" +``` + + diff --git a/local/bin/x-ip.md b/local/bin/x-ip.md new file mode 100644 index 0000000..4eb3907 --- /dev/null +++ b/local/bin/x-ip.md @@ -0,0 +1,19 @@ +# x-ip + +Fetch your public IP address using `curl`. + +## Usage + +```bash +x-ip [curl-options] +``` + +Any arguments are passed directly to `curl`. + +### Example + +```bash +x-ip -4 +``` + + diff --git a/local/bin/x-load-configs.md b/local/bin/x-load-configs.md new file mode 100644 index 0000000..55d812f --- /dev/null +++ b/local/bin/x-load-configs.md @@ -0,0 +1,21 @@ +# x-load-configs + +Source shell configuration files for aliases and exports. Intended to +be run after `dfm install` or when switching hosts. + +## Usage + +```bash +x-load-configs +``` + +Set `VERBOSE=1` to print each file as it is sourced. Use `DEBUG=1` to +enable tracing. + +### Example + +```bash +VERBOSE=1 x-load-configs +``` + + diff --git a/local/bin/x-localip.md b/local/bin/x-localip.md new file mode 100644 index 0000000..a2285e0 --- /dev/null +++ b/local/bin/x-localip.md @@ -0,0 +1,25 @@ +# x-localip + +Display local IPv4 and IPv6 addresses with optional interface filtering. + +## Usage + +```bash +x-localip [--ipv4] [--ipv6] [interface] +``` + +- `--ipv4` – show only IPv4 addresses +- `--ipv6` – show only IPv6 addresses +- `interface` – limit output to the named interface + +## Example + +```bash +# Show all addresses +x-localip + +# IPv4 for wlan0 +x-localip --ipv4 wlan0 +``` + + diff --git a/local/bin/x-mkd.md b/local/bin/x-mkd.md new file mode 100644 index 0000000..4b5aabe --- /dev/null +++ b/local/bin/x-mkd.md @@ -0,0 +1,19 @@ +# x-mkd + +Create a directory and immediately `cd` into it. + +## Usage + +```bash +x-mkd +``` + +Set `VERBOSE=1` for status messages. + +## Example + +```bash +x-mkd project && git init +``` + + diff --git a/local/bin/x-multi-ping.md b/local/bin/x-multi-ping.md new file mode 100644 index 0000000..46a0655 --- /dev/null +++ b/local/bin/x-multi-ping.md @@ -0,0 +1,20 @@ +# x-multi-ping + +Multi-protocol ping helper supporting IPv4 and IPv6. + +## Usage + +```bash +x-multi-ping [--loop] [--sleep=N] host1 host2... +``` + +- `--loop` – ping continuously +- `--sleep` – seconds to wait between iterations + +## Example + +```bash +x-multi-ping --loop --sleep=5 example.com +``` + + diff --git a/local/bin/x-multi-ping.pl.md b/local/bin/x-multi-ping.pl.md new file mode 100644 index 0000000..848a421 --- /dev/null +++ b/local/bin/x-multi-ping.pl.md @@ -0,0 +1,20 @@ +# x-multi-ping.pl + +Ping multiple hosts with IPv4/IPv6 support. + +## Usage + +```bash +x-multi-ping.pl [--loop|--forever] [--sleep N] host1 host2 ... +``` + +`--loop` keeps pinging each host until interrupted. `--sleep` controls +the delay between attempts. + +### Example + +```bash +x-multi-ping.pl --loop --sleep 2 example.com 1.1.1.1 +``` + + diff --git a/local/bin/x-open-ports.md b/local/bin/x-open-ports.md new file mode 100644 index 0000000..8d30a4c --- /dev/null +++ b/local/bin/x-open-ports.md @@ -0,0 +1,19 @@ +# x-open-ports + +List listening ports using `lsof` or `ss`. + +## Usage + +```bash +x-open-ports [--json] +``` + +- `--json` – output as JSON instead of Markdown + +## Example + +```bash +x-open-ports --json +``` + + diff --git a/local/bin/x-path-append.md b/local/bin/x-path-append.md new file mode 100644 index 0000000..96996eb --- /dev/null +++ b/local/bin/x-path-append.md @@ -0,0 +1,19 @@ +# x-path-append + +Append directories to the `PATH` variable without duplicates. + +## Usage + +```bash +x-path-append [dir2 ...] +``` + +Set `VERBOSE=1` for verbose logging. + +## Example + +```bash +x-path-append /usr/local/sbin "$HOME/bin" +``` + + diff --git a/local/bin/x-path-prepend.md b/local/bin/x-path-prepend.md new file mode 100644 index 0000000..dff2f90 --- /dev/null +++ b/local/bin/x-path-prepend.md @@ -0,0 +1,19 @@ +# x-path-prepend + +Prepend directories to the `PATH` variable without duplicates. + +## Usage + +```bash +x-path-prepend [dir2 ...] +``` + +Set `VERBOSE=1` for verbose logging. + +## Example + +```bash +x-path-prepend "$HOME/bin" /opt/tools +``` + + diff --git a/local/bin/x-path-remove.md b/local/bin/x-path-remove.md new file mode 100644 index 0000000..cc79c36 --- /dev/null +++ b/local/bin/x-path-remove.md @@ -0,0 +1,19 @@ +# x-path-remove + +Remove directories from the `PATH` variable. + +## Usage + +```bash +x-path-remove [dir2 ...] +``` + +Set `VERBOSE=1` for verbose logging. + +## Example + +```bash +x-path-remove /usr/local/bin +``` + + diff --git a/local/bin/x-path.md b/local/bin/x-path.md new file mode 100644 index 0000000..1e3ba8d --- /dev/null +++ b/local/bin/x-path.md @@ -0,0 +1,30 @@ +# x-path + +Manage entries in the `PATH` variable through subcommands. + +## Usage + +```bash +x-path [directory2 ...] +``` + +### Commands + +- `append` / `a` – Append directories to `PATH` +- `prepend` / `p` – Prepend directories to `PATH` +- `remove` – Remove directories from `PATH` +- `check` – Validate directories (default: all in `PATH`) + +Set `VERBOSE=1` for progress output. + +## Examples + +```bash +# Prepend /opt/bin to PATH +x-path prepend /opt/bin + +# Remove /usr/local/bin from PATH +x-path remove /usr/local/bin +``` + + diff --git a/local/bin/x-quota-usage.php.md b/local/bin/x-quota-usage.php.md new file mode 100644 index 0000000..16a91c7 --- /dev/null +++ b/local/bin/x-quota-usage.php.md @@ -0,0 +1,14 @@ +# x-quota-usage.php + +Display filesystem quota usage in a human readable table. + +## Usage + +```bash +x-quota-usage.php +``` + +Runs the `quota` command and formats the output. Requires PHP with the +`shell_exec` function enabled. + + diff --git a/local/bin/x-record.md b/local/bin/x-record.md new file mode 100644 index 0000000..d3927cd --- /dev/null +++ b/local/bin/x-record.md @@ -0,0 +1,19 @@ +# x-record + +Interactive screen recording wrapper around `giph`. + +## Usage + +```bash +x-record +``` + +The script asks for file type and area when omitted. + +## Example + +```bash +x-record gif fullscreen +``` + + diff --git a/local/bin/x-set-php-aliases.md b/local/bin/x-set-php-aliases.md new file mode 100644 index 0000000..a41ad70 --- /dev/null +++ b/local/bin/x-set-php-aliases.md @@ -0,0 +1,14 @@ +# x-set-php-aliases + +--- + +## Usage + +```bash +source x-set-php-aliases +``` + +Generates shell aliases (`php80`, `php81` ...) for each Homebrew PHP +installation. Caches the list under `$XDG_CACHE_HOME/x-set-php-aliases`. + + diff --git a/local/bin/x-sha256sum-matcher.md b/local/bin/x-sha256sum-matcher.md new file mode 100644 index 0000000..701c671 --- /dev/null +++ b/local/bin/x-sha256sum-matcher.md @@ -0,0 +1,22 @@ +# x-sha256sum-matcher + +Compare two files by calculating their SHA256 checksums. + +## Usage + +```bash +x-sha256sum-matcher [options] file1 file2 +``` + +Options: + +- `-v` – verbose output +- `-h, --help` – show help + +### Example + +```bash +x-sha256sum-matcher original.iso download.iso +``` + + diff --git a/local/bin/x-ssl-expiry-date.md b/local/bin/x-ssl-expiry-date.md new file mode 100644 index 0000000..1c2bfc9 --- /dev/null +++ b/local/bin/x-ssl-expiry-date.md @@ -0,0 +1,22 @@ +# x-ssl-expiry-date + +Check the expiry date of an SSL certificate for one or more hosts. + +## Usage + +```bash +x-ssl-expiry-date [-d] [-p PORT] host1 host2 ... +``` + +Options: + +- `-d` – show days left instead of the full date +- `-p ` – use custom port (default: 443) + +### Example + +```bash +x-ssl-expiry-date -d github.com +``` + + diff --git a/local/bin/x-term-colors.md b/local/bin/x-term-colors.md new file mode 100644 index 0000000..6ced9e4 --- /dev/null +++ b/local/bin/x-term-colors.md @@ -0,0 +1,14 @@ +# x-term-colors + +Display a table of 24‑bit color codes for testing terminal color +support. + +## Usage + +```bash +x-term-colors +``` + +Pipe the output to `less -R` to view with color highlighting. + + diff --git a/local/bin/x-thumbgen.md b/local/bin/x-thumbgen.md new file mode 100644 index 0000000..fcc01cd --- /dev/null +++ b/local/bin/x-thumbgen.md @@ -0,0 +1,26 @@ +# x-thumbgen + +Generate thumbnails using ImageMagick (magick) with MIME type filtering. + +## Usage + +```bash +x-thumbgen [options] source_directory +``` + +Options: + +- `-o DIR` – output directory (default: same as source) +- `-s STR` – suffix for thumbnails +- `-h` – show help + +Environment variables like `THUMB_BACKGROUND` control the background +color. + +### Example + +```bash +THUMB_BACKGROUND=black x-thumbgen -o ~/thumbs ~/images +``` + + diff --git a/local/bin/x-until-error.md b/local/bin/x-until-error.md new file mode 100644 index 0000000..0f54625 --- /dev/null +++ b/local/bin/x-until-error.md @@ -0,0 +1,20 @@ +# x-until-error + +Repeatedly execute a command until it returns a non-zero exit status. + +## Usage + +```bash +x-until-error [--sleep SECONDS] command [args...] +``` + +Use `--sleep` to wait between runs. The command is executed at least +once. + +### Example + +```bash +x-until-error --sleep 2 ping -c1 example.com +``` + + diff --git a/local/bin/x-until-success.md b/local/bin/x-until-success.md new file mode 100644 index 0000000..64db783 --- /dev/null +++ b/local/bin/x-until-success.md @@ -0,0 +1,20 @@ +# x-until-success + +Repeat a command until it succeeds (exit status 0). The command is +always executed at least once. + +## Usage + +```bash +x-until-success [--sleep SECONDS] command [args...] +``` + +Use `--sleep` to control the delay between attempts. + +### Example + +```bash +x-until-success --sleep 5 curl -I https://example.com +``` + + diff --git a/local/bin/x-validate-sha256sum.sh.md b/local/bin/x-validate-sha256sum.sh.md new file mode 100644 index 0000000..0432160 --- /dev/null +++ b/local/bin/x-validate-sha256sum.sh.md @@ -0,0 +1,14 @@ +# x-validate-sha256sum.sh + +This script contains a helper for sha256 validating your downloads + +## Usage + +```bash +x-validate-sha256sum.sh file sha256sum +``` + +The script computes the SHA256 hash of `file` and compares it to the +expected value. It exits non-zero if the sums differ. + + diff --git a/local/bin/x-welcome-banner.md b/local/bin/x-welcome-banner.md new file mode 100644 index 0000000..32d8d3e --- /dev/null +++ b/local/bin/x-welcome-banner.md @@ -0,0 +1,13 @@ +# x-welcome-banner + +Print a colorful MOTD with greeting, system info and today's weather. + +## Usage + +```bash +x-welcome-banner +``` + +Requires optional tools: `neofetch`, `figlet`, `lolcat` and `curl` for extra info. + + diff --git a/local/bin/x-when-down.md b/local/bin/x-when-down.md new file mode 100644 index 0000000..e7b435f --- /dev/null +++ b/local/bin/x-when-down.md @@ -0,0 +1,17 @@ +# x-when-down + +Wait until a host stops responding to ping, then run a command. + +## Usage + +```bash +x-when-down +``` + +## Example + +```bash +x-when-down 1.2.3.4 echo "server down" +``` + + diff --git a/local/bin/x-when-up.md b/local/bin/x-when-up.md new file mode 100644 index 0000000..bd56d4f --- /dev/null +++ b/local/bin/x-when-up.md @@ -0,0 +1,19 @@ +# x-when-up + +Wait for a host to respond to ping before running a command. + +## Usage + +```bash +x-when-up +``` + +If the command is `ssh`, the host argument may be omitted. + +## Example + +```bash +x-when-up 1.2.3.4 ssh 1.2.3.4 +``` + + diff --git a/package.json b/package.json index 15463fe..a1ac5e1 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "fix:markdown": "npx markdownlint -df .", "lint:prettier": "npx prettier . --check", "fix:prettier": "npx prettier . --write", - "test": "echo \"Error: no test specified\" && exit 0" + "test": "bash test-all.sh" }, "repository": { "type": "git", @@ -29,6 +29,7 @@ "devDependencies": { "@ivuorinen/base-configs": "^2.0.0", "@types/node": "^24.0.1", + "bats": "^1.12.0", "typescript": "^5.8.3" }, "packageManager": "yarn@1.22.22" diff --git a/scripts/create-aerospace-keymaps.md b/scripts/create-aerospace-keymaps.md new file mode 100644 index 0000000..d3a8010 --- /dev/null +++ b/scripts/create-aerospace-keymaps.md @@ -0,0 +1,11 @@ +# create-aerospace-keymaps + +Generates `docs/aerospace-keybindings.md` using `aerospace config --json`. + +## Usage + +```bash +scripts/create-aerospace-keymaps.php +``` + +Requires the `aerospace` CLI tool to be installed. diff --git a/scripts/create-nvim-keymaps.md b/scripts/create-nvim-keymaps.md new file mode 100644 index 0000000..e086a9e --- /dev/null +++ b/scripts/create-nvim-keymaps.md @@ -0,0 +1,11 @@ +# create-nvim-keymaps + +Outputs current Neovim key mappings to `docs/nvim-keybindings.md`. + +## Usage + +```bash +scripts/create-nvim-keymaps.sh +``` + +Requires Neovim to be installed. diff --git a/scripts/create-wezterm-keymaps.md b/scripts/create-wezterm-keymaps.md new file mode 100644 index 0000000..b10f399 --- /dev/null +++ b/scripts/create-wezterm-keymaps.md @@ -0,0 +1,11 @@ +# create-wezterm-keymaps + +Generates `docs/wezterm-keybindings.md` by invoking `wezterm show-keys`. + +## Usage + +```bash +scripts/create-wezterm-keymaps.sh +``` + +Requires wezterm to be installed. diff --git a/scripts/install-cargo-packages.md b/scripts/install-cargo-packages.md new file mode 100644 index 0000000..1d30426 --- /dev/null +++ b/scripts/install-cargo-packages.md @@ -0,0 +1,12 @@ +# install-cargo-packages + +Install Rust packages listed in `config/asdf/cargo-packages`. + +## Usage + +```bash +scripts/install-cargo-packages.sh +``` + +The script installs each package with `cargo install` and runs +`cargo-install-update` when available to update existing packages. diff --git a/scripts/install-cheat-purebashbible.md b/scripts/install-cheat-purebashbible.md new file mode 100644 index 0000000..e418a43 --- /dev/null +++ b/scripts/install-cheat-purebashbible.md @@ -0,0 +1,12 @@ +# install-cheat-purebashbible + +Fetches the Pure Bash Bible repository and installs its cheatsheets for the +`cheat` utility. + +## Usage + +```bash +scripts/install-cheat-purebashbible.sh +``` + +Requires `git` and `cheat` to be available in PATH. diff --git a/scripts/install-composer.md b/scripts/install-composer.md new file mode 100644 index 0000000..703a585 --- /dev/null +++ b/scripts/install-composer.md @@ -0,0 +1,11 @@ +# install-composer + +Installs the PHP package manager [Composer](https://getcomposer.org/). + +## Usage + +```bash +scripts/install-composer.sh +``` + +The script downloads the latest Composer PHAR and places it in `$HOME/.local/bin`. diff --git a/scripts/install-fonts.md b/scripts/install-fonts.md new file mode 100644 index 0000000..43ac61e --- /dev/null +++ b/scripts/install-fonts.md @@ -0,0 +1,11 @@ +# install-fonts + +Installs Nerd Fonts used by various terminal and editor setups. + +## Usage + +```bash +scripts/install-fonts.sh +``` + +Fonts are downloaded to `$HOME/.local/share/fonts` and refreshed automatically. diff --git a/scripts/install-gh-extensions.md b/scripts/install-gh-extensions.md new file mode 100644 index 0000000..90c3ec8 --- /dev/null +++ b/scripts/install-gh-extensions.md @@ -0,0 +1,12 @@ +# install-gh-extensions + +Installs a curated set of GitHub CLI extensions defined in +`config/gh/extensions`. + +## Usage + +```bash +scripts/install-gh-extensions.sh +``` + +The script installs each extension using the `gh extension install` command. diff --git a/scripts/install-git-crypt.md b/scripts/install-git-crypt.md new file mode 100644 index 0000000..3163e5d --- /dev/null +++ b/scripts/install-git-crypt.md @@ -0,0 +1,12 @@ +# install-git-crypt + +Installs `git-crypt` for transparent encryption of files in Git repositories. + +## Usage + +```bash +scripts/install-git-crypt.sh +``` + +After installation you can run `git-crypt init` inside a repository to begin +encrypting files. diff --git a/scripts/install-go-packages.md b/scripts/install-go-packages.md new file mode 100644 index 0000000..94d0044 --- /dev/null +++ b/scripts/install-go-packages.md @@ -0,0 +1,12 @@ +# install-go-packages + +Installs Go binaries defined in `config/go/packages`. + +## Usage + +```bash +scripts/install-go-packages.sh +``` + +The script uses `go install` for each package path listed in the configuration +file. diff --git a/scripts/install-macos-defaults.md b/scripts/install-macos-defaults.md new file mode 100644 index 0000000..19bf870 --- /dev/null +++ b/scripts/install-macos-defaults.md @@ -0,0 +1,11 @@ +# install-macos-defaults + +Applies a set of macOS defaults for a consistent developer environment. + +## Usage + +```bash +scripts/install-macos-defaults.sh +``` + +Requires macOS and the `defaults` command. diff --git a/scripts/install-npm-packages.md b/scripts/install-npm-packages.md new file mode 100644 index 0000000..a1ba2da --- /dev/null +++ b/scripts/install-npm-packages.md @@ -0,0 +1,11 @@ +# install-npm-packages + +Installs global npm packages listed in `config/npm/packages`. + +## Usage + +```bash +scripts/install-npm-packages.sh +``` + +Uses `npm install -g` for each package in the configuration file. diff --git a/scripts/install-ntfy.md b/scripts/install-ntfy.md new file mode 100644 index 0000000..d0764c9 --- /dev/null +++ b/scripts/install-ntfy.md @@ -0,0 +1,11 @@ +# install-ntfy + +Installs the lightweight notification tool [`ntfy`](https://ntfy.sh/). + +## Usage + +```bash +scripts/install-ntfy.sh +``` + +After running you can send notifications using `ntfy publish`. diff --git a/scripts/install-pip-packages.md b/scripts/install-pip-packages.md new file mode 100644 index 0000000..ee818f4 --- /dev/null +++ b/scripts/install-pip-packages.md @@ -0,0 +1,11 @@ +# install-pip-packages + +Installs Python packages from `config/pip/packages` using `pip`. + +## Usage + +```bash +scripts/install-pip-packages.sh +``` + +The script uses `pip install --user` for each package entry. diff --git a/scripts/install-xcode-cli-tools.md b/scripts/install-xcode-cli-tools.md new file mode 100644 index 0000000..3413e7f --- /dev/null +++ b/scripts/install-xcode-cli-tools.md @@ -0,0 +1,11 @@ +# install-xcode-cli-tools + +Installs the Xcode Command Line Tools on macOS using `osascript` prompts. + +## Usage + +```bash +scripts/install-xcode-cli-tools.sh +``` + +Requires macOS with administrator privileges. diff --git a/scripts/install-z.md b/scripts/install-z.md new file mode 100644 index 0000000..99b968a --- /dev/null +++ b/scripts/install-z.md @@ -0,0 +1,11 @@ +# install-z + +Installs [z](https://github.com/rupa/z), a directory jumping tool. + +## Usage + +```bash +scripts/install-z.sh +``` + +Once installed add `. ~/.z` to your shell startup file to enable the command. diff --git a/scripts/shared.md b/scripts/shared.md new file mode 100644 index 0000000..46a7764 --- /dev/null +++ b/scripts/shared.md @@ -0,0 +1,13 @@ +# shared + +Collection of helper functions shared across install scripts. + +## Usage + +Source the file in your script: + +```bash +source "${DOTFILES}/scripts/shared.sh" +``` + +Provides messaging helpers and common environment checks. diff --git a/scripts/shared.sh b/scripts/shared.sh index c2d7c85..c8b132c 100755 --- a/scripts/shared.sh +++ b/scripts/shared.sh @@ -10,6 +10,7 @@ [ -z "$SHARED_SCRIPTS_SOURCED" ] && { source "${DOTFILES}/config/shared.sh" + # Warn the user if the shared configuration hasn't been loaded yet msgr warn "(!) shared.sh not sourced" # Set variable that checks if the shared.sh script has been diff --git a/scripts/update-readme-aliases.md b/scripts/update-readme-aliases.md new file mode 100644 index 0000000..9880d69 --- /dev/null +++ b/scripts/update-readme-aliases.md @@ -0,0 +1,11 @@ +# update-readme-aliases + +Regenerates the alias table located at `docs/alias.md`. + +## Usage + +```bash +scripts/update-readme-aliases.sh +``` + +This script parses `config/alias` and writes the markdown table to the docs. diff --git a/test-all.sh b/test-all.sh new file mode 100755 index 0000000..7a8ee03 --- /dev/null +++ b/test-all.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# Run all bats tests + +set -euo pipefail + +if [ -x "node_modules/bats/bin/bats" ]; then + git ls-files '*.bats' -z | xargs -0 node_modules/bats/bin/bats +elif command -v npx >/dev/null; then + git ls-files '*.bats' -z | xargs -0 npx --yes bats +elif command -v bats >/dev/null; then + git ls-files '*.bats' -z | xargs -0 bats +else + echo "bats not installed. Run 'yarn install' first." >&2 + exit 1 +fi diff --git a/tests/dfm.bats b/tests/dfm.bats new file mode 100644 index 0000000..3b0c2a7 --- /dev/null +++ b/tests/dfm.bats @@ -0,0 +1,11 @@ +#!/usr/bin/env bats + +setup() { + export DOTFILES="$PWD" +} + +@test "dfm help shows usage" { + run bash local/bin/dfm help + [ "$status" -eq 0 ] + [[ "$output" == *"Usage: dfm"* ]] +} diff --git a/tests/x-gh-get-latest-version.bats b/tests/x-gh-get-latest-version.bats new file mode 100644 index 0000000..9dfa4c5 --- /dev/null +++ b/tests/x-gh-get-latest-version.bats @@ -0,0 +1,7 @@ +#!/usr/bin/env bats + +@test "x-gh-get-latest-version help" { + run bash local/bin/x-gh-get-latest-version --help + [ "$status" -eq 1 ] + [[ "$output" == "Usage: x-gh-get-latest-version"* ]] +} diff --git a/tests/x-localip.bats b/tests/x-localip.bats new file mode 100644 index 0000000..fc9d9c8 --- /dev/null +++ b/tests/x-localip.bats @@ -0,0 +1,7 @@ +#!/usr/bin/env bats + +@test "x-localip prints version" { + run bash local/bin/x-localip --version + [ "$status" -eq 0 ] + [[ "$output" == "x-localip version"* ]] +} diff --git a/tests/x-mkd.bats b/tests/x-mkd.bats new file mode 100644 index 0000000..ce7a4b9 --- /dev/null +++ b/tests/x-mkd.bats @@ -0,0 +1,8 @@ +#!/usr/bin/env bats + +@test "x-mkd creates directory" { + dir="$BATS_TMPDIR/mkd-test" + run env VERBOSE=1 bash local/bin/x-mkd "$dir" + [ "$status" -eq 0 ] + [ -d "$dir" ] +} diff --git a/tests/x-path.bats b/tests/x-path.bats new file mode 100644 index 0000000..629e214 --- /dev/null +++ b/tests/x-path.bats @@ -0,0 +1,22 @@ +#!/usr/bin/env bats + +@test "x-path-append adds directory" { + mkdir -p "$BATS_TMPDIR/dir" + PATH="/usr/bin" + VERBOSE=1 source local/bin/x-path-append "$BATS_TMPDIR/dir" + [ "$PATH" = "/usr/bin:$BATS_TMPDIR/dir" ] +} + +@test "x-path-prepend adds directory to start" { + mkdir -p "$BATS_TMPDIR/dir" + PATH="/usr/bin:/bin" + VERBOSE=1 source local/bin/x-path-prepend "$BATS_TMPDIR/dir" + [ "$PATH" = "$BATS_TMPDIR/dir:/usr/bin:/bin" ] +} + +@test "x-path-remove removes directory" { + mkdir -p "$BATS_TMPDIR/dir" + PATH="$BATS_TMPDIR/dir:/usr/bin" + VERBOSE=1 source local/bin/x-path-remove "$BATS_TMPDIR/dir" + [ "$PATH" = "/usr/bin" ] +}