Merge nucleic/sleek-thistle-egret-fyej into dev
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
# brush documentation
|
||||
|
||||
The docs are grouped into:
|
||||
|
||||
* [How-to guides](how-to/README.md)
|
||||
* [Tutorials](tutorials/README.md)
|
||||
* [Reference material](reference/README.md)
|
||||
|
||||
If you're just getting started building this project, you should consult the [How to Build](how-to/build.md) guide.
|
||||
|
||||
---
|
||||
|
||||
> _Note: The structure of our docs is inspired by the [Diátaxis](https://diataxis.fr/) approach; we've found over time that best helps readers find the material most relevant to them, as well as provides a rough shape for where to place the right docs._
|
||||
@@ -0,0 +1,146 @@
|
||||
# Works with https://github.com/charmbracelet/vhs
|
||||
|
||||
Output sample.gif
|
||||
|
||||
Set FontFamily "CaskaydiaMono Nerd Font Mono"
|
||||
Set FontSize 20
|
||||
Set Theme "Monokai Pro"
|
||||
Set Width 1600
|
||||
Set Height 600
|
||||
Set CursorBlink false
|
||||
|
||||
# Setup environment to launch brush in
|
||||
Env HISTFILE ""
|
||||
Env PS1 '$0$ '
|
||||
|
||||
# Launch brush and set up bash-completion
|
||||
Hide
|
||||
Type `brush --enable-highlighting --norc --noprofile --no-config`
|
||||
Enter
|
||||
Type `source /usr/share/bash-completion/bash_completion && clear`
|
||||
Enter
|
||||
Show
|
||||
|
||||
# Enable starship
|
||||
Type `# Let's start with a better prompt. starship to the rescue!`
|
||||
Sleep 0.8s
|
||||
Enter
|
||||
Type `eval "$(starship init bash)"`
|
||||
Sleep 0.8s
|
||||
Enter
|
||||
Sleep 1s
|
||||
|
||||
# git describe
|
||||
Type `git d`
|
||||
Tab
|
||||
Sleep 1.3s
|
||||
Enter
|
||||
Sleep 0.4s
|
||||
Type `--l`
|
||||
Sleep 0.4s
|
||||
Tab
|
||||
Sleep 0.8s
|
||||
Type `brush-she`
|
||||
Sleep 0.5s
|
||||
Tab
|
||||
Sleep 0.2s
|
||||
Right
|
||||
Sleep 0.2s
|
||||
Right
|
||||
Sleep 0.8s
|
||||
Enter
|
||||
Sleep 0.8s
|
||||
Enter
|
||||
Sleep 1s
|
||||
|
||||
# vim
|
||||
Type `vim Ca`
|
||||
Sleep 0.5s
|
||||
Tab
|
||||
Sleep 0.8s
|
||||
Right
|
||||
Sleep 0.5s
|
||||
Enter
|
||||
Sleep 1s
|
||||
Enter
|
||||
|
||||
Type `1G`
|
||||
Type `i`
|
||||
Enter
|
||||
Up
|
||||
Type `# Let's try suspending vim...`
|
||||
Enter
|
||||
Escape
|
||||
Sleep 1s
|
||||
Ctrl+Z
|
||||
Sleep 0.7s
|
||||
|
||||
Type `# Yep, it's suspended.`
|
||||
Sleep 0.4s
|
||||
Type ` Let's bring it back.`
|
||||
Enter
|
||||
Sleep 0.8s
|
||||
|
||||
Type `fg`
|
||||
Sleep 0.4s
|
||||
Enter
|
||||
Sleep 0.6s
|
||||
|
||||
Type `:q!`
|
||||
Sleep 0.3s
|
||||
Enter
|
||||
Sleep 0.5s
|
||||
Ctrl+L
|
||||
Sleep 0.2s
|
||||
|
||||
Type `# Let's properly greet the world.`
|
||||
Enter
|
||||
Sleep 0.4s
|
||||
|
||||
# Figure out version
|
||||
Type `verline=$(help | head -n1)`
|
||||
Sleep 0.2s
|
||||
Enter
|
||||
Sleep 0.3s
|
||||
Type `[[ "${verline}" =~ ^.*version\ ([[:digit:]\.]+).*$ ]] && ver=${BASH_REMATCH[1]}`
|
||||
Sleep 0.4s
|
||||
Enter
|
||||
Sleep 0.2s
|
||||
Type `declare -p ver`
|
||||
Enter
|
||||
Sleep 0.4s
|
||||
|
||||
# Declare function
|
||||
Type `function greet() {`
|
||||
Enter
|
||||
Type ` echo "Hello from brush ${ver}!"`
|
||||
Enter
|
||||
Type `}`
|
||||
Sleep 1s
|
||||
Enter
|
||||
Type `type greet`
|
||||
Sleep 0.4s
|
||||
Enter
|
||||
Sleep 1s
|
||||
|
||||
# Use function
|
||||
Ctrl+L
|
||||
Type `for ((i = 0; i < 5; i++)); do greet; done`
|
||||
Sleep 1s
|
||||
Enter
|
||||
Sleep 0.8s
|
||||
|
||||
Type `# Surely we can make that more colorful.`
|
||||
Enter
|
||||
Sleep 1s
|
||||
|
||||
# Now with lolcat
|
||||
Type `for `
|
||||
Sleep 1s
|
||||
Right
|
||||
Sleep 0.8s
|
||||
Type ` | lolcat -F 0.3 -S 12`
|
||||
Sleep 0.6s
|
||||
Enter
|
||||
|
||||
Sleep 3s
|
||||
@@ -0,0 +1,60 @@
|
||||
# Works with https://github.com/charmbracelet/vhs
|
||||
# This tape assumes that fzf and brush are already pre-installed and ready to go.
|
||||
|
||||
Output sample.gif
|
||||
|
||||
# Set FontFamily "CaskaydiaMono Nerd Font Mono"
|
||||
Set FontSize 20
|
||||
Set Theme "Monokai Pro"
|
||||
Set Width 1600
|
||||
Set Height 600
|
||||
Set CursorBlink false
|
||||
|
||||
# Setup environment to launch brush in
|
||||
Env HISTFILE ""
|
||||
Env PS1 '$0$ '
|
||||
|
||||
# Launch brush and set up bash-completion
|
||||
Hide
|
||||
Type `brush --enable-highlighting --norc --noprofile --no-config`
|
||||
Enter
|
||||
Show
|
||||
|
||||
# Enable fzf
|
||||
Type `# Let's enable fzf with standard bash mode`
|
||||
Sleep 0.8s
|
||||
Enter
|
||||
Type `eval "$(fzf --bash)"`
|
||||
Sleep 0.8s
|
||||
Enter
|
||||
Sleep 1s
|
||||
|
||||
Enter
|
||||
Enter
|
||||
|
||||
Type `# ^^^ we see an error above. Some key combos are missing but more are functional.`
|
||||
Enter
|
||||
|
||||
Enter
|
||||
Enter
|
||||
|
||||
# Type some things.
|
||||
Type `echo 'We will type something'`
|
||||
Enter
|
||||
Type `echo '...just to populate history'`
|
||||
Enter
|
||||
Type `echo 'And now, hit Ctrl+R.'`
|
||||
Enter
|
||||
Sleep 1s
|
||||
|
||||
# Ctrl+R
|
||||
Ctrl+R
|
||||
Sleep 1.5s
|
||||
Up
|
||||
Sleep 0.8s
|
||||
Enter
|
||||
|
||||
Sleep 2s
|
||||
Enter
|
||||
Sleep 2s
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
@@ -0,0 +1,8 @@
|
||||
# How-to guides
|
||||
|
||||
* [How to build](build.md)
|
||||
* [How to run tests](run-tests.md)
|
||||
* [How to run benchmarks](run-benchmarks.md)
|
||||
* [How to release](release.md)
|
||||
* [How to upgrade the MSRV](upgrade-msrv.md)
|
||||
* [How to record "tapes"](record-tapes.md)
|
||||
@@ -0,0 +1,5 @@
|
||||
# How to build and run
|
||||
|
||||
1. Install Rust toolchain. We recommend using [rustup](https://rustup.rs/).
|
||||
1. Build `brush`: `cargo build`
|
||||
1. Run `brush`: `cargo run`
|
||||
@@ -0,0 +1,16 @@
|
||||
# How to record "tapes"
|
||||
|
||||
Under the `docs/demos` directory of this repo, we have some `.tape` files checked in.
|
||||
These are interactive scripts for recording screencast-style demos of `brush` using
|
||||
the [`VHS` tool](https://github.com/charmbracelet/vhs).
|
||||
|
||||
## Install `vhs`
|
||||
|
||||
You first need to install `vhs`. For consistency, we've found it easiest to install
|
||||
`golang` and then follow the instructions on the `vhs` github page to install via
|
||||
`go install`. (Also note that there are some native prerequisites required.)
|
||||
|
||||
## Run `vhs`
|
||||
|
||||
To run `vhs` against the `.tape` file you may need to use `VHS_NO_SANDBOX=1`. For more
|
||||
details see [this issue on GitHub](https://github.com/charmbracelet/vhs/issues/504).
|
||||
@@ -0,0 +1,14 @@
|
||||
# How to release
|
||||
|
||||
_(This is only relevant for project maintainers.)_
|
||||
|
||||
* Install [release-plz](https://github.com/MarcoIeni/release-plz)
|
||||
* Checkout the `main` branch (with a clean working tree).
|
||||
* Run: `release-plz update`. Review its changes, notable including the changelog updates.
|
||||
* PR through any generated changes with a `chore: prepare release` commit summary.
|
||||
* After the changes have merged into `main`, update your local `main` branch.
|
||||
* Acquire GitHub and `crates.io` tokens that have sufficient permissions to publish.
|
||||
* Authenticate with `crates.io` by running: `cargo login`.
|
||||
* Run: `release-plz release --backend github --git-token <TOKEN>`.
|
||||
* Update the published GitHub release to include an auto-generated changelog.
|
||||
* Run: `cargo install --locked brush-shell` to verify the release.
|
||||
@@ -0,0 +1,31 @@
|
||||
# How to run benchmarks
|
||||
|
||||
## Using xtask (Recommended)
|
||||
|
||||
The project provides `cargo xtask` commands for running benchmarks:
|
||||
|
||||
```bash
|
||||
# Run benchmarks
|
||||
cargo xtask analyze bench
|
||||
|
||||
# Run benchmarks and save output to a file
|
||||
cargo xtask analyze bench --output benchmarks.txt
|
||||
```
|
||||
|
||||
## Manual Approach (Alternate)
|
||||
|
||||
To run performance benchmarks:
|
||||
|
||||
```bash
|
||||
cargo bench --workspace --benches
|
||||
```
|
||||
|
||||
## Collecting flamegraphs
|
||||
|
||||
To collect flamegraphs from performance benchmarks (running for 10 seconds):
|
||||
|
||||
```bash
|
||||
cargo bench --workspace --benches -- --profile-time 10
|
||||
```
|
||||
|
||||
The flamegraphs will be created as `.svg` files and placed under `target/criterion/<benchmark_name>/profile`.
|
||||
@@ -0,0 +1,48 @@
|
||||
# How to run tests
|
||||
|
||||
## Using xtask (Recommended)
|
||||
|
||||
The project provides `cargo xtask` commands for running tests:
|
||||
|
||||
```bash
|
||||
# Run unit tests (fast tests excluding integration binaries)
|
||||
cargo xtask test unit
|
||||
|
||||
# Run integration tests (all workspace tests including compat tests)
|
||||
cargo xtask test integration
|
||||
|
||||
# Run tests with code coverage
|
||||
cargo xtask test integration --coverage --coverage-output codecov.xml
|
||||
```
|
||||
|
||||
## CI Workflows
|
||||
|
||||
For comprehensive validation, use the CI workflows:
|
||||
|
||||
```bash
|
||||
# Quick inner-loop checks (~7s warm): fmt, build, lint, unit tests
|
||||
cargo xtask ci quick
|
||||
|
||||
# Full pre-commit checks (~45s warm): quick + deps, schemas, integration tests
|
||||
cargo xtask ci pre-commit
|
||||
```
|
||||
|
||||
## Manual Approach (Alternate)
|
||||
|
||||
To run all workspace tests:
|
||||
|
||||
```bash
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
To run just bash compatibility tests:
|
||||
|
||||
```bash
|
||||
cargo test --test brush-compat-tests
|
||||
```
|
||||
|
||||
To run a specific compatibility test case
|
||||
|
||||
```bash
|
||||
cargo test --test brush-compat-tests -- '<name of test case>'
|
||||
```
|
||||
@@ -0,0 +1,69 @@
|
||||
# How to upgrade MSRV
|
||||
|
||||
This document outlines the process for upgrading the Minimum Supported Rust Version (MSRV) for the `brush` project.
|
||||
|
||||
## Overview
|
||||
|
||||
Before upgrading MSRV, review the [MSRV Policy](../reference/msrv-policy.md) to ensure the update aligns with project guidelines.
|
||||
|
||||
## Process
|
||||
|
||||
### 1. Find all MSRV references
|
||||
|
||||
Search for the current MSRV version throughout the codebase:
|
||||
|
||||
```bash
|
||||
grep -r "<current-version>" .
|
||||
```
|
||||
|
||||
Typically, MSRV is specified in:
|
||||
- `Cargo.toml` (workspace `rust-version` field)
|
||||
- `.github/workflows/ci.yaml` (CI test matrix)
|
||||
- `.github/copilot-instructions.md` (GitHub Copilot instructions)
|
||||
|
||||
### 2. Update MSRV references
|
||||
|
||||
Update all occurrences to the new version:
|
||||
|
||||
- **`Cargo.toml`**: Update the `rust-version` field under `[workspace.package]`
|
||||
- **`.github/workflows/ci.yaml`**: Update the version in the test matrix
|
||||
|
||||
### 3. Verify the build
|
||||
|
||||
Test that the project builds successfully with the updated MSRV:
|
||||
|
||||
```bash
|
||||
cargo check --workspace
|
||||
```
|
||||
|
||||
### 4. Run tests
|
||||
|
||||
Verify that tests pass with the new MSRV:
|
||||
|
||||
```bash
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
### 5. Run static checks
|
||||
|
||||
After upgrading MSRV, it's important to rerun all static checks, as newer Rust versions may introduce new lints and clippy warnings that weren't present in the previous MSRV. These warnings need to be resolved to maintain code quality.
|
||||
|
||||
Run clippy with all warnings treated as errors:
|
||||
|
||||
```bash
|
||||
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
```
|
||||
|
||||
Also run other static checks such as formatting:
|
||||
|
||||
```bash
|
||||
cargo fmt --all -- --check
|
||||
```
|
||||
|
||||
**Note**: Upgrading MSRV often enables new clippy lints (particularly in nursery categories) that may flag code patterns that were previously acceptable. Review and fix these warnings, as they often suggest improvements like adding `const` to functions or other optimizations that are newly available in the updated Rust version.
|
||||
|
||||
### 6. Update documentation
|
||||
|
||||
When merging the MSRV update:
|
||||
- Call out the update in an appropriate Conventional Commit commit description
|
||||
- Include justification for the change in the release notes
|
||||
@@ -0,0 +1,9 @@
|
||||
# Reference
|
||||
|
||||
These documents serve as reference material for the `brush` project.
|
||||
|
||||
* [Configuration file](configuration.md)
|
||||
* [Experimental features](experimental.md)
|
||||
* [Integration testing](integration-testing.md)
|
||||
* [Minimum Supported Rust Version (MSRV) policy](msrv-policy.md)
|
||||
* [Compatibility](compatibility.md)
|
||||
@@ -0,0 +1,209 @@
|
||||
# `bash` Compatibility Reference
|
||||
|
||||
This document details `brush`'s compatibility with `bash`, including supported features, known limitations, and how to report issues.
|
||||
|
||||
## Overview
|
||||
|
||||
`brush` aims for high compatibility with `bash`. We validate this through **1700+ compatibility test cases** that compare behavior against `bash` as an oracle.
|
||||
|
||||
**Compatibility snapshot:** Production-ready for most use cases. Your `.bashrc`, aliases, functions, and completions should "just work."
|
||||
|
||||
## Fully Supported Features ✅
|
||||
|
||||
### Shell Syntax & Control Flow
|
||||
|
||||
- `if`/`then`/`elif`/`else`/`fi` conditionals
|
||||
- `for`, `while`, `until` loops
|
||||
- Arithmetic `for` loops: `for ((i=0; i<10; i++))`
|
||||
- `case`/`esac` pattern matching
|
||||
- `&&`, `||` conditional execution
|
||||
- Subshells `()` and command grouping `{}`
|
||||
- Pipelines and pipeline negation `!`
|
||||
- Coprocesses: `coproc { ... }` and `coproc NAME { ... }`
|
||||
|
||||
### Expansions
|
||||
|
||||
- Brace expansion: `{a,b,c}`, `{1..10}`, `{a..z}`
|
||||
- Parameter expansion: `${var:-default}`, `${var:+set}`, `${var#pattern}`, `${var%pattern}`, `${var//find/replace}`, etc.
|
||||
- Command substitution: `$(cmd)`, `` `cmd` ``
|
||||
- Arithmetic expansion: `$((expr))`
|
||||
- Process substitution: `<(cmd)`, `>(cmd)`
|
||||
- Tilde expansion: `~`, `~user`
|
||||
- Globbing: `*`, `?`, `[...]`
|
||||
- Extended globbing: `?(pat)`, `*(pat)`, `+(pat)`, `@(pat)`, `!(pat)`
|
||||
- `globstar`: `**` recursive matching
|
||||
|
||||
### Builtins (50+)
|
||||
|
||||
- **I/O:** `echo`, `printf`, `read`, `mapfile`/`readarray`
|
||||
- **Variables:** `declare`, `local`, `export`, `unset`, `readonly`, `typeset`
|
||||
- **Control:** `break`, `continue`, `return`, `exit`
|
||||
- **Navigation:** `cd`, `pushd`, `popd`, `dirs`, `pwd`
|
||||
- **Jobs:** `jobs`, `fg`, `bg`, `wait`, `kill`
|
||||
- **Completion:** `complete`, `compgen`, `compopt`
|
||||
- **History:** `history`, `fc`
|
||||
- **Testing:** `test`, `[`, `[[`
|
||||
- **Sourcing & introspection:** `.`, `source`, `eval`, `caller`
|
||||
- **Misc:** `alias`, `unalias`, `hash`, `type`, `command`, `builtin`, `enable`, `help`, `times`, `ulimit`, `umask`, `trap`, `shopt`, `set`, `shift`, `getopts`
|
||||
|
||||
### Arrays
|
||||
|
||||
- Indexed arrays: `arr=(a b c)`, `${arr[0]}`, `${arr[@]}`
|
||||
- Associative arrays: `declare -A map`
|
||||
- Array slicing: `${arr[@]:start:length}`
|
||||
- Array operations: `${#arr[@]}`, `${!arr[@]}`, `${!arr[*]}`
|
||||
|
||||
### Job Control
|
||||
|
||||
- Background execution: `cmd &`
|
||||
- Suspend/resume: Ctrl+Z, `fg`, `bg`
|
||||
- Job listing: `jobs`
|
||||
- Process groups and pipelines
|
||||
|
||||
### Dynamic Variables
|
||||
|
||||
- `RANDOM`, `SRANDOM`
|
||||
- `LINENO`, `FUNCNAME`, `BASH_SOURCE`
|
||||
- `EPOCHSECONDS`, `EPOCHREALTIME`
|
||||
- `SECONDS`
|
||||
- `PWD`, `OLDPWD`
|
||||
- `BASH_VERSINFO`, `BASH_VERSION`
|
||||
|
||||
### Programmable Completion
|
||||
|
||||
- Compatible with [`bash-completion`](https://github.com/scop/bash-completion)
|
||||
- Git, Docker, systemctl, etc. completions work out of the box
|
||||
- `complete`, `compgen`, `compopt` builtins
|
||||
|
||||
### Redirection
|
||||
|
||||
- Standard: `>`, `>>`, `<`, `2>&1`
|
||||
- Here documents: `<<EOF`, `<<-EOF` (tab-stripped), `<<<` (here strings)
|
||||
- File descriptor manipulation: `>&n`, `<&n`, `n>&m`
|
||||
- Process substitution redirects: `>(cmd)`, `<(cmd)`
|
||||
- Clobber control: `>|`, `set -o noclobber`
|
||||
|
||||
## Partially Supported Features 🔷
|
||||
|
||||
### Traps
|
||||
|
||||
| Status | Feature |
|
||||
|--------|----------|
|
||||
| ✅ | `DEBUG` trap |
|
||||
| ✅ | `ERR` trap |
|
||||
| ✅ | `EXIT` trap |
|
||||
| 🔷 | Signal traps (`SIGINT`, `SIGTERM`, etc.) — in progress |
|
||||
|
||||
### Key Bindings (`bind`)
|
||||
|
||||
| Status | Feature |
|
||||
|--------|---------|
|
||||
| ✅ | Basic `bind` support |
|
||||
| ✅ | `bind -x` for custom key-bound commands |
|
||||
| 🔷 | Advanced bind features — in progress |
|
||||
|
||||
### Shell Options
|
||||
|
||||
| Status | Feature |
|
||||
|--------|---------|
|
||||
| ✅ | Common options: `errexit`, `pipefail`, `extglob`, `globstar`, `noclobber`, `nounset`, `failglob` |
|
||||
| 🔷 | Less common options — in progress |
|
||||
|
||||
## Not Yet Supported Features 🚧
|
||||
|
||||
These features are on our roadmap but not yet implemented:
|
||||
|
||||
### `select` Statement
|
||||
|
||||
The `select` builtin for creating menu-driven scripts is not yet implemented.
|
||||
|
||||
```bash
|
||||
# Not yet supported
|
||||
select opt in "Option A" "Option B" "Quit"; do
|
||||
case $opt in
|
||||
"Option A") echo "A";;
|
||||
"Option B") echo "B";;
|
||||
"Quit") break;;
|
||||
esac
|
||||
done
|
||||
```
|
||||
|
||||
### `wait -n`
|
||||
|
||||
The `wait -n` option to wait for the next background job to complete is not implemented.
|
||||
|
||||
```bash
|
||||
# Not yet supported
|
||||
job1 &
|
||||
job2 &
|
||||
wait -n # Wait for whichever finishes first
|
||||
```
|
||||
|
||||
### `BASH_COMMAND` Variable
|
||||
|
||||
The special variable `BASH_COMMAND` that contains the currently executing command is currently only available in trap contexts.
|
||||
|
||||
### `disown` and `logout`
|
||||
|
||||
These job control builtins are not yet implemented.
|
||||
|
||||
## Known Edge Cases
|
||||
|
||||
These areas have known differences from `bash` in edge cases. Most users won't encounter these, but they're documented for completeness.
|
||||
|
||||
### IFS (Input Field Separator)
|
||||
|
||||
There are ~10 known edge cases where IFS word splitting behavior differs from `bash`, particularly around:
|
||||
|
||||
- Non-whitespace IFS characters and empty field creation
|
||||
- Mixed whitespace and non-whitespace IFS
|
||||
- Leading/trailing delimiter handling
|
||||
|
||||
### `printf` Format Specifiers
|
||||
|
||||
Some advanced `printf` format specifiers behave differently (~8 known cases), particularly features not supported by the underlying `uucore` library.
|
||||
|
||||
### Arithmetic Expressions
|
||||
|
||||
- Division by zero handling may differ in `errexit` mode
|
||||
- `$(( exit N ))` syntax edge case
|
||||
|
||||
### Aliases
|
||||
|
||||
Some complex alias expansion scenarios differ from `bash` (see GitHub issues #57, #286).
|
||||
|
||||
## Test Suite Statistics
|
||||
|
||||
- **Total test cases:** 1700+
|
||||
- **Known failures:** ~125
|
||||
- **Most failures are edge cases** in IFS handling and printf
|
||||
|
||||
The test suite runs on every PR and compares behavior against `bash` as an oracle.
|
||||
|
||||
## Version Compatibility
|
||||
|
||||
`brush` targets compatibility with **`bash` 5.3+**. Behavior may differ from older `bash` versions (3.x, 4.x) in some areas.
|
||||
|
||||
## Reporting Compatibility Issues
|
||||
|
||||
Found a script that works in `bash` but not in `brush`?
|
||||
|
||||
1. **Check existing issues:** [GitHub Issues](https://github.com/reubeno/brush/issues)
|
||||
2. **Create a minimal reproducer:** Reduce to the smallest failing script
|
||||
3. **File an issue** with:
|
||||
- The script or command that fails
|
||||
- Expected behavior (what `bash` does)
|
||||
- Actual behavior (what `brush` does)
|
||||
- Your platform (Linux/macOS/etc.)
|
||||
|
||||
## Tracking Progress
|
||||
|
||||
- **GitHub Issues:** Track specific compatibility work
|
||||
- **Test Suite:** 1700+ tests run on every PR
|
||||
- **This Document:** Updated as features are implemented
|
||||
|
||||
## Related Resources
|
||||
|
||||
- [`bash` Reference Manual](https://www.gnu.org/software/bash/manual/)
|
||||
- [POSIX Shell Specification](https://pubs.opengroup.org/onlinepubs/9699919799/)
|
||||
- [`brush` Test Cases](https://github.com/reubeno/brush/tree/main/brush-shell/tests/cases)
|
||||
@@ -0,0 +1,118 @@
|
||||
# Configuration File
|
||||
|
||||
brush supports an optional TOML configuration file that allows you to customize shell behavior without command-line arguments.
|
||||
|
||||
## File Location
|
||||
|
||||
`brush` looks for the configuration file at:
|
||||
|
||||
- **Linux/macOS**: `${XDG_CONFIG_HOME}/brush/config.toml`*
|
||||
- **Windows**: `%APPDATA%\brush\config.toml`
|
||||
|
||||
> [!NOTE]
|
||||
> On Linux/macOS falls back to `~/.config/brush/config.toml` if `XDG_CONFIG_HOME` is undefined.
|
||||
|
||||
You can override this location with the `--config` flag:
|
||||
|
||||
```bash
|
||||
brush --config /path/to/custom/config.toml
|
||||
```
|
||||
|
||||
To disable configuration file loading entirely, use:
|
||||
|
||||
```bash
|
||||
brush --no-config
|
||||
```
|
||||
|
||||
## Configuration Priority
|
||||
|
||||
Settings are applied in the following order (later values override earlier ones):
|
||||
|
||||
1. **Defaults** - Built-in default values
|
||||
2. **Configuration file** - Values from `config.toml`
|
||||
3. **Command-line arguments** - Flags passed to brush
|
||||
|
||||
## File Format
|
||||
|
||||
The configuration file uses [TOML](https://toml.io/) format. All settings are optional; brush uses sensible defaults for any unspecified values.
|
||||
|
||||
### Example Configuration
|
||||
|
||||
```toml
|
||||
[ui]
|
||||
syntax-highlighting = true
|
||||
|
||||
[experimental]
|
||||
zsh-hooks = true
|
||||
terminal-shell-integration = true
|
||||
```
|
||||
|
||||
## Available Settings
|
||||
|
||||
### `[ui]` Section
|
||||
|
||||
User interface settings.
|
||||
|
||||
| Setting | Type | Default | CLI flag | Description |
|
||||
|-----------------------|---------|---------|-------------------------|----------------------------------------------|
|
||||
| `syntax-highlighting` | boolean | see below | `--enable-highlighting` | Enable syntax highlighting in the input line |
|
||||
|
||||
> The default value of `syntax-highlighting` depends on how `brush-shell`
|
||||
> was built: `true` when built with the `experimental` Cargo feature,
|
||||
> `false` otherwise. CLI flags take precedence over the configuration
|
||||
> file.
|
||||
|
||||
### `[experimental]` Section
|
||||
|
||||
Experimental features that may change or be removed in future versions.
|
||||
Each setting has an equivalent command-line flag; CLI flags take
|
||||
precedence over the configuration file. See the
|
||||
[experimental features reference](experimental.md) for details on each
|
||||
feature.
|
||||
|
||||
| Setting | Type | Default | CLI flag | Description |
|
||||
|------------------------------|---------|---------|----------------------------------|---------------------------------------|
|
||||
| `zsh-hooks` | boolean | `false` | `--enable-zsh-hooks` | Enable zsh-style preexec/precmd hooks |
|
||||
| `terminal-shell-integration` | boolean | `false` | `--enable-terminal-integration` | Enable terminal shell integration |
|
||||
|
||||
## JSON Schema
|
||||
|
||||
A JSON Schema for the configuration file is available at [`schemas/config.schema.json`](../../schemas/config.schema.json). This can be used with editors that support schema-based validation and autocompletion for TOML files.
|
||||
|
||||
### Using the Schema with VS Code
|
||||
|
||||
To enable schema validation in VS Code with the [Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml) extension, add this to your `config.toml`:
|
||||
|
||||
```toml
|
||||
#:schema https://raw.githubusercontent.com/reubeno/brush/main/schemas/config.schema.json
|
||||
|
||||
[ui]
|
||||
syntax-highlighting = true
|
||||
```
|
||||
|
||||
The `#:schema` directive tells the editor where to find the schema for validation and autocompletion.
|
||||
|
||||
### Using the Schema with Other Editors
|
||||
|
||||
Many editors support JSON Schema for TOML files. Consult your editor's documentation for how to associate a schema with a file. You can reference the schema via:
|
||||
|
||||
- **URL**: `https://raw.githubusercontent.com/reubeno/brush/main/schemas/config.schema.json`
|
||||
- **Local path**: Point to `schemas/config.schema.json` in your brush source checkout
|
||||
|
||||
## Sample Configuration
|
||||
|
||||
A sample configuration file is available at [`samples/config.toml`](../../samples/config.toml) in the brush repository. You can copy this file to get started:
|
||||
|
||||
```bash
|
||||
# Linux/macOS
|
||||
mkdir -p ~/.config/brush
|
||||
cp samples/config.toml ~/.config/brush/config.toml
|
||||
```
|
||||
|
||||
## Forward Compatibility
|
||||
|
||||
brush ignores unknown settings in the configuration file. This allows configuration files to be shared across different versions of brush without causing errors.
|
||||
|
||||
## Error Handling
|
||||
|
||||
If the configuration file cannot be read or parsed, brush logs an error message and continues with default settings. The shell will still start normally.
|
||||
@@ -0,0 +1,149 @@
|
||||
# Experimental Features
|
||||
|
||||
`brush` ships several features that are intentionally marked as
|
||||
**experimental**. They are usable today, but their interface or behavior
|
||||
may evolve based on feedback before being stabilized. This page is the
|
||||
canonical index of what's currently experimental and how to opt in.
|
||||
|
||||
Experimental features fall into two categories:
|
||||
|
||||
1. **Build-time experiments** — additional functionality gated behind
|
||||
Cargo feature flags. To get them, you build `brush-shell` with the
|
||||
relevant feature(s) enabled.
|
||||
2. **Run-time experiments** — features that ship in standard builds but
|
||||
are off by default and enabled through configuration.
|
||||
|
||||
> Names, defaults, and semantics of experimental features may change
|
||||
> between releases.
|
||||
|
||||
---
|
||||
|
||||
## Build-time experiments (Cargo features)
|
||||
|
||||
These are flags on the `brush-shell` crate. You can enable them
|
||||
individually, or pull in the whole set with the umbrella `experimental`
|
||||
feature.
|
||||
|
||||
```bash
|
||||
# Enable everything experimental
|
||||
cargo install --locked brush-shell --features experimental
|
||||
|
||||
# Or pick and choose
|
||||
cargo install --locked brush-shell --features experimental-bundled-coreutils
|
||||
```
|
||||
|
||||
### `experimental-bundled-coreutils`
|
||||
|
||||
Bundles a configurable subset of [`uutils/coreutils`](https://github.com/uutils/coreutils)
|
||||
implementations directly into `brush-shell` as builtins. Useful when:
|
||||
|
||||
- shipping `brush` into containers, embedded systems, or other
|
||||
environments where a standalone coreutils package is inconvenient or
|
||||
unavailable,
|
||||
- distributing a single self-contained `brush` binary that doesn't
|
||||
rely on host utilities being present.
|
||||
|
||||
When enabled (via the umbrella `experimental` feature, or directly), the
|
||||
full set of supported utilities is bundled. When building the
|
||||
`brush-coreutils-builtins` crate directly, individual utilities can be
|
||||
selected via `coreutils.<name>` features (e.g., `coreutils.cat`,
|
||||
`coreutils.ls`); the `coreutils.all` feature enables all of them.
|
||||
|
||||
Bundled utilities run in-process and take precedence over external
|
||||
executables of the same name on `PATH` when invoked unqualified. As with
|
||||
any builtin, you can bypass the in-process implementation with
|
||||
`command <name>` or by giving an explicit path.
|
||||
|
||||
### `experimental-builtins`
|
||||
|
||||
Pulls in the [`brush-experimental-builtins`](../../brush-experimental-builtins)
|
||||
crate, which provides additional builtins that are too new or too
|
||||
narrow-purpose to ship in the default builtin set. Currently this
|
||||
includes:
|
||||
|
||||
- **`save`** — serializes the current shell state to JSON on stdout.
|
||||
Primarily intended for debugging and tooling. ⚠️ The serialized state
|
||||
may include sensitive information (variable values, command history,
|
||||
environment).
|
||||
|
||||
### `experimental-load`
|
||||
|
||||
Enables `serde`-based serialization support in `brush-core`, and adds a
|
||||
`--load <FILE>` command-line flag that restores shell state from a JSON
|
||||
file previously produced by the experimental [`save`](#experimental-builtins)
|
||||
builtin (or by other tooling that emits the same format). State loaded
|
||||
this way overrides non-UI command-line options. Useful for tooling
|
||||
built on top of `brush-core` that wants to snapshot or transfer shell
|
||||
state.
|
||||
|
||||
### `experimental-parser`
|
||||
|
||||
Switches on the in-development [`winnow`](https://crates.io/crates/winnow)-based
|
||||
parser scaffolding in `brush-parser`, and adds an `--experimental-parser`
|
||||
command-line flag that selects it at runtime. This parser is not yet the
|
||||
production parser; the existing PEG parser remains the default. Enable
|
||||
this only if you're contributing to or experimenting with the parser
|
||||
work.
|
||||
|
||||
---
|
||||
|
||||
## Run-time experiments (configuration)
|
||||
|
||||
These features ship in standard builds but are off by default. Each one
|
||||
can be enabled either through the optional [TOML configuration
|
||||
file](configuration.md) (under the `[experimental]` section, persistent
|
||||
across sessions) or through a command-line flag at startup (one-shot).
|
||||
|
||||
When both are specified, command-line flags take precedence over the
|
||||
configuration file.
|
||||
|
||||
```toml
|
||||
[experimental]
|
||||
zsh-hooks = true
|
||||
terminal-shell-integration = true
|
||||
```
|
||||
|
||||
| Feature | TOML setting (`[experimental]`) | Command-line flag |
|
||||
|---------|---------------------------------|-------------------|
|
||||
| zsh-style hooks | `zsh-hooks = true` | `--enable-zsh-hooks` |
|
||||
| Terminal shell integration | `terminal-shell-integration = true` | `--enable-terminal-integration` |
|
||||
|
||||
### `zsh-hooks`
|
||||
|
||||
Enables zsh-style `preexec` and `precmd` hook functions. When set:
|
||||
|
||||
- A function named `preexec` (if defined) is invoked before each
|
||||
interactively-entered command runs, with the command line as `$1`.
|
||||
- A function named `precmd` (if defined) is invoked just before each
|
||||
prompt is displayed.
|
||||
|
||||
This is convenient for prompt frameworks, command timing, and
|
||||
integrations that expect zsh-style hook conventions. Equivalent
|
||||
behavior in stock bash typically requires `DEBUG`/`PROMPT_COMMAND`
|
||||
plumbing.
|
||||
|
||||
Enable persistently with `zsh-hooks = true` under `[experimental]` in
|
||||
`config.toml`, or per-invocation with `brush --enable-zsh-hooks`.
|
||||
|
||||
### `terminal-shell-integration`
|
||||
|
||||
Emits standard terminal shell-integration escape sequences (semantic
|
||||
prompt and command boundary marking) that modern terminal emulators —
|
||||
including VS Code, iTerm2, WezTerm, and others — use to enable features
|
||||
like command navigation, exit-status display, and selective output
|
||||
copying. This is off by default to avoid emitting escape sequences in
|
||||
terminals that don't recognize them.
|
||||
|
||||
Enable persistently with `terminal-shell-integration = true` under
|
||||
`[experimental]` in `config.toml`, or per-invocation with
|
||||
`brush --enable-terminal-integration`.
|
||||
|
||||
---
|
||||
|
||||
## Reporting feedback
|
||||
|
||||
Experimental features are the place where your feedback is most valuable
|
||||
— they exist precisely because we want to iterate on them before
|
||||
stabilizing. If you try one and find a rough edge, missing capability,
|
||||
or behavior that surprises you, please [file an
|
||||
issue](https://github.com/reubeno/brush/issues).
|
||||
@@ -0,0 +1,17 @@
|
||||
# Integration testing
|
||||
|
||||
Our approach to integration testing relies heavily on using test oracles to provide the "correct" answers/expectations for test cases. In practice, we use existing alternate shell implementations as oracles.
|
||||
|
||||
Test cases are defined in YAML files. The test cases defined in a given file comprise a test case set. Running the integration tests for this project executes test case sets in parallel.
|
||||
|
||||
```yaml
|
||||
name: "Example tests"
|
||||
cases:
|
||||
- name: "Basic usage"
|
||||
stdin: |
|
||||
echo hi
|
||||
```
|
||||
|
||||
This defines a new test case set with the name "Example tests". It contains one defined test case called "Basic usage". This test case will launch the shell without any additional custom arguments (beyond a few standard ones to disable processing default profiles and rc files), write "echo hi" (with a trailing newline) to stdin of the shell, and then close that stream. The test harness will capture the shell's stdout, stderr, and exit code. After repeating these steps with the test oracle, each of these 3 data are compared. An error is flagged if any of the 3 differ.
|
||||
|
||||
Test cases are run with the working directory initialized to a temporary directory. The contents of the temporary directory are inspected after the shell-under-test has exited, and compared against their counterparts in the oracle's run. This enables easy checking of files created, deleted, or mutated as side effects of running the test case.
|
||||
@@ -0,0 +1,37 @@
|
||||
# Minimum Supported Rust Version (MSRV) Policy
|
||||
|
||||
## Overview
|
||||
|
||||
The `brush` project maintains a conservative MSRV policy to balance two key concerns:
|
||||
|
||||
1. **Binary distribution**: Users building `brush` from source should not need a bleeding-edge compiler
|
||||
2. **Library usage**: Downstream projects depending on `brush` crates should not face aggressive MSRV increases
|
||||
|
||||
## Policy
|
||||
|
||||
### When We Update MSRV
|
||||
|
||||
We **do not** update MSRV proactively. Updates only occur when:
|
||||
|
||||
- A meaningful set of language features or capabilities becomes available that provides clear value to the project
|
||||
- The return-on-investment justifies the potential impact on users and downstream dependencies
|
||||
|
||||
### MSRV Age Requirements
|
||||
|
||||
When we do update MSRV, we move to a Rust version that is **at least 4-6 months old** from the time of the update. This ensures:
|
||||
|
||||
- Sufficient time for the Rust version to stabilize
|
||||
- Wide availability in package managers and development environments
|
||||
- Reduced friction for users building from source
|
||||
|
||||
### Communication
|
||||
|
||||
MSRV changes are always:
|
||||
|
||||
- Explicitly documented in release notes
|
||||
- Considered a notable change requiring user awareness
|
||||
- Announced with clear justification for the update
|
||||
|
||||
## Rationale
|
||||
|
||||
This conservative approach recognizes that `brush` serves dual purposes: as a standalone binary tool and as a library for integration into other projects. Both use cases benefit from stability and predictability in compiler requirements.
|
||||
@@ -0,0 +1,3 @@
|
||||
# Tutorials
|
||||
|
||||
_To be written_
|
||||
Reference in New Issue
Block a user