feat: install tab completion for bash, zsh, and fish (#16)

`completions install` generates the script from the same clap definition
the binary parses with, so it cannot drift from `--help`, and writes it
where each shell already looks. fish scans its own completions directory
unprompted; bash and zsh get one marked `source` line appended to their rc
file, because nothing puts a per-user directory on their search path by
default. `completions uninstall` takes back exactly those lines and leaves
the rest of the file alone.
This commit is contained in:
Michel de Graaf
2026-07-26 12:18:53 +02:00
committed by GitHub
parent 72f2e31a2c
commit 534b09a20a
13 changed files with 583 additions and 10 deletions
+7 -2
View File
@@ -181,14 +181,19 @@ export const Docs = () => {
<Code>download</Code>, <Code>browse</Code>, <Code>room</Code>,{' '}
<Code>message</Code>, <Code>serve</Code>, <Code>user</Code>,{' '}
<Code>whoami</Code>, <Code>shares</Code>, <Code>config</Code>,{' '}
<Code>portmap</Code>, <Code>skills</Code>. Records are tab-separated fields,
one per line, or NDJSON with <Code>--json</Code>.
<Code>portmap</Code>, <Code>skills</Code>, <Code>completions</Code>. Records
are tab-separated fields, one per line, or NDJSON with <Code>--json</Code>.
</p>
<p>
No TTY, no daemon. <Code>search --json</Code> pipes through <Code>jq</Code>{' '}
into <Code>download --stdin</Code>. Every ending has its own exit code: 4 found
nothing, 3 could not reach the server, 6 the transfer died.
</p>
<p>
<Code>completions install</Code> gives bash, zsh and fish tab completion for
all of it, generated from the same definition the binary parses with.{' '}
<Code>completions uninstall</Code> takes it back out.
</p>
<p>
<Code>portmap</Code> tests whether your router will let peers connect back,
worth running once.{' '}
+12 -1
View File
@@ -301,6 +301,12 @@ export const Install = () => {
a terminal and the TUI opens, in a script or a pipe it wants a subcommand
instead.
</p>
<p className="text-[13px] text-muted">
<Code>soulseek-rs completions install</Code> then adds tab completion to
whichever of bash, zsh and fish this machine uses &mdash; generated from the
same definition the binary parses with, so it never drifts from{' '}
<Code>--help</Code>. Open a new shell to pick it up.
</p>
<div className="flex flex-wrap gap-2 sm:gap-3">
<Button href={LINKS.releases}>Prebuilt binaries</Button>
</div>
@@ -519,13 +525,17 @@ export const Install = () => {
<Section band>
<SectionHead eyebrow="uninstall" title="Removing it completely.">
Three things exist on disk: the binary, the config, and the state. Nothing else,
Three things exist on disk: the binary, the config, and the state &mdash; plus
the completion scripts and the agent skill, if you asked for those. Nothing else,
unless you point <Code>--log-file</Code> somewhere. No telemetry to opt out of.
</SectionHead>
<Cols start>
<Terminal
label="macOS · Linux"
lines={[
{ t: 'cm', text: '# while the binary is still there' },
{ t: 'cmd', text: 'soulseek-rs completions uninstall' },
{ t: 'cmd', text: 'soulseek-rs skills uninstall' },
{ t: 'cmd', text: 'cargo uninstall soulseek-rs' },
{ t: 'cm', text: '# config and state: searches, downloads, rooms, messages' },
{
@@ -539,6 +549,7 @@ export const Install = () => {
<Terminal
label="Windows · PowerShell"
lines={[
{ t: 'cmd', text: 'soulseek-rs skills uninstall' },
{ t: 'cmd', text: 'cargo uninstall soulseek-rs' },
{
t: 'cmd',