- Shell 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
PATH is arranged while the shell starts, so installing elan into a running session leaves ~/.elan/bin on disk and out of PATH, and doctor simply did not list elan, with nothing to explain why. Remember every directory a module asks for, including the ones that do not exist yet, and let doctor name the ones that exist now but are not in this shell's PATH, along with the two ways to pick them up. The fzf stub matched with grep, whose own arguments then appeared in the process list fkill was choosing from, so the kill test failed whenever that pid had already gone. It matches in the shell now. |
||
| lib | ||
| modules | ||
| tests | ||
| .editorconfig | ||
| .gitignore | ||
| bash_prompt.bash | ||
| bashrc | ||
| env | ||
| install.sh | ||
| manage.sh | ||
| README.en.md | ||
| README.md | ||
bashra
A collection of Bash settings and scripts. Source bashra/env from your shell
configuration to load only the scripts enabled in that file. It covers the
prompt, history, completion, directory movement, and file handling, along with
Git, GitHub CLI, fzf, and the Lean 4, Haskell, Idris 2, Racket, and Chez Scheme
toolchains. Every part can be switched on or off by itself.
Requirements
bashra is designed for Bash. Completion and fzf integration use common Linux
installation paths. Git, GitHub CLI, fzf, bash-completion, direnv, and zoxide are
optional; integrations activate when the corresponding tools are installed. The
language toolchains (GHCup, Cabal, Stack, elan, Lake, pack, Idris 2, Racket, and
Chez Scheme) are optional in the same way, and shortcuts and completion are
configured only for the ones that are installed. The tests require Bash 4.4 or
later and Git; the line editing checks use script, and are skipped without it.
Usage
Add this line to ~/.bashrc. Skip this step if it already loads bashra.
source "$HOME/.bashra/env"
Alternatively, run bash install.sh from this directory to back up your existing
startup file and append the loader. Do not run the installer if you already have
a handwritten loader. Keep this repository at the same location after installation.
The repository's bashrc is a compatibility entry point that delegates to env.
The installer refuses to edit symlinks. To edit the target file explicitly, use
bash install.sh /path/to/bashrc.
Enable or disable scripts
Comment out a source line in env to disable a script; uncomment it to enable it.
Scripts load in the order listed. Files are never loaded by directory discovery.
source "$BASHRA_ROOT/modules/10-shell.bash"
# source "$BASHRA_ROOT/bash_prompt.bash"
From a shell, the bashra command does the same work.
bashra list
bashra disable bash_prompt.bash
bashra enable bash_prompt.bash
bashra reload
bashra doctor
| Command | Action |
|---|---|
bashra list |
Show every script and whether it is enabled |
bashra enable SCRIPT / disable SCRIPT |
Switch a script, from the next Bash session |
bashra reload |
Load the configuration again in the current shell |
bashra doctor |
Report the load path, Bash version, script states, the tools that were found, and any PATH entry still missing |
bashra root |
Print the directory bashra was loaded from |
bashra help |
Show the usage message |
PATH entries are added while the shell starts, so a tool installed afterwards is
not visible to a shell that was already running. bashra doctor lists the
directories a module asked for that exist but are not in PATH, and says what to
do about them.
installed since this shell started, and not in its PATH:
/home/yuotsuka/.elan/bin
Run bashra reload, or open a new shell, to use them here.
Tab completion offers the commands, and the switchable script paths after
enable and disable. bashra doctor runs none of the tools; it reports only
whether an executable is in PATH. bashra reload re-reads the configuration in
the current shell, but a script switched off does not take back the aliases and
functions it has already defined.
The management script edits the same file:
bash ~/.bashra/manage.sh list
bash ~/.bashra/manage.sh disable bash_prompt.bash
bash ~/.bashra/manage.sh enable bash_prompt.bash
bash ~/.bashra/manage.sh disable modules/20-integrations.bash
Managed declarations must use a standalone source "$BASHRA_ROOT/relative/path"
line. Files under lib/ are a prerequisite of the modules, so they are listed as
required and refused as a switch. Leading whitespace and a comment marker are supported. The manager changes
only the matching declaration and preserves other settings. Unknown script names
and duplicate declarations are rejected. To add a script, create its file and
add a declaration in this format to env. All bundled scripts are currently enabled.
Changes apply to new Bash sessions. Disabling a script does not undo aliases, functions, or PATH changes in an existing shell. Interactive settings load once per session.
Scripts
| Path | Purpose |
|---|---|
lib/core.bash |
Helpers shared by the modules (required, not switchable) |
modules/00-path.bash |
Append ~/.local/bin to PATH without duplicates |
modules/01-haskell.bash |
PATH, shortcuts, and completion for GHCup, Cabal, and Stack |
modules/02-lean.bash |
PATH, shortcuts, and completion for elan and Lake |
modules/03-idris.bash |
PATH, shortcuts, and completion for pack and Idris 2 |
modules/04-racket.bash |
PATH, shortcuts, and completion for Racket and raco |
modules/05-chez.bash |
Chez Scheme detection, library path, and shortcuts |
modules/10-shell.bash |
Aliases and mkcd |
modules/11-options.bash |
Shell options such as autocd and globstar |
modules/12-history.bash |
History size and append, multiline entries, timestamps, and expansion review |
modules/13-navigation.bash |
Moving to an ancestor directory or a project root, and the directory stack |
modules/14-files.bash |
Archive extraction, backups, scratch directories, and file search |
modules/15-readline.bash |
Completion display, key bindings, and prefix history search |
modules/16-editor.bash |
Defaults for EDITOR and VISUAL, plus e |
modules/17-output.bash |
Pager defaults, colored output, and man rendering |
modules/20-integrations.bash |
Optional bash-completion, fzf, direnv, and zoxide integration |
modules/22-fzf.bash |
fzf pickers for directories, files, processes, and Git |
modules/30-git.bash |
Git shortcuts, completion, and repository root navigation |
modules/35-gh.bash |
GitHub CLI shortcuts for PRs, issues, and Actions |
bash_prompt.bash |
Username, hostname, working directory, and exit status prompt |
modules/40-git-prompt.bash |
Git branch and working tree status in the prompt |
modules/80-bashra.bash |
The bashra command: list, switch, reload, and report |
modules/90-local.bash |
Load ~/.alias and ~/.config/bashra/local.bash |
PATH settings also apply to noninteractive shells that source env. Subsequent
settings apply only to interactive shells. Use ll and la to list files,
.. and ... to move up directories, and mkcd DIRECTORY to create and enter a
directory. fzf integration loads both its key bindings and its ** completion,
falling back to the output of fzf --bash when neither file is installed.
When the last command failed, its exit status appears before the prompt
character on the second line, and nothing appears when it succeeded. Bash
restores that status around PROMPT_COMMAND, so a hook installed by another
tool does not hide it, and the substitutions expanded earlier in the prompt,
such as the Git information, return that status unchanged.
yuki@host ~/src/mathlib [main *]
1 $
Set NO_COLOR=1 or TERM=dumb to disable prompt colors.
bashra itself changes neither PROMPT_COMMAND nor the DEBUG trap. When direnv
or zoxide is installed, its own initialization runs, and those tools install a
PROMPT_COMMAND hook of their own.
PATH settings live in one file per tool, and the logic they share is collected in
lib/core.bash.
Everyday use
bashra prioritizes everyday shell comfort, with separate controls for the prompt, history, and completion.
- Type a prefix such as
git, then use the up and down arrows to find commands beginning with the text before the cursor. With an empty line, the keys navigate all history. This works in Emacs mode and Vi insertion mode. - Tab completion ignores case and displays candidates when a match is ambiguous. Pressing Tab on an empty line does not list every command in PATH.
- Candidates are marked by file type and colored the way
lscolors them when the terminal can show it. A list of more than 200 candidates is confirmed first. - Ctrl with the left and right arrows moves by words. Pasted text is inserted as it is, so a newline inside it does not run the line.
- Multiline commands retain their line breaks in a single history entry, and
historydisplays timestamps. History is appended on shell exit; sessions do not share new entries immediately. - A history expansion such as
!!or!sshis placed on the command line instead of running, so it can be read before Enter. One that fails is left there to be corrected.
The following Bash options are enabled. Each one is a Bash feature and can be
turned off individually with shopt -u.
| Option | Behavior |
|---|---|
autocd |
A bare directory name changes to it, echoing the command it runs |
cdspell / dirspell |
Correct small spelling mistakes in cd and in completion |
globstar |
Expand recursive patterns such as **/*.lean |
extglob |
Accept extended patterns such as !(*.o) |
checkjobs |
Warn on the first exit while jobs are still running |
checkhash |
Look up a remembered command again when its path has changed |
checkwinsize |
Update LINES and COLUMNS after the terminal is resized |
History limits are set to HISTSIZE=10000 and HISTFILESIZE=20000. Bash assigns
those two itself before any startup file runs, so a conditional default would
never apply; choose other limits in ~/.config/bashra/local.bash, which loads
last.
HISTCONTROL and HISTTIMEFORMAT are left to whatever they already are, because
Bash does not set them. Set HISTTIMEFORMAT='' to hide timestamps. You can also
override key bindings in that file.
bash ~/.bashra/manage.sh disable modules/11-options.bash
bash ~/.bashra/manage.sh disable modules/12-history.bash
bash ~/.bashra/manage.sh disable modules/15-readline.bash
Directory movement
| Command | Action |
|---|---|
up |
Move to the parent directory |
up 3 |
Move three levels up |
up src |
Move to the nearest ancestor directory named src |
proot |
Move to the project root, the nearest ancestor holding a marker |
d |
dirs -v, the directory stack |
pd / po |
pushd / popd |
The markers proot looks for are the file names and globs in
BASHRA_PROJECT_MARKERS. It starts with .git, and each language module adds
the build files of its own ecosystem. Add your own from
~/.config/bashra/local.bash with bashra_project_marker flake.nix. To move to
the Git root specifically, use groot.
Tab completion on up offers the names of the ancestor directories, quoting the
ones that contain spaces. An unknown name or an extra argument reports an error
and leaves the working directory unchanged.
bash ~/.bashra/manage.sh disable modules/13-navigation.bash
Editor
When EDITOR is unset, the first of nvim, vim, vi, and nano that is
installed is used, and VISUAL follows it when it is unset too. e FILE opens
$EDITOR, expanded when the alias runs, so a later change to EDITOR applies.
A value set earlier, for example in ~/.config/bashra/local.bash, is kept.
bash ~/.bashra/manage.sh disable modules/16-editor.bash
Output and pager
PAGER and LESS are filled in only when unset. The LESS default is
-F -R -i: quit when the output fits one screen, keep color escapes, and search
without regard to case. grep, diff, ls, and ip gain --color=auto, which
prints escapes to a terminal only, so piped output stays plain. man renders
through less, so headings and option names are colored there too.
Nothing is colored when NO_COLOR is set or TERM is dumb, and LESS_TERMCAP_*
values you set yourself are kept.
bash ~/.bashra/manage.sh disable modules/17-output.bash
File helpers
| Command | Action |
|---|---|
extract ARCHIVE... |
Unpack by file name extension, keeping the archive |
bak FILE... |
Copy to FILE.bak-TIMESTAMP with the original attributes |
cdtmp |
Create a scratch directory, move into it, and print its path |
ff PATTERN [DIR...] |
List paths whose name contains PATTERN, ignoring case |
extract handles tar, zip, 7z, rar, gz, bz2, xz, and zst, and
names the missing command before unpacking when one is not installed. bak
refuses to overwrite an existing copy. ff is a plain find wrapper, so hidden
directories are searched too.
bash ~/.bashra/manage.sh disable modules/14-files.bash
Language toolchains
PATH entries and project markers apply to non-interactive shells too, so a build started from an editor or a script uses the same tools as the prompt. Shortcuts and completion are configured only in an interactive shell, and only for the tools that are installed. Nothing is defined for a tool that is absent, no directory is added to PATH unless it exists, and an alias, function, or command that already has the name keeps it.
| Module | Toolchain |
|---|---|
modules/01-haskell.bash |
GHCup, Cabal, and Stack |
modules/02-lean.bash |
elan and Lake, for Lean 4 |
modules/03-idris.bash |
pack and Idris 2 |
modules/04-racket.bash |
Racket and raco |
modules/05-chez.bash |
Chez Scheme |
Haskell
~/.ghcup/bin and ~/.cabal/bin are prepended to PATH in that order.
| Command | Action |
|---|---|
cb / cr / ct / crepl |
cabal build / run / test / repl |
sb / sr / st / srepl |
stack build / run / test / repl |
Completion for cabal uses cabal --list-options for the subcommand being
typed, and falls back to file names when there is nothing to offer. Completion
for stack and ghcup is generated the first time you press Tab. The markers
*.cabal, cabal.project, stack.yaml, and package.yaml are registered for
proot.
bash ~/.bashra/manage.sh disable modules/01-haskell.bash
Lean 4
~/.elan/bin is prepended to PATH. lean and lake are elan shims, so the
version in use still comes from the project's lean-toolchain.
| Command | Action |
|---|---|
lk |
lake |
lkb / lkt / lkc |
lake build / test / clean |
lke NAME |
lake exe NAME |
lku |
lake update |
lkcache |
lake exe cache get, fetching Mathlib's compiled oleans |
Completion for elan is generated the first time you press Tab. lakefile.lean,
lakefile.toml, and lean-toolchain are registered as proot markers, so one
command returns from a directory such as Mathlib/Algebra/Group to the root.
bash ~/.bashra/manage.sh disable modules/02-lean.bash
Idris 2
~/.pack/bin and ~/.idris2/bin are prepended to PATH in that order.
| Command | Action |
|---|---|
idr |
idris2 |
pk |
pack |
pkb / pkt / pkr |
pack build / test / repl |
pki / pkd |
pack install / install-deps |
pku |
pack update-db, refreshing the package collection |
Completion for pack and idris2 is generated on the first Tab when the
installed build can print a completion script; otherwise file name completion
stays in place. pack.toml and *.ipkg are registered as proot markers.
bash ~/.bashra/manage.sh disable modules/03-idris.bash
Racket
~/racket/bin, where the official installer puts a home installation, and the
launchers raco pkg install writes to ~/.local/share/racket/VERSION/bin and
~/.racket/VERSION/bin are added to PATH. The home installation is searched
first, and among versioned directories the newest one is.
| Command | Action |
|---|---|
rkt |
racket |
rktrl |
racket -il readline, a REPL with line editing |
rr |
raco |
rrm / rrt |
raco make / test |
rrp / rrd / rre |
raco pkg / docs / exe |
Completion for racket and raco is loaded from the shell-completion package
when the installation includes it. info.rkt is registered as a proot marker.
bash ~/.bashra/manage.sh disable modules/04-racket.bash
Chez Scheme
The executable has a different name on each system, so chezscheme,
chez-scheme, and chez are tried in that order, and scheme after them.
Because other implementations answer to scheme as well, that name is accepted
only next to scheme-script or petite, which Chez installs alongside it.
| Command | Action |
|---|---|
chez |
The Chez Scheme executable that was found |
chezs FILE |
Run a script with --script, without the banner or the REPL |
When ~/.local/lib/chez exists and CHEZSCHEMELIBDIRS is unset, it becomes
~/.local/lib/chez:.. Chez searches only the working directory by default, so
. stays in the list next to your own library directory. Expression editing and
history are Chez's own, stored in ~/.chezscheme_history.
bash ~/.bashra/manage.sh disable modules/05-chez.bash
fzf pickers
These activate when fzf is installed. Cancelling a selection runs nothing and leaves the shell as it was.
| Command | Action |
|---|---|
fcd [DIR] |
Choose a directory and move into it, skipping .git, .lake, dist-newstyle, and .stack-work |
fe |
Choose files and open them in $EDITOR; Tab selects several |
fkill [SIGNAL] |
Choose processes and signal them, TERM by default |
fgb |
Choose a local branch and git switch to it |
fgl [git log arguments] |
Choose commits and print their hashes |
fgl writes the chosen hashes to standard output, so they can be passed on, as
in git show $(fgl).
When FZF_DEFAULT_OPTS is unset it becomes
--height=40% --layout=reverse --border --info=inline. With fd installed,
FZF_DEFAULT_COMMAND and FZF_ALT_C_COMMAND use it. Previews use bat when it
is installed and head otherwise; BASHRA_FZF_PREVIEW overrides the command.
bash ~/.bashra/manage.sh disable modules/22-fzf.bash
Git integration
Git integration activates when Git is installed and does not change global Git settings.
| Command | Action |
|---|---|
g |
Run git, for example g fetch |
gs |
Show the branch and a short status summary |
gd / gds |
Show unstaged / staged changes |
gl |
Show the latest 20 commits as a graph |
ga |
Run git add, for example ga file.txt |
gc |
Run git commit, for example gc -m "message" |
gsw |
Run git switch, for example gsw -c feature |
gb |
Run git branch |
gsh |
Run git show |
grs |
Run git restore, for example grs file.txt |
gf / gpl / gp |
Run git fetch / pull / push |
groot |
Move to the current worktree root |
Shortcuts reuse Git completion definitions when available.
The prompt displays repository status, for example [main >2 <1 + * ?].
| Marker | Meaning |
|---|---|
>N / <N |
N commits ahead of / behind the locally recorded upstream |
+ |
Staged changes |
* |
Unstaged changes |
? |
Untracked files |
! |
Conflicts |
merge / rebase / rebase/am / cherry-pick |
Operation in progress |
detached:hash |
Detached HEAD |
The prompt supports repositories without an initial commit and linked worktrees.
It displays nothing outside a worktree and makes no network requests. Upstream
comparisons use locally available information from the last fetch. Since the
prompt runs git status each time, you can disable the display for large repositories:
bash ~/.bashra/manage.sh disable modules/40-git-prompt.bash
bash ~/.bashra/manage.sh disable modules/30-git.bash
The Git prompt module loads after the base prompt. It also works with custom
prompts, but assigning PS1 afterward replaces the Git display as well.
GitHub CLI integration
This integration activates when gh is installed. Authenticate initially with
gh auth login. bashra uses existing authentication and repository settings
without changing them.
| Command | Action |
|---|---|
gh-pr / gh-mine |
List PRs / PRs you authored |
gh-pv [number] |
View a PR; defaults to the current branch |
gh-pd [number] |
Show a PR diff |
gh-ps |
Show the status of PRs relevant to you |
gh-co [number] |
Check out a PR; select interactively if omitted |
gh-checks [number] |
Show PR checks |
gh-i / gh-iv number |
List issues / view an issue |
gh-r / gh-rv [ID] / gh-rw [ID] |
List / view / watch Actions runs |
gh-ci |
List Actions runs for the current branch |
gh-browse |
Open the repository in a browser |
Commands preserve the underlying gh arguments and exit codes.
In detached HEAD, gh-ci filters by the current commit instead of the branch.
gh-pr --search 'label:"needs review"'
gh-pv 42 --repo owner/repo
gh-co 42
gh-checks --watch
gh-ci --workflow 'Build and Test' --limit 5
gh-rv 123456 --log-failed
The module loads Bash completion for gh itself, generated the first time you
press Tab so that starting a shell never waits for gh; it does not register
completion for the shortcuts. Shell startup and prompt rendering do not access
the GitHub API. Network access and authentication are needed when running GitHub operations.
To disable the module, run the following and open a new Bash session:
bash ~/.bashra/manage.sh disable modules/35-gh.bash
See the GitHub CLI manual for command details.
Extending
Personal settings belong in ~/.config/bashra/local.bash, which loads after the
bundled scripts and can therefore override any alias or variable. To add a
script, create the file and add a source "$BASHRA_ROOT/modules/NAME.bash" line
to env.
Modules can use these helpers. All of them are defined in lib/core.bash, and
every name starts with bashra_, so none of them shadows a command of yours.
| Helper | Behavior |
|---|---|
bashra_have COMMAND |
Report whether a command exists, without running it |
bashra_path_prepend DIR... |
Prepend the directories that exist, in the order given |
bashra_path_append DIR... |
Append them the same way |
bashra_first_file PATH... |
Print the first readable path; the caller sources it |
bashra_alias NAME VALUE |
Define an alias only if the name is free |
bashra_project_marker NAME... |
Register a file name or glob for proot, once each |
bashra_lazy_completion CMD GENERATOR |
Run GENERATOR on the first Tab and install what it prints |
A directory already in PATH is left where it is, and one that does not exist is not added.
| Variable | Contents |
|---|---|
BASHRA_ROOT |
The directory bashra was loaded from |
BASHRA_LOADED |
Records that the interactive settings are already loaded |
BASHRA_PROJECT_MARKERS |
The markers proot looks for |
BASHRA_PATH_REQUESTED |
The directories the modules asked to put on PATH |
BASHRA_FZF_PREVIEW |
The preview command used by the fzf pickers |
BASHRA_COMPLETION_GENERATORS |
The completions waiting for their first Tab |
# ~/.config/bashra/local.bash
bashra_project_marker flake.nix dune-project
bashra_path_prepend "$HOME/opt/bin"
HISTSIZE=50000
alias ll='ls -alFh'
Uninstall
Remove the source line from your shell configuration and open a new Bash session.
If you used the installer, remove the block from # >>> bashra >>> through
# <<< bashra <<<.
Development and testing
Source files use UTF-8, LF line endings, and four spaces for indentation.
Basic formatting settings are provided in .editorconfig.
Run the following from the repository root:
bash tests/run.bash
To run a single suite:
bash tests/core.bash
bash tests/smoke.bash
bash tests/git.bash
bash tests/gh.bash
GitHub CLI tests use a stub and do not access or modify GitHub.