URL: https://github.com/peterbe/gg2/pull/30

Remember my blog post about gg2? It's a CLI tool, written in TypeScript, compiled with Bun, called gg. You use it to help with various git tasks such as creating a new branch. For example gg start will prompt you for a nice title, and create a branch with appropriate name, and remember that title you entered as the default git commit message later.

Anyway, now you can just type gg s[TAB] and it will finish typing gg start for you. It works for flags too. For example, gg pr -[TAB] will suggest gg pr --watch. And simplest of all, gg [TAB] will list all possible commands.

Installation

To install it you need to put this at the bottom of your ~/.bashrc or ~/.zshrc file:


source <(gg shell-completion)

That command gg shell-completion spits out a block of Bash code. You can see the code by typing gg shell-completion or view the source here.

That bash script effectively calls gg shell-completion --list "$arguments-here" which means that when gg changes (for example, a new sub-command is added), you won't need to re-install the Bash/Zsh hook because it refers back to the executable gg to get the completion options.

What was tricky

The TypeScript code for this project compiles the .ts files down to a single executable binary. But making it read the ./src/completion.sh file from disk was hard. You can't rely on Bun.file(path.join(import.meta.here, './scr/completion.sh')) because that won't work after compilation.

The solution, after some sleuthing was to import it with type text.


// @ts-ignore
import code from "./completion.sh" with { type: "text" }

The ts-ignore is because my tsc seems to think it won't work because the file is not .ts.

The code that powers gg shell-completion (which you pipe to source) looks like this:


// @ts-ignore - a trick to make a non TS file part of memory and build
import code from "./completion.sh" with { type: "text" }

export async function shellCompletion() {
  console.log(code)
}

Comments

Peter Bengtsson

I (almost) forgot! The credit for this Shell hook idea came from this blog post: https://mill-build.org/blog/14-bash-zsh-completion.html

Your email will never ever be published.

Previous:
Combining Django signals with in-memory LRU cache August 9, 2025 Python, Django
Related by category:
gg2 - a new CLI for helping me manage git branches August 6, 2025 Bun, JavaScript, macOS
Parse a CSV file with Bun September 13, 2023 Bun
Switching from Next.js to Vite + wouter July 28, 2023 JavaScript
Video to screenshots app June 21, 2025 Bun, JavaScript
Related by keyword:
set -ex - The most useful bash trick of the year August 31, 2014 Linux
<datalist> looks great on mobile devices August 28, 2020 Mobile, Web development
How to throttle AND debounce an autocomplete input in React March 1, 2018 Web development, React, JavaScript
How to intercept and react to non-zero exits in bash February 23, 2023 Bash, GitHub