aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--AGENTS.md22
-rw-r--r--Cargo.lock10
-rw-r--r--Cargo.toml1
-rw-r--r--PLAN.md40
-rw-r--r--TODO.md24
-rw-r--r--completions/rsp.bash920
-rw-r--r--completions/rsp.fish114
-rw-r--r--completions/rsp.zsh685
-rwxr-xr-xinstall.sh28
-rw-r--r--src/daemon.rs32
10 files changed, 1755 insertions, 121 deletions
diff --git a/AGENTS.md b/AGENTS.md
index 7dded6c..6782574 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -11,7 +11,7 @@ Run these before completing any task:
11- Build: `cargo build` 11- Build: `cargo build`
12 12
13## Development Workflow 13## Development Workflow
14- Use `rsp restart` or `rsplayer restart` to kill any running daemon and start a new one (useful during development) 14- Use `rsp restart` to kill any running daemon and start a new one (useful during development)
15- Daemon runs in background; restart command handles cleanup automatically 15- Daemon runs in background; restart command handles cleanup automatically
16- After making changes to audio/playback/daemon code, always restart the daemon to test changes 16- After making changes to audio/playback/daemon code, always restart the daemon to test changes
17 17
@@ -20,7 +20,7 @@ Run these before completing any task:
20- Follow standard Rust style (enforced by `cargo fmt`) 20- Follow standard Rust style (enforced by `cargo fmt`)
21- Never commit changes unless explicitly requested by the user 21- Never commit changes unless explicitly requested by the user
22- Update shell completions when adding/modifying CLI subcommands 22- Update shell completions when adding/modifying CLI subcommands
23- Use `rand` crate for shuffle/randomization features (added in v0.9) 23- Use `rand` crate for shuffle/randomization features
24 24
25## Task-Specific Guidelines 25## Task-Specific Guidelines
26- **CLI changes**: Update clap subcommands (including `rsp scan` and `rsp settings`) and regenerate shell completion scripts 26- **CLI changes**: Update clap subcommands (including `rsp scan` and `rsp settings`) and regenerate shell completion scripts
@@ -33,7 +33,7 @@ Run these before completing any task:
33- **Scrobbling changes**: Update Last.fm/ListenBrainz client implementation 33- **Scrobbling changes**: Update Last.fm/ListenBrainz client implementation
34- **Config/Settings changes**: Update config schema, `rsp settings` subcommands, and scan interval/auto-scan logic 34- **Config/Settings changes**: Update config schema, `rsp settings` subcommands, and scan interval/auto-scan logic
35 35
36## Completed Features (Phase 2) 36## Completed Features
37- [x] Unix socket daemon IPC 37- [x] Unix socket daemon IPC
38- [x] Audio engine with play/pause/stop/volume 38- [x] Audio engine with play/pause/stop/volume
39- [x] Queue system with in-memory tracking and auto-advance 39- [x] Queue system with in-memory tracking and auto-advance
@@ -42,16 +42,16 @@ Run these before completing any task:
42- [x] Resume CLI subcommand 42- [x] Resume CLI subcommand
43- [x] Directory playback - queues all audio files in folder recursively 43- [x] Directory playback - queues all audio files in folder recursively
44- [x] Fixed audio buffer underrun issues by using device default sample rate 44- [x] Fixed audio buffer underrun issues by using device default sample rate
45- [x] Queue display with pager support (`rsplayer queue`) 45- [x] Queue display with pager support (`rsp queue`)
46- [x] Auto-play next track when current track ends 46- [x] Auto-play next track when current track ends
47- [x] Metadata extraction and display (INDEX. ARTIST - TITLE format, falls back to filename) 47- [x] Metadata extraction and display (INDEX. ARTIST - TITLE format, falls back to filename)
48- [x] `rsp scan` with `--force` and `--paths` options
49- [x] `rsp settings` subcommands (get/set/list/unset)
50- [x] Shell completions (`rsp completions bash|zsh|fish|powershell|elvish`)
51- [x] Unit tests for Player, Track, and ShuffleMode
48 52
49## Remaining Work 53## Remaining Work
50- Album shuffle mode (`ShuffleMode::Album`) 54- Queue state persistence to disk
51- Database integration for queue persistence 55- Album shuffle mode with proper album/folder grouping
52- `rsplayer queue` command for queue management
53- Scrobbling (Last.fm/ListenBrainz) 56- Scrobbling (Last.fm/ListenBrainz)
54- Database scanning and schema 57- Systemd service unit \ No newline at end of file
55- Shell completion scripts
56- Systemd service unit
57- MPRIS/playerctl integration (zbus requires async, needs refactoring)
diff --git a/Cargo.lock b/Cargo.lock
index 82ef060..1a889fe 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -251,6 +251,15 @@ dependencies = [
251] 251]
252 252
253[[package]] 253[[package]]
254name = "clap_complete"
255version = "4.6.3"
256source = "registry+https://github.com/rust-lang/crates.io-index"
257checksum = "660c0520455b1013b9bcb0393d5f643d7e4454fb69c915b8d6d2aa0e9a45acc3"
258dependencies = [
259 "clap",
260]
261
262[[package]]
254name = "clap_derive" 263name = "clap_derive"
255version = "4.6.1" 264version = "4.6.1"
256source = "registry+https://github.com/rust-lang/crates.io-index" 265source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1622,6 +1631,7 @@ version = "0.1.0"
1622dependencies = [ 1631dependencies = [
1623 "chrono", 1632 "chrono",
1624 "clap", 1633 "clap",
1634 "clap_complete",
1625 "cpal", 1635 "cpal",
1626 "ctrlc", 1636 "ctrlc",
1627 "directories", 1637 "directories",
diff --git a/Cargo.toml b/Cargo.toml
index 62aa530..04f49e1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,6 +17,7 @@ path = "src/main.rs"
17 17
18[dependencies] 18[dependencies]
19clap = { version = "4.6.1", features = ["derive", "string"] } 19clap = { version = "4.6.1", features = ["derive", "string"] }
20clap_complete = "4.6"
20rusqlite = { version = "0.39", features = ["bundled"] } 21rusqlite = { version = "0.39", features = ["bundled"] }
21directories = "6.0" 22directories = "6.0"
22serde = { version = "1.0.228", features = ["derive"] } 23serde = { version = "1.0.228", features = ["derive"] }
diff --git a/PLAN.md b/PLAN.md
index 98bd897..d04e528 100644
--- a/PLAN.md
+++ b/PLAN.md
@@ -1,24 +1,28 @@
1# rsplayer Project Plan 1# rsplayer Project Plan
2 2
3## Phase 1: Setup & Core 3## Phase 1: Setup & Core ✓
41. Initialize Rust project, add dependencies: `clap` (CLI/autocompletion), `rusqlite` (SQLite), `symphonia`/`cpal` (audio), `directories` (XDG paths), `serde`/`toml` (config), `tokio` (daemon async), `reqwest` (scrobbling). 41. Initialize Rust project, add dependencies: `clap` (CLI/autocompletion), `rusqlite` (SQLite), `symphonia`/`cpal` (audio), `directories` (XDG paths), `serde`/`toml` (config), `tokio` (daemon async), `reqwest` (scrobbling). ✓
52. Config stored at `$XDG_CONFIG_HOME/rsplayer/config.toml`: `music_paths` (array of directories to scan), `scan_interval` (optional periodic rescan interval), scrobbling credentials, daemon socket path. Daemon auto-scans configured paths on first run if database is empty/missing. 52. Config stored at `$XDG_CONFIG_HOME/rsplayer/config.toml`: `music_paths` (array of directories to scan), `scan_interval` (optional periodic rescan interval), scrobbling credentials, daemon socket path. ✓
63. SQLite library schema: `artists`, `albums`, `tracks` tables. Implement `rsp scan` to scan all paths in config's `music_paths`, populate/update database. Support `--force` full rescan, `--paths` override config paths. Auto-scan triggers on first run (if DB empty) and periodically per `scan_interval` config. 63. SQLite library schema: `artists`, `albums`, `tracks` tables. Implement `rsp scan` to scan all paths in config's `music_paths`, populate/update database. ✓
7 7
8## Phase 2: Daemon 8## Phase 2: Daemon ✓
91. Unix socket daemon (path: `$XDG_RUNTIME_DIR/rsplayer/daemon.sock`) for IPC. 91. Unix socket daemon (path: `$XDG_RUNTIME_DIR/rsplayer/daemon.sock`) for IPC. ✓
102. Audio engine: Symphonia decode + CPAL output, support play/pause/stop/volume/seek. 102. Audio engine: Symphonia decode + CPAL output, support play/pause/stop/volume/seek. ✓
113. Queue: in-memory, `last` (append to end, default), `now` (play immediately, ending current song playback), `next` (insert after current). 113. Queue: in-memory, `last` (append to end, default), `now` (play immediately, ending current song playback), `next` (insert after current). ✓
124. Shuffle modes: `none` (linear playback), `all` (shuffle all tracks), `album` (shuffle within album). 124. Shuffle modes: `none` (linear playback), `all` (shuffle all tracks), `album` (shuffle within album, structure ready). ✓
135. Scrobbling: Last.fm and ListenBrainz support via configured credentials.
14 13
15## Phase 3: CLI & Completion 14## Phase 3: CLI & Completion ✓
161. Clap-based CLI with all subcommands. Generate shell completions for bash/zsh/fish, suggest database artists/albums/tracks, file paths, and config keys/values. 151. Clap-based CLI with all subcommands. ✓
172. `rsp status`: show player state, current track, progress, volume, next 2-3 queue items. 162. Shell completions for bash/zsh/fish/powershell/elvish (`rsp completions`). PARTIALLY
183. `rsp queue`: no arguments display current queue; with arguments add items (default `last` behavior). 173. `rsp status`: show player state, current track, progress, volume, next 2-3 queue items. ✓
194. `rsp settings` subcommands: `get`, `set`, `list`, `unset` config values (music paths, scrobbling credentials, scan interval, etc.) without manual file editing. 184. `rsp queue`: no arguments display current queue; with arguments add items (default `last` behavior). BUGGED
195. `rsp settings` subcommands: `get`, `set`, `list`, `unset` config values. ✓
206. `rsp scan`: `--force` full rescan, `--paths` override config paths. Uses symphonia for metadata. ✓
217. `rsp play`: flexible insert options (`-i`/`--now`, `-n`/`--next`, `-l`/`--last`). ✓
20 22
21## Phase 4: Polish 23## Phase 4: Polish
221. Direct file/folder playback: prioritize database metadata if path matches known artist/album. 241. [ ] Queue state persistence - Save queue to disk so it survives daemon restarts.
232. Logging, systemd service unit, unit tests. 252. [ ] Album shuffle mode - Implement proper `ShuffleMode::Album` (shuffle tracks within same album/folder).
243. Periodic rescan logic per config's `scan_interval`. 263. [ ] Scrobbling - Last.fm and ListenBrainz support via configured credentials.
274. [ ] Logging and error handling improvements.
285. [ ] Systemd service unit for auto-start.
diff --git a/TODO.md b/TODO.md
index 8a3fca8..68a0cf0 100644
--- a/TODO.md
+++ b/TODO.md
@@ -4,7 +4,7 @@
4 4
5- [x] **Dev/release build config separation** - Store config next to binary in dev mode, use XDG in release mode. 5- [x] **Dev/release build config separation** - Store config next to binary in dev mode, use XDG in release mode.
6 6
7- [x] **Volume without argument returns current volume** - `rsplayer volume` now returns current level. 7- [x] **Volume without argument returns current volume** - `rsp volume` now returns current level.
8 8
9- [x] **Fix SampleRate access in audio.rs:104** - `config.sample_rate().0` is invalid because `cpal::SampleRate` is a type alias for `u32`, not a tuple struct. 9- [x] **Fix SampleRate access in audio.rs:104** - `config.sample_rate().0` is invalid because `cpal::SampleRate` is a type alias for `u32`, not a tuple struct.
10 10
@@ -14,7 +14,7 @@
14 14
15- [x] **Run clippy** - All linting checks pass. 15- [x] **Run clippy** - All linting checks pass.
16 16
17- [x] **Run tests** - All tests pass (no tests exist yet). 17- [x] **Run tests** - All tests pass.
18 18
19- [x] **Check formatting** - Code formatting is correct. 19- [x] **Check formatting** - Code formatting is correct.
20 20
@@ -24,7 +24,7 @@
24 24
25- [x] **Add Resume CLI subcommand** - Added `Resume` subcommand to CLI so users can resume playback after pause. 25- [x] **Add Resume CLI subcommand** - Added `Resume` subcommand to CLI so users can resume playback after pause.
26 26
27- [x] **Implement shuffle mode** - Added shuffle on/off/album functionality with queue management in daemon. Supports `rsplayer shuffle on/off/album` commands. 27- [x] **Implement shuffle mode** - Added shuffle on/off/album functionality with queue management in daemon. Supports `rsp shuffle on/off/album` commands.
28 28
29- [x] **Implement next/previous commands** - Next and previous track commands now work with the queue system. 29- [x] **Implement next/previous commands** - Next and previous track commands now work with the queue system.
30 30
@@ -32,7 +32,7 @@
32 32
33- [x] **Auto-play next track** - Daemon automatically plays next track when current one ends (using `poll_track_ended()`). 33- [x] **Auto-play next track** - Daemon automatically plays next track when current one ends (using `poll_track_ended()`).
34 34
35- [x] **Queue display with pager** - `rsplayer queue` shows all queued tracks with pager support for long lists. 35- [x] **Queue display with pager** - `rsp queue` shows all queued tracks with pager support for long lists.
36 36
37- [x] **Album shuffle mode structure** - `ShuffleMode::Album` added to enum and queue logic (behaves like `All` until database ready). 37- [x] **Album shuffle mode structure** - `ShuffleMode::Album` added to enum and queue logic (behaves like `All` until database ready).
38 38
@@ -40,20 +40,20 @@
40 40
41- [x] **Flexible play command** - Added `-i/--now`, `-n/--next`, `-l/--last` flags to play command: `play MUSIC` (default - add to end and play), `play -i MUSIC` (insert after current and skip to it), `play -n MUSIC` (insert after current, don't skip), `play -l MUSIC` (add to end of queue). Also fixed queue display to correctly show playing track. 41- [x] **Flexible play command** - Added `-i/--now`, `-n/--next`, `-l/--last` flags to play command: `play MUSIC` (default - add to end and play), `play -i MUSIC` (insert after current and skip to it), `play -n MUSIC` (insert after current, don't skip), `play -l MUSIC` (add to end of queue). Also fixed queue display to correctly show playing track.
42 42
43## Potential Improvements 43- [x] **Add unit tests for Player struct** - Tests added for Player, Track, PlaybackState, and ShuffleMode in `tests/playback.rs`.
44 44
45- [ ] **Add error handling for audio playback** - Consider more robust error handling in the audio thread. 45- [x] **Database scan command** - Implemented `rsp scan` with `--force` full rescan and `--paths` override options. Uses symphonia for metadata extraction.
46 46
47- [x] **Add unit tests for Player struct** - The `Player` struct in `playback.rs` has no corresponding tests. 47- [x] **Settings subcommands** - Implemented `rsp settings get/set/list/unset` for config management.
48 48
49- [ ] **Persist queue state** - Save queue to disk so it survives daemon restarts. 49- [x] **Shell completions** - Generate shell completions with `rsp completions bash|elvish|fish|powershell|zsh`.
50 50
51- [ ] **Album shuffle mode (database)** - Implement proper `ShuffleMode::Album` when database is ready (shuffle tracks within same album/folder). 51## Remaining Work
52 52
53- [ ] **Scrobbling (Last.fm/ListenBrainz)** - Add scrobbling support via configured credentials. 53- [ ] **Persist queue state** - Save queue to disk so it survives daemon restarts.
54 54
55- [ ] **Database integration** - Scan music paths, populate SQLite database, use for metadata. 55- [ ] **Scrobbling (Last.fm/ListenBrainz)** - Add scrobbling support via configured credentials.
56 56
57- [ ] **Shell completion scripts** - Generate bash/zsh/fish completions using clap. 57- [ ] **Shell completion scripts** - Generate bash/zsh/fish completions using clap.
58 58
59- [ ] **Systemd service unit** - Create systemd service file for auto-start. 59- [ ] **Systemd service unit** - Create systemd service file for auto-start. \ No newline at end of file
diff --git a/completions/rsp.bash b/completions/rsp.bash
index b625927..4ea8603 100644
--- a/completions/rsp.bash
+++ b/completions/rsp.bash
@@ -1,26 +1,918 @@
1#!/usr/bin/env bash 1_rsp_play_query_completions() {
2 local cur="${COMP_WORDS[COMP_CWORD]}"
3 # Only do dynamic completion if COMPREPLY is empty (no flag matched)
4 # and the current word doesn't start with -
5 if [[ ${#COMPREPLY[@]} -eq 0 && "$cur" != -* ]]; then
6 local -a artists
7 artists=($(rsp play --list 2>/dev/null))
8 COMPREPLY=( $(compgen -W "${artists[*]}" -- "$cur") )
9 fi
10}
2 11
3_rsp() { 12_rsp() {
4 local cur prev words cword 13 local i cur prev opts cmd
5 _init_completion || return 14 COMPREPLY=()
15 if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
16 cur="$2"
17 else
18 cur="${COMP_WORDS[COMP_CWORD]}"
19 fi
20 prev="$3"
21 cmd=""
22 opts=""
23
24 for i in "${COMP_WORDS[@]:0:COMP_CWORD}"
25 do
26 case "${cmd},${i}" in
27 ",$1")
28 cmd="rsp"
29 ;;
30 rsp,completions)
31 cmd="rsp__subcmd__completions"
32 ;;
33 rsp,help)
34 cmd="rsp__subcmd__help"
35 ;;
36 rsp,next)
37 cmd="rsp__subcmd__next"
38 ;;
39 rsp,pause)
40 cmd="rsp__subcmd__pause"
41 ;;
42 rsp,play)
43 cmd="rsp__subcmd__play"
44 ;;
45 rsp,previous)
46 cmd="rsp__subcmd__previous"
47 ;;
48 rsp,queue)
49 cmd="rsp__subcmd__queue"
50 ;;
51 rsp,restart)
52 cmd="rsp__subcmd__restart"
53 ;;
54 rsp,resume)
55 cmd="rsp__subcmd__resume"
56 ;;
57 rsp,scan)
58 cmd="rsp__subcmd__scan"
59 ;;
60 rsp,settings)
61 cmd="rsp__subcmd__settings"
62 ;;
63 rsp,shuffle)
64 cmd="rsp__subcmd__shuffle"
65 ;;
66 rsp,start)
67 cmd="rsp__subcmd__start"
68 ;;
69 rsp,status)
70 cmd="rsp__subcmd__status"
71 ;;
72 rsp,stop)
73 cmd="rsp__subcmd__stop"
74 ;;
75 rsp,stop-playback)
76 cmd="rsp__subcmd__stop__subcmd__playback"
77 ;;
78 rsp,toggle)
79 cmd="rsp__subcmd__toggle"
80 ;;
81 rsp,volume)
82 cmd="rsp__subcmd__volume"
83 ;;
84 rsp__subcmd__help,completions)
85 cmd="rsp__subcmd__help__subcmd__completions"
86 ;;
87 rsp__subcmd__help,help)
88 cmd="rsp__subcmd__help__subcmd__help"
89 ;;
90 rsp__subcmd__help,next)
91 cmd="rsp__subcmd__help__subcmd__next"
92 ;;
93 rsp__subcmd__help,pause)
94 cmd="rsp__subcmd__help__subcmd__pause"
95 ;;
96 rsp__subcmd__help,play)
97 cmd="rsp__subcmd__help__subcmd__play"
98 ;;
99 rsp__subcmd__help,previous)
100 cmd="rsp__subcmd__help__subcmd__previous"
101 ;;
102 rsp__subcmd__help,queue)
103 cmd="rsp__subcmd__help__subcmd__queue"
104 ;;
105 rsp__subcmd__help,restart)
106 cmd="rsp__subcmd__help__subcmd__restart"
107 ;;
108 rsp__subcmd__help,resume)
109 cmd="rsp__subcmd__help__subcmd__resume"
110 ;;
111 rsp__subcmd__help,scan)
112 cmd="rsp__subcmd__help__subcmd__scan"
113 ;;
114 rsp__subcmd__help,settings)
115 cmd="rsp__subcmd__help__subcmd__settings"
116 ;;
117 rsp__subcmd__help,shuffle)
118 cmd="rsp__subcmd__help__subcmd__shuffle"
119 ;;
120 rsp__subcmd__help,start)
121 cmd="rsp__subcmd__help__subcmd__start"
122 ;;
123 rsp__subcmd__help,status)
124 cmd="rsp__subcmd__help__subcmd__status"
125 ;;
126 rsp__subcmd__help,stop)
127 cmd="rsp__subcmd__help__subcmd__stop"
128 ;;
129 rsp__subcmd__help,stop-playback)
130 cmd="rsp__subcmd__help__subcmd__stop__subcmd__playback"
131 ;;
132 rsp__subcmd__help,toggle)
133 cmd="rsp__subcmd__help__subcmd__toggle"
134 ;;
135 rsp__subcmd__help,volume)
136 cmd="rsp__subcmd__help__subcmd__volume"
137 ;;
138 rsp__subcmd__help__subcmd__settings,get)
139 cmd="rsp__subcmd__help__subcmd__settings__subcmd__get"
140 ;;
141 rsp__subcmd__help__subcmd__settings,list)
142 cmd="rsp__subcmd__help__subcmd__settings__subcmd__list"
143 ;;
144 rsp__subcmd__help__subcmd__settings,set)
145 cmd="rsp__subcmd__help__subcmd__settings__subcmd__set"
146 ;;
147 rsp__subcmd__help__subcmd__settings,unset)
148 cmd="rsp__subcmd__help__subcmd__settings__subcmd__unset"
149 ;;
150 rsp__subcmd__settings,get)
151 cmd="rsp__subcmd__settings__subcmd__get"
152 ;;
153 rsp__subcmd__settings,help)
154 cmd="rsp__subcmd__settings__subcmd__help"
155 ;;
156 rsp__subcmd__settings,list)
157 cmd="rsp__subcmd__settings__subcmd__list"
158 ;;
159 rsp__subcmd__settings,set)
160 cmd="rsp__subcmd__settings__subcmd__set"
161 ;;
162 rsp__subcmd__settings,unset)
163 cmd="rsp__subcmd__settings__subcmd__unset"
164 ;;
165 rsp__subcmd__settings__subcmd__help,get)
166 cmd="rsp__subcmd__settings__subcmd__help__subcmd__get"
167 ;;
168 rsp__subcmd__settings__subcmd__help,help)
169 cmd="rsp__subcmd__settings__subcmd__help__subcmd__help"
170 ;;
171 rsp__subcmd__settings__subcmd__help,list)
172 cmd="rsp__subcmd__settings__subcmd__help__subcmd__list"
173 ;;
174 rsp__subcmd__settings__subcmd__help,set)
175 cmd="rsp__subcmd__settings__subcmd__help__subcmd__set"
176 ;;
177 rsp__subcmd__settings__subcmd__help,unset)
178 cmd="rsp__subcmd__settings__subcmd__help__subcmd__unset"
179 ;;
180 *)
181 ;;
182 esac
183 done
6 184
7 case $prev in 185 case "${cmd}" in
8 rsp) 186 rsp)
9 COMPREPLY=($(compgen -W "start stop restart play pause resume toggle next previous volume shuffle queue status scan settings" -- "$cur")) 187 opts="-h --help start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help"
188 if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
189 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
190 return 0
191 fi
192 case "${prev}" in
193 *)
194 COMPREPLY=()
195 ;;
196 esac
197 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
198 return 0
199 ;;
200 rsp__subcmd__completions)
201 opts="-h --shell --help"
202 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
203 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
204 return 0
205 fi
206 case "${prev}" in
207 --shell)
208 COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}"))
209 return 0
210 ;;
211 *)
212 COMPREPLY=()
213 ;;
214 esac
215 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
216 return 0
217 ;;
218 rsp__subcmd__help)
219 opts="start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help"
220 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
221 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
222 return 0
223 fi
224 case "${prev}" in
225 *)
226 COMPREPLY=()
227 ;;
228 esac
229 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
230 return 0
231 ;;
232 rsp__subcmd__help__subcmd__completions)
233 opts=""
234 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
235 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
236 return 0
237 fi
238 case "${prev}" in
239 *)
240 COMPREPLY=()
241 ;;
242 esac
243 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
244 return 0
245 ;;
246 rsp__subcmd__help__subcmd__help)
247 opts=""
248 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
249 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
250 return 0
251 fi
252 case "${prev}" in
253 *)
254 COMPREPLY=()
255 ;;
256 esac
257 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
258 return 0
259 ;;
260 rsp__subcmd__help__subcmd__next)
261 opts=""
262 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
263 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
264 return 0
265 fi
266 case "${prev}" in
267 *)
268 COMPREPLY=()
269 ;;
270 esac
271 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
272 return 0
273 ;;
274 rsp__subcmd__help__subcmd__pause)
275 opts=""
276 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
277 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
278 return 0
279 fi
280 case "${prev}" in
281 *)
282 COMPREPLY=()
283 ;;
284 esac
285 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
286 return 0
287 ;;
288 rsp__subcmd__help__subcmd__play)
289 opts=""
290 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
291 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
292 return 0
293 fi
294 case "${prev}" in
295 *)
296 COMPREPLY=()
297 ;;
298 esac
299 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
300 return 0
301 ;;
302 rsp__subcmd__help__subcmd__previous)
303 opts=""
304 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
305 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
306 return 0
307 fi
308 case "${prev}" in
309 *)
310 COMPREPLY=()
311 ;;
312 esac
313 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
314 return 0
315 ;;
316 rsp__subcmd__help__subcmd__queue)
317 opts=""
318 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
319 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
320 return 0
321 fi
322 case "${prev}" in
323 *)
324 COMPREPLY=()
325 ;;
326 esac
327 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
328 return 0
329 ;;
330 rsp__subcmd__help__subcmd__restart)
331 opts=""
332 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
333 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
334 return 0
335 fi
336 case "${prev}" in
337 *)
338 COMPREPLY=()
339 ;;
340 esac
341 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
342 return 0
343 ;;
344 rsp__subcmd__help__subcmd__resume)
345 opts=""
346 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
347 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
348 return 0
349 fi
350 case "${prev}" in
351 *)
352 COMPREPLY=()
353 ;;
354 esac
355 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
356 return 0
357 ;;
358 rsp__subcmd__help__subcmd__scan)
359 opts=""
360 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
361 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
362 return 0
363 fi
364 case "${prev}" in
365 *)
366 COMPREPLY=()
367 ;;
368 esac
369 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
370 return 0
371 ;;
372 rsp__subcmd__help__subcmd__settings)
373 opts="get set list unset"
374 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
375 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
376 return 0
377 fi
378 case "${prev}" in
379 *)
380 COMPREPLY=()
381 ;;
382 esac
383 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
384 return 0
385 ;;
386 rsp__subcmd__help__subcmd__settings__subcmd__get)
387 opts=""
388 if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then
389 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
390 return 0
391 fi
392 case "${prev}" in
393 *)
394 COMPREPLY=()
395 ;;
396 esac
397 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
398 return 0
399 ;;
400 rsp__subcmd__help__subcmd__settings__subcmd__list)
401 opts=""
402 if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then
403 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
404 return 0
405 fi
406 case "${prev}" in
407 *)
408 COMPREPLY=()
409 ;;
410 esac
411 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
412 return 0
413 ;;
414 rsp__subcmd__help__subcmd__settings__subcmd__set)
415 opts=""
416 if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then
417 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
418 return 0
419 fi
420 case "${prev}" in
421 *)
422 COMPREPLY=()
423 ;;
424 esac
425 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
426 return 0
427 ;;
428 rsp__subcmd__help__subcmd__settings__subcmd__unset)
429 opts=""
430 if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then
431 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
432 return 0
433 fi
434 case "${prev}" in
435 *)
436 COMPREPLY=()
437 ;;
438 esac
439 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
440 return 0
441 ;;
442 rsp__subcmd__help__subcmd__shuffle)
443 opts=""
444 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
445 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
446 return 0
447 fi
448 case "${prev}" in
449 *)
450 COMPREPLY=()
451 ;;
452 esac
453 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
454 return 0
455 ;;
456 rsp__subcmd__help__subcmd__start)
457 opts=""
458 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
459 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
460 return 0
461 fi
462 case "${prev}" in
463 *)
464 COMPREPLY=()
465 ;;
466 esac
467 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
468 return 0
469 ;;
470 rsp__subcmd__help__subcmd__status)
471 opts=""
472 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
473 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
474 return 0
475 fi
476 case "${prev}" in
477 *)
478 COMPREPLY=()
479 ;;
480 esac
481 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
482 return 0
483 ;;
484 rsp__subcmd__help__subcmd__stop)
485 opts=""
486 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
487 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
488 return 0
489 fi
490 case "${prev}" in
491 *)
492 COMPREPLY=()
493 ;;
494 esac
495 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
496 return 0
497 ;;
498 rsp__subcmd__help__subcmd__stop__subcmd__playback)
499 opts=""
500 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
501 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
502 return 0
503 fi
504 case "${prev}" in
505 *)
506 COMPREPLY=()
507 ;;
508 esac
509 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
510 return 0
511 ;;
512 rsp__subcmd__help__subcmd__toggle)
513 opts=""
514 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
515 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
516 return 0
517 fi
518 case "${prev}" in
519 *)
520 COMPREPLY=()
521 ;;
522 esac
523 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
524 return 0
525 ;;
526 rsp__subcmd__help__subcmd__volume)
527 opts=""
528 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
529 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
530 return 0
531 fi
532 case "${prev}" in
533 *)
534 COMPREPLY=()
535 ;;
536 esac
537 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
538 return 0
539 ;;
540 rsp__subcmd__next)
541 opts="-h --help"
542 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
543 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
544 return 0
545 fi
546 case "${prev}" in
547 *)
548 COMPREPLY=()
549 ;;
550 esac
551 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
552 return 0
553 ;;
554 rsp__subcmd__pause)
555 opts="-h --help"
556 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
557 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
558 return 0
559 fi
560 case "${prev}" in
561 *)
562 COMPREPLY=()
563 ;;
564 esac
565 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
566 return 0
567 ;;
568 rsp__subcmd__play)
569 opts="-i -n -l -L -h --now --next --last --list --help [QUERY]"
570 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
571 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
572 return 0
573 fi
574 case "${prev}" in
575 *)
576 COMPREPLY=()
577 ;;
578 esac
579 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
580
581 # Dynamic artist/album completion for query argument
582 _rsp_play_query_completions
583return 0
584 ;;
585 rsp__subcmd__previous)
586 opts="-h --help"
587 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
588 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
589 return 0
590 fi
591 case "${prev}" in
592 *)
593 COMPREPLY=()
594 ;;
595 esac
596 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
597 return 0
598 ;;
599 rsp__subcmd__queue)
600 opts="-h --help [POSITION] [QUERY]"
601 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
602 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
603 return 0
604 fi
605 case "${prev}" in
606 *)
607 COMPREPLY=()
608 ;;
609 esac
610 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
611 return 0
612 ;;
613 rsp__subcmd__restart)
614 opts="-h --help"
615 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
616 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
617 return 0
618 fi
619 case "${prev}" in
620 *)
621 COMPREPLY=()
622 ;;
623 esac
624 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
625 return 0
626 ;;
627 rsp__subcmd__resume)
628 opts="-h --help"
629 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
630 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
631 return 0
632 fi
633 case "${prev}" in
634 *)
635 COMPREPLY=()
636 ;;
637 esac
638 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
639 return 0
640 ;;
641 rsp__subcmd__scan)
642 opts="-h --force --paths --help"
643 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
644 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
645 return 0
646 fi
647 case "${prev}" in
648 --paths)
649 COMPREPLY=($(compgen -f "${cur}"))
650 return 0
651 ;;
652 *)
653 COMPREPLY=()
654 ;;
655 esac
656 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
657 return 0
658 ;;
659 rsp__subcmd__settings)
660 opts="-h --help get set list unset help"
661 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
662 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
663 return 0
664 fi
665 case "${prev}" in
666 *)
667 COMPREPLY=()
668 ;;
669 esac
670 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
671 return 0
672 ;;
673 rsp__subcmd__settings__subcmd__get)
674 opts="-h --help <KEY>"
675 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
676 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
677 return 0
678 fi
679 case "${prev}" in
680 *)
681 COMPREPLY=()
682 ;;
683 esac
684 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
685 return 0
686 ;;
687 rsp__subcmd__settings__subcmd__help)
688 opts="get set list unset help"
689 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
690 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
691 return 0
692 fi
693 case "${prev}" in
694 *)
695 COMPREPLY=()
696 ;;
697 esac
698 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
699 return 0
700 ;;
701 rsp__subcmd__settings__subcmd__help__subcmd__get)
702 opts=""
703 if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then
704 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
705 return 0
706 fi
707 case "${prev}" in
708 *)
709 COMPREPLY=()
710 ;;
711 esac
712 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
713 return 0
714 ;;
715 rsp__subcmd__settings__subcmd__help__subcmd__help)
716 opts=""
717 if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then
718 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
719 return 0
720 fi
721 case "${prev}" in
722 *)
723 COMPREPLY=()
724 ;;
725 esac
726 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
727 return 0
728 ;;
729 rsp__subcmd__settings__subcmd__help__subcmd__list)
730 opts=""
731 if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then
732 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
733 return 0
734 fi
735 case "${prev}" in
736 *)
737 COMPREPLY=()
738 ;;
739 esac
740 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
741 return 0
742 ;;
743 rsp__subcmd__settings__subcmd__help__subcmd__set)
744 opts=""
745 if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then
746 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
747 return 0
748 fi
749 case "${prev}" in
750 *)
751 COMPREPLY=()
752 ;;
753 esac
754 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
755 return 0
756 ;;
757 rsp__subcmd__settings__subcmd__help__subcmd__unset)
758 opts=""
759 if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then
760 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
761 return 0
762 fi
763 case "${prev}" in
764 *)
765 COMPREPLY=()
766 ;;
767 esac
768 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
769 return 0
770 ;;
771 rsp__subcmd__settings__subcmd__list)
772 opts="-h --help"
773 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
774 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
775 return 0
776 fi
777 case "${prev}" in
778 *)
779 COMPREPLY=()
780 ;;
781 esac
782 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
783 return 0
784 ;;
785 rsp__subcmd__settings__subcmd__set)
786 opts="-h --help <KEY> <VALUE>"
787 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
788 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
789 return 0
790 fi
791 case "${prev}" in
792 *)
793 COMPREPLY=()
794 ;;
795 esac
796 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
797 return 0
798 ;;
799 rsp__subcmd__settings__subcmd__unset)
800 opts="-h --help <KEY>"
801 if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
802 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
803 return 0
804 fi
805 case "${prev}" in
806 *)
807 COMPREPLY=()
808 ;;
809 esac
810 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
811 return 0
812 ;;
813 rsp__subcmd__shuffle)
814 opts="-h --help [MODE]"
815 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
816 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
817 return 0
818 fi
819 case "${prev}" in
820 *)
821 COMPREPLY=()
822 ;;
823 esac
824 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
825 return 0
826 ;;
827 rsp__subcmd__start)
828 opts="-h --help"
829 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
830 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
831 return 0
832 fi
833 case "${prev}" in
834 *)
835 COMPREPLY=()
836 ;;
837 esac
838 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
839 return 0
840 ;;
841 rsp__subcmd__status)
842 opts="-h --help"
843 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
844 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
845 return 0
846 fi
847 case "${prev}" in
848 *)
849 COMPREPLY=()
850 ;;
851 esac
852 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
853 return 0
10 ;; 854 ;;
11 play) 855 rsp__subcmd__stop)
12 _filedir 856 opts="-h --help"
857 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
858 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
859 return 0
860 fi
861 case "${prev}" in
862 *)
863 COMPREPLY=()
864 ;;
865 esac
866 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
867 return 0
13 ;; 868 ;;
14 volume) 869 rsp__subcmd__stop__subcmd__playback)
15 COMPREPLY=($(compgen -W "0 10 20 30 40 50 60 70 80 90 100" -- "$cur")) 870 opts="-h --help"
871 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
872 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
873 return 0
874 fi
875 case "${prev}" in
876 *)
877 COMPREPLY=()
878 ;;
879 esac
880 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
881 return 0
16 ;; 882 ;;
17 shuffle) 883 rsp__subcmd__toggle)
18 COMPREPLY=($(compgen -W "on off album" -- "$cur")) 884 opts="-h --help"
885 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
886 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
887 return 0
888 fi
889 case "${prev}" in
890 *)
891 COMPREPLY=()
892 ;;
893 esac
894 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
895 return 0
19 ;; 896 ;;
20 settings) 897 rsp__subcmd__volume)
21 COMPREPLY=($(compgen -W "get set list unset" -- "$cur")) 898 opts="-h --help [LEVEL]"
899 if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
900 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
901 return 0
902 fi
903 case "${prev}" in
904 *)
905 COMPREPLY=()
906 ;;
907 esac
908 COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
909 return 0
22 ;; 910 ;;
23 esac 911 esac
24} 912}
25 913
26complete -F _rsp rsp 914if [[ "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -ge 4 || "${BASH_VERSINFO[0]}" -gt 4 ]]; then
915 complete -F _rsp -o nosort -o bashdefault -o default rsp
916else
917 complete -F _rsp -o bashdefault -o default rsp
918fi
diff --git a/completions/rsp.fish b/completions/rsp.fish
index 4f44f63..d0e391d 100644
--- a/completions/rsp.fish
+++ b/completions/rsp.fish
@@ -1,11 +1,109 @@
1# rsp fish completion 1# Print an optspec for argparse to handle cmd's options that are independent of any subcommand.
2function __fish_rsp_global_optspecs
3 string join \n h/help
4end
2 5
3complete -c rsp -n '__fish_use_subcommand' -a 'start stop restart play pause resume toggle next previous volume shuffle queue status scan settings' -d 'Command' 6function __fish_rsp_needs_command
7 # Figure out if the current invocation already has a command.
8 set -l cmd (commandline -opc)
9 set -e cmd[1]
10 argparse -s (__fish_rsp_global_optspecs) -- $cmd 2>/dev/null
11 or return
12 if set -q argv[1]
13 # Also print the command, so this can be used to figure out what it is.
14 echo $argv[1]
15 return 1
16 end
17 return 0
18end
4 19
5complete -c rsp -n '__fish_seen_subcommand_from play' -f -d 'Audio file or directory' 20function __fish_rsp_using_subcommand
21 set -l cmd (__fish_rsp_needs_command)
22 test -z "$cmd"
23 and return 1
24 contains -- $cmd[1] $argv
25end
6 26
7complete -c rsp -n '__fish_seen_subcommand_from volume' -a '0 10 20 30 40 50 60 70 80 90 100' -d 'Volume level' 27complete -c rsp -n "__fish_rsp_needs_command" -s h -l help -d 'Print help'
8 28complete -c rsp -n "__fish_rsp_needs_command" -f -a "start" -d 'Start the daemon'
9complete -c rsp -n '__fish_seen_subcommand_from shuffle' -a 'on off album' -d 'Shuffle mode' 29complete -c rsp -n "__fish_rsp_needs_command" -f -a "stop" -d 'Stop the daemon'
10 30complete -c rsp -n "__fish_rsp_needs_command" -f -a "restart" -d 'Restart the daemon (kill existing and start new)'
11complete -c rsp -n '__fish_seen_subcommand_from settings' -a 'get set list unset' -d 'Settings command' 31complete -c rsp -n "__fish_rsp_needs_command" -f -a "play" -d 'Play a track, album, or artist'
32complete -c rsp -n "__fish_rsp_needs_command" -f -a "pause" -d 'Pause playback'
33complete -c rsp -n "__fish_rsp_needs_command" -f -a "resume" -d 'Resume playback'
34complete -c rsp -n "__fish_rsp_needs_command" -f -a "toggle" -d 'Toggle play/pause'
35complete -c rsp -n "__fish_rsp_needs_command" -f -a "stop-playback" -d 'Stop playback'
36complete -c rsp -n "__fish_rsp_needs_command" -f -a "next" -d 'Skip to next track'
37complete -c rsp -n "__fish_rsp_needs_command" -f -a "previous" -d 'Skip to previous track'
38complete -c rsp -n "__fish_rsp_needs_command" -f -a "volume" -d 'Set volume (0-100)'
39complete -c rsp -n "__fish_rsp_needs_command" -f -a "shuffle" -d 'Shuffle mode'
40complete -c rsp -n "__fish_rsp_needs_command" -f -a "queue" -d 'Queue management'
41complete -c rsp -n "__fish_rsp_needs_command" -f -a "status" -d 'Show player status'
42complete -c rsp -n "__fish_rsp_needs_command" -f -a "scan" -d 'Scan music paths to populate database'
43complete -c rsp -n "__fish_rsp_needs_command" -f -a "settings" -d 'Settings management'
44complete -c rsp -n "__fish_rsp_needs_command" -f -a "completions" -d 'Generate shell completions and write to completions/ directory (bash, elvish, fish, powershell, zsh)'
45complete -c rsp -n "__fish_rsp_needs_command" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'
46complete -c rsp -n "__fish_rsp_using_subcommand start" -s h -l help -d 'Print help'
47complete -c rsp -n "__fish_rsp_using_subcommand stop" -s h -l help -d 'Print help'
48complete -c rsp -n "__fish_rsp_using_subcommand restart" -s h -l help -d 'Print help'
49complete -c rsp -n "__fish_rsp_using_subcommand play" -s i -l now -d 'Play immediately (add after current and skip to it)'
50complete -c rsp -n "__fish_rsp_using_subcommand play" -s n -l next -d 'Add to queue after current track (don\'t skip)'
51complete -c rsp -n "__fish_rsp_using_subcommand play" -s l -l last -d 'Add to end of queue (default)'
52complete -c rsp -n "__fish_rsp_using_subcommand play" -s L -l list -d 'List available artists/albums'
53complete -c rsp -n "__fish_rsp_using_subcommand play" -s h -l help -d 'Print help'
54complete -c rsp -n "__fish_rsp_using_subcommand pause" -s h -l help -d 'Print help'
55complete -c rsp -n "__fish_rsp_using_subcommand resume" -s h -l help -d 'Print help'
56complete -c rsp -n "__fish_rsp_using_subcommand toggle" -s h -l help -d 'Print help'
57complete -c rsp -n "__fish_rsp_using_subcommand stop-playback" -s h -l help -d 'Print help'
58complete -c rsp -n "__fish_rsp_using_subcommand next" -s h -l help -d 'Print help'
59complete -c rsp -n "__fish_rsp_using_subcommand previous" -s h -l help -d 'Print help'
60complete -c rsp -n "__fish_rsp_using_subcommand volume" -s h -l help -d 'Print help'
61complete -c rsp -n "__fish_rsp_using_subcommand shuffle" -s h -l help -d 'Print help'
62complete -c rsp -n "__fish_rsp_using_subcommand queue" -s h -l help -d 'Print help'
63complete -c rsp -n "__fish_rsp_using_subcommand status" -s h -l help -d 'Print help'
64complete -c rsp -n "__fish_rsp_using_subcommand scan" -l paths -r -F
65complete -c rsp -n "__fish_rsp_using_subcommand scan" -l force
66complete -c rsp -n "__fish_rsp_using_subcommand scan" -s h -l help -d 'Print help'
67complete -c rsp -n "__fish_rsp_using_subcommand settings; and not __fish_seen_subcommand_from get set list unset help" -s h -l help -d 'Print help'
68complete -c rsp -n "__fish_rsp_using_subcommand settings; and not __fish_seen_subcommand_from get set list unset help" -f -a "get" -d 'Get a setting value'
69complete -c rsp -n "__fish_rsp_using_subcommand settings; and not __fish_seen_subcommand_from get set list unset help" -f -a "set" -d 'Set a setting value'
70complete -c rsp -n "__fish_rsp_using_subcommand settings; and not __fish_seen_subcommand_from get set list unset help" -f -a "list" -d 'List all settings'
71complete -c rsp -n "__fish_rsp_using_subcommand settings; and not __fish_seen_subcommand_from get set list unset help" -f -a "unset" -d 'Unset a setting'
72complete -c rsp -n "__fish_rsp_using_subcommand settings; and not __fish_seen_subcommand_from get set list unset help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'
73complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help'
74complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help'
75complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from list" -s h -l help -d 'Print help'
76complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help'
77complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from help" -f -a "get" -d 'Get a setting value'
78complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from help" -f -a "set" -d 'Set a setting value'
79complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from help" -f -a "list" -d 'List all settings'
80complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from help" -f -a "unset" -d 'Unset a setting'
81complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'
82complete -c rsp -n "__fish_rsp_using_subcommand completions" -l shell -d 'Also print to stdout for a specific shell' -r -f -a "bash\t''
83elvish\t''
84fish\t''
85powershell\t''
86zsh\t''"
87complete -c rsp -n "__fish_rsp_using_subcommand completions" -s h -l help -d 'Print help'
88complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "start" -d 'Start the daemon'
89complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "stop" -d 'Stop the daemon'
90complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "restart" -d 'Restart the daemon (kill existing and start new)'
91complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "play" -d 'Play a track, album, or artist'
92complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "pause" -d 'Pause playback'
93complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "resume" -d 'Resume playback'
94complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "toggle" -d 'Toggle play/pause'
95complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "stop-playback" -d 'Stop playback'
96complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "next" -d 'Skip to next track'
97complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "previous" -d 'Skip to previous track'
98complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "volume" -d 'Set volume (0-100)'
99complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "shuffle" -d 'Shuffle mode'
100complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "queue" -d 'Queue management'
101complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "status" -d 'Show player status'
102complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "scan" -d 'Scan music paths to populate database'
103complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "settings" -d 'Settings management'
104complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "completions" -d 'Generate shell completions and write to completions/ directory (bash, elvish, fish, powershell, zsh)'
105complete -c rsp -n "__fish_rsp_using_subcommand help; and not __fish_seen_subcommand_from start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)'
106complete -c rsp -n "__fish_rsp_using_subcommand help; and __fish_seen_subcommand_from settings" -f -a "get" -d 'Get a setting value'
107complete -c rsp -n "__fish_rsp_using_subcommand help; and __fish_seen_subcommand_from settings" -f -a "set" -d 'Set a setting value'
108complete -c rsp -n "__fish_rsp_using_subcommand help; and __fish_seen_subcommand_from settings" -f -a "list" -d 'List all settings'
109complete -c rsp -n "__fish_rsp_using_subcommand help; and __fish_seen_subcommand_from settings" -f -a "unset" -d 'Unset a setting'
diff --git a/completions/rsp.zsh b/completions/rsp.zsh
index cfba4e5..d635e3c 100644
--- a/completions/rsp.zsh
+++ b/completions/rsp.zsh
@@ -1,26 +1,665 @@
1#compdef rsp 1#compdef rsp
2 2
3autoload -U is-at-least
4
3_rsp() { 5_rsp() {
4 _arguments -C \ 6 typeset -A opt_args
5 '1:command:->cmd' \ 7 typeset -a _arguments_options
6 '*::args:->args' 8 local ret=1
7 9
8 case $state in 10 if is-at-least 5.2; then
9 cmd) 11 _arguments_options=(-s -S -C)
10 _values 'command' \ 12 else
11 'start' 'stop' 'restart' 'play' 'pause' 'resume' 'toggle' 'next' 'previous' \ 13 _arguments_options=(-s -C)
12 'volume' 'shuffle' 'queue' 'status' 'scan' 'settings' 14 fi
13 ;; 15
14 args) 16 local context curcontext="$curcontext" state line
15 # if first word is "play", complete files/dirs 17 _arguments "${_arguments_options[@]}" : \
16 if [[ $words[1] == play || $words[2] == play ]]; then 18'-h[Print help]' \
17 _files 19'--help[Print help]' \
18 else 20":: :_rsp_commands" \
19 # default: complete nothing (or you can list other subcommand args) 21"*::: :->rsp" \
20 return 0 22&& ret=0
21 fi 23 case $state in
22 ;; 24 (rsp)
23 esac 25 words=($line[1] "${words[@]}")
24} 26 (( CURRENT += 1 ))
25 27 curcontext="${curcontext%:*:*}:rsp-command-$line[1]:"
26compdef _rsp rsp 28 case $line[1] in
29 (start)
30_arguments "${_arguments_options[@]}" : \
31'-h[Print help]' \
32'--help[Print help]' \
33&& ret=0
34;;
35(stop)
36_arguments "${_arguments_options[@]}" : \
37'-h[Print help]' \
38'--help[Print help]' \
39&& ret=0
40;;
41(restart)
42_arguments "${_arguments_options[@]}" : \
43'-h[Print help]' \
44'--help[Print help]' \
45&& ret=0
46;;
47(play)
48_arguments "${_arguments_options[@]}" : \
49'-i[Play immediately (add after current and skip to it)]' \
50'--now[Play immediately (add after current and skip to it)]' \
51'-n[Add to queue after current track (don'\''t skip)]' \
52'--next[Add to queue after current track (don'\''t skip)]' \
53'-l[Add to end of queue (default)]' \
54'--last[Add to end of queue (default)]' \
55'-L[List available artists/albums]' \
56'--list[List available artists/albums]' \
57'-h[Print help]' \
58'--help[Print help]' \
59'::query -- Artist/Album or local file path:_rsp_play_artist_album_completion' \
60&& ret=0
61;;
62(pause)
63_arguments "${_arguments_options[@]}" : \
64'-h[Print help]' \
65'--help[Print help]' \
66&& ret=0
67;;
68(resume)
69_arguments "${_arguments_options[@]}" : \
70'-h[Print help]' \
71'--help[Print help]' \
72&& ret=0
73;;
74(toggle)
75_arguments "${_arguments_options[@]}" : \
76'-h[Print help]' \
77'--help[Print help]' \
78&& ret=0
79;;
80(stop-playback)
81_arguments "${_arguments_options[@]}" : \
82'-h[Print help]' \
83'--help[Print help]' \
84&& ret=0
85;;
86(next)
87_arguments "${_arguments_options[@]}" : \
88'-h[Print help]' \
89'--help[Print help]' \
90&& ret=0
91;;
92(previous)
93_arguments "${_arguments_options[@]}" : \
94'-h[Print help]' \
95'--help[Print help]' \
96&& ret=0
97;;
98(volume)
99_arguments "${_arguments_options[@]}" : \
100'-h[Print help]' \
101'--help[Print help]' \
102'::level:_default' \
103&& ret=0
104;;
105(shuffle)
106_arguments "${_arguments_options[@]}" : \
107'-h[Print help]' \
108'--help[Print help]' \
109'::mode:_default' \
110&& ret=0
111;;
112(queue)
113_arguments "${_arguments_options[@]}" : \
114'-h[Print help]' \
115'--help[Print help]' \
116'::position:_default' \
117'::query:_default' \
118&& ret=0
119;;
120(status)
121_arguments "${_arguments_options[@]}" : \
122'-h[Print help]' \
123'--help[Print help]' \
124&& ret=0
125;;
126(scan)
127_arguments "${_arguments_options[@]}" : \
128'*--paths=[]:PATHS:_files' \
129'--force[]' \
130'-h[Print help]' \
131'--help[Print help]' \
132&& ret=0
133;;
134(settings)
135_arguments "${_arguments_options[@]}" : \
136'-h[Print help]' \
137'--help[Print help]' \
138":: :_rsp__subcmd__settings_commands" \
139"*::: :->settings" \
140&& ret=0
141
142 case $state in
143 (settings)
144 words=($line[1] "${words[@]}")
145 (( CURRENT += 1 ))
146 curcontext="${curcontext%:*:*}:rsp-settings-command-$line[1]:"
147 case $line[1] in
148 (get)
149_arguments "${_arguments_options[@]}" : \
150'-h[Print help]' \
151'--help[Print help]' \
152':key:_default' \
153&& ret=0
154;;
155(set)
156_arguments "${_arguments_options[@]}" : \
157'-h[Print help]' \
158'--help[Print help]' \
159':key:_default' \
160':value:_default' \
161&& ret=0
162;;
163(list)
164_arguments "${_arguments_options[@]}" : \
165'-h[Print help]' \
166'--help[Print help]' \
167&& ret=0
168;;
169(unset)
170_arguments "${_arguments_options[@]}" : \
171'-h[Print help]' \
172'--help[Print help]' \
173':key:_default' \
174&& ret=0
175;;
176(help)
177_arguments "${_arguments_options[@]}" : \
178":: :_rsp__subcmd__settings__subcmd__help_commands" \
179"*::: :->help" \
180&& ret=0
181
182 case $state in
183 (help)
184 words=($line[1] "${words[@]}")
185 (( CURRENT += 1 ))
186 curcontext="${curcontext%:*:*}:rsp-settings-help-command-$line[1]:"
187 case $line[1] in
188 (get)
189_arguments "${_arguments_options[@]}" : \
190&& ret=0
191;;
192(set)
193_arguments "${_arguments_options[@]}" : \
194&& ret=0
195;;
196(list)
197_arguments "${_arguments_options[@]}" : \
198&& ret=0
199;;
200(unset)
201_arguments "${_arguments_options[@]}" : \
202&& ret=0
203;;
204(help)
205_arguments "${_arguments_options[@]}" : \
206&& ret=0
207;;
208 esac
209 ;;
210esac
211;;
212 esac
213 ;;
214esac
215;;
216(completions)
217_arguments "${_arguments_options[@]}" : \
218'--shell=[Also print to stdout for a specific shell]:SHELL:(bash elvish fish powershell zsh)' \
219'-h[Print help]' \
220'--help[Print help]' \
221&& ret=0
222;;
223(help)
224_arguments "${_arguments_options[@]}" : \
225":: :_rsp__subcmd__help_commands" \
226"*::: :->help" \
227&& ret=0
228
229 case $state in
230 (help)
231 words=($line[1] "${words[@]}")
232 (( CURRENT += 1 ))
233 curcontext="${curcontext%:*:*}:rsp-help-command-$line[1]:"
234 case $line[1] in
235 (start)
236_arguments "${_arguments_options[@]}" : \
237&& ret=0
238;;
239(stop)
240_arguments "${_arguments_options[@]}" : \
241&& ret=0
242;;
243(restart)
244_arguments "${_arguments_options[@]}" : \
245&& ret=0
246;;
247(play)
248_arguments "${_arguments_options[@]}" : \
249&& ret=0
250;;
251(pause)
252_arguments "${_arguments_options[@]}" : \
253&& ret=0
254;;
255(resume)
256_arguments "${_arguments_options[@]}" : \
257&& ret=0
258;;
259(toggle)
260_arguments "${_arguments_options[@]}" : \
261&& ret=0
262;;
263(stop-playback)
264_arguments "${_arguments_options[@]}" : \
265&& ret=0
266;;
267(next)
268_arguments "${_arguments_options[@]}" : \
269&& ret=0
270;;
271(previous)
272_arguments "${_arguments_options[@]}" : \
273&& ret=0
274;;
275(volume)
276_arguments "${_arguments_options[@]}" : \
277&& ret=0
278;;
279(shuffle)
280_arguments "${_arguments_options[@]}" : \
281&& ret=0
282;;
283(queue)
284_arguments "${_arguments_options[@]}" : \
285&& ret=0
286;;
287(status)
288_arguments "${_arguments_options[@]}" : \
289&& ret=0
290;;
291(scan)
292_arguments "${_arguments_options[@]}" : \
293&& ret=0
294;;
295(settings)
296_arguments "${_arguments_options[@]}" : \
297":: :_rsp__subcmd__help__subcmd__settings_commands" \
298"*::: :->settings" \
299&& ret=0
300
301 case $state in
302 (settings)
303 words=($line[1] "${words[@]}")
304 (( CURRENT += 1 ))
305 curcontext="${curcontext%:*:*}:rsp-help-settings-command-$line[1]:"
306 case $line[1] in
307 (get)
308_arguments "${_arguments_options[@]}" : \
309&& ret=0
310;;
311(set)
312_arguments "${_arguments_options[@]}" : \
313&& ret=0
314;;
315(list)
316_arguments "${_arguments_options[@]}" : \
317&& ret=0
318;;
319(unset)
320_arguments "${_arguments_options[@]}" : \
321&& ret=0
322;;
323 esac
324 ;;
325esac
326;;
327(completions)
328_arguments "${_arguments_options[@]}" : \
329&& ret=0
330;;
331(help)
332_arguments "${_arguments_options[@]}" : \
333&& ret=0
334;;
335 esac
336 ;;
337esac
338;;
339 esac
340 ;;
341esac
342}
343
344(( $+functions[_rsp_commands] )) ||
345_rsp_commands() {
346 local commands; commands=(
347'start:Start the daemon' \
348'stop:Stop the daemon' \
349'restart:Restart the daemon (kill existing and start new)' \
350'play:Play a track, album, or artist' \
351'pause:Pause playback' \
352'resume:Resume playback' \
353'toggle:Toggle play/pause' \
354'stop-playback:Stop playback' \
355'next:Skip to next track' \
356'previous:Skip to previous track' \
357'volume:Set volume (0-100)' \
358'shuffle:Shuffle mode' \
359'queue:Queue management' \
360'status:Show player status' \
361'scan:Scan music paths to populate database' \
362'settings:Settings management' \
363'completions:Generate shell completions and write to completions/ directory (bash, elvish, fish, powershell, zsh)' \
364'help:Print this message or the help of the given subcommand(s)' \
365 )
366 _describe -t commands 'rsp commands' commands "$@"
367}
368(( $+functions[_rsp__subcmd__completions_commands] )) ||
369_rsp__subcmd__completions_commands() {
370 local commands; commands=()
371 _describe -t commands 'rsp completions commands' commands "$@"
372}
373(( $+functions[_rsp__subcmd__help_commands] )) ||
374_rsp__subcmd__help_commands() {
375 local commands; commands=(
376'start:Start the daemon' \
377'stop:Stop the daemon' \
378'restart:Restart the daemon (kill existing and start new)' \
379'play:Play a track, album, or artist' \
380'pause:Pause playback' \
381'resume:Resume playback' \
382'toggle:Toggle play/pause' \
383'stop-playback:Stop playback' \
384'next:Skip to next track' \
385'previous:Skip to previous track' \
386'volume:Set volume (0-100)' \
387'shuffle:Shuffle mode' \
388'queue:Queue management' \
389'status:Show player status' \
390'scan:Scan music paths to populate database' \
391'settings:Settings management' \
392'completions:Generate shell completions and write to completions/ directory (bash, elvish, fish, powershell, zsh)' \
393'help:Print this message or the help of the given subcommand(s)' \
394 )
395 _describe -t commands 'rsp help commands' commands "$@"
396}
397(( $+functions[_rsp__subcmd__help__subcmd__completions_commands] )) ||
398_rsp__subcmd__help__subcmd__completions_commands() {
399 local commands; commands=()
400 _describe -t commands 'rsp help completions commands' commands "$@"
401}
402(( $+functions[_rsp__subcmd__help__subcmd__help_commands] )) ||
403_rsp__subcmd__help__subcmd__help_commands() {
404 local commands; commands=()
405 _describe -t commands 'rsp help help commands' commands "$@"
406}
407(( $+functions[_rsp__subcmd__help__subcmd__next_commands] )) ||
408_rsp__subcmd__help__subcmd__next_commands() {
409 local commands; commands=()
410 _describe -t commands 'rsp help next commands' commands "$@"
411}
412(( $+functions[_rsp__subcmd__help__subcmd__pause_commands] )) ||
413_rsp__subcmd__help__subcmd__pause_commands() {
414 local commands; commands=()
415 _describe -t commands 'rsp help pause commands' commands "$@"
416}
417(( $+functions[_rsp__subcmd__help__subcmd__play_commands] )) ||
418_rsp__subcmd__help__subcmd__play_commands() {
419 local commands; commands=()
420 _describe -t commands 'rsp help play commands' commands "$@"
421}
422(( $+functions[_rsp__subcmd__help__subcmd__previous_commands] )) ||
423_rsp__subcmd__help__subcmd__previous_commands() {
424 local commands; commands=()
425 _describe -t commands 'rsp help previous commands' commands "$@"
426}
427(( $+functions[_rsp__subcmd__help__subcmd__queue_commands] )) ||
428_rsp__subcmd__help__subcmd__queue_commands() {
429 local commands; commands=()
430 _describe -t commands 'rsp help queue commands' commands "$@"
431}
432(( $+functions[_rsp__subcmd__help__subcmd__restart_commands] )) ||
433_rsp__subcmd__help__subcmd__restart_commands() {
434 local commands; commands=()
435 _describe -t commands 'rsp help restart commands' commands "$@"
436}
437(( $+functions[_rsp__subcmd__help__subcmd__resume_commands] )) ||
438_rsp__subcmd__help__subcmd__resume_commands() {
439 local commands; commands=()
440 _describe -t commands 'rsp help resume commands' commands "$@"
441}
442(( $+functions[_rsp__subcmd__help__subcmd__scan_commands] )) ||
443_rsp__subcmd__help__subcmd__scan_commands() {
444 local commands; commands=()
445 _describe -t commands 'rsp help scan commands' commands "$@"
446}
447(( $+functions[_rsp__subcmd__help__subcmd__settings_commands] )) ||
448_rsp__subcmd__help__subcmd__settings_commands() {
449 local commands; commands=(
450'get:Get a setting value' \
451'set:Set a setting value' \
452'list:List all settings' \
453'unset:Unset a setting' \
454 )
455 _describe -t commands 'rsp help settings commands' commands "$@"
456}
457(( $+functions[_rsp__subcmd__help__subcmd__settings__subcmd__get_commands] )) ||
458_rsp__subcmd__help__subcmd__settings__subcmd__get_commands() {
459 local commands; commands=()
460 _describe -t commands 'rsp help settings get commands' commands "$@"
461}
462(( $+functions[_rsp__subcmd__help__subcmd__settings__subcmd__list_commands] )) ||
463_rsp__subcmd__help__subcmd__settings__subcmd__list_commands() {
464 local commands; commands=()
465 _describe -t commands 'rsp help settings list commands' commands "$@"
466}
467(( $+functions[_rsp__subcmd__help__subcmd__settings__subcmd__set_commands] )) ||
468_rsp__subcmd__help__subcmd__settings__subcmd__set_commands() {
469 local commands; commands=()
470 _describe -t commands 'rsp help settings set commands' commands "$@"
471}
472(( $+functions[_rsp__subcmd__help__subcmd__settings__subcmd__unset_commands] )) ||
473_rsp__subcmd__help__subcmd__settings__subcmd__unset_commands() {
474 local commands; commands=()
475 _describe -t commands 'rsp help settings unset commands' commands "$@"
476}
477(( $+functions[_rsp__subcmd__help__subcmd__shuffle_commands] )) ||
478_rsp__subcmd__help__subcmd__shuffle_commands() {
479 local commands; commands=()
480 _describe -t commands 'rsp help shuffle commands' commands "$@"
481}
482(( $+functions[_rsp__subcmd__help__subcmd__start_commands] )) ||
483_rsp__subcmd__help__subcmd__start_commands() {
484 local commands; commands=()
485 _describe -t commands 'rsp help start commands' commands "$@"
486}
487(( $+functions[_rsp__subcmd__help__subcmd__status_commands] )) ||
488_rsp__subcmd__help__subcmd__status_commands() {
489 local commands; commands=()
490 _describe -t commands 'rsp help status commands' commands "$@"
491}
492(( $+functions[_rsp__subcmd__help__subcmd__stop_commands] )) ||
493_rsp__subcmd__help__subcmd__stop_commands() {
494 local commands; commands=()
495 _describe -t commands 'rsp help stop commands' commands "$@"
496}
497(( $+functions[_rsp__subcmd__help__subcmd__stop-playback_commands] )) ||
498_rsp__subcmd__help__subcmd__stop-playback_commands() {
499 local commands; commands=()
500 _describe -t commands 'rsp help stop-playback commands' commands "$@"
501}
502(( $+functions[_rsp__subcmd__help__subcmd__toggle_commands] )) ||
503_rsp__subcmd__help__subcmd__toggle_commands() {
504 local commands; commands=()
505 _describe -t commands 'rsp help toggle commands' commands "$@"
506}
507(( $+functions[_rsp__subcmd__help__subcmd__volume_commands] )) ||
508_rsp__subcmd__help__subcmd__volume_commands() {
509 local commands; commands=()
510 _describe -t commands 'rsp help volume commands' commands "$@"
511}
512(( $+functions[_rsp__subcmd__next_commands] )) ||
513_rsp__subcmd__next_commands() {
514 local commands; commands=()
515 _describe -t commands 'rsp next commands' commands "$@"
516}
517(( $+functions[_rsp__subcmd__pause_commands] )) ||
518_rsp__subcmd__pause_commands() {
519 local commands; commands=()
520 _describe -t commands 'rsp pause commands' commands "$@"
521}
522(( $+functions[_rsp__subcmd__play_commands] )) ||
523_rsp__subcmd__play_commands() {
524 local commands; commands=()
525 _describe -t commands 'rsp play commands' commands "$@"
526}
527(( $+functions[_rsp__subcmd__previous_commands] )) ||
528_rsp__subcmd__previous_commands() {
529 local commands; commands=()
530 _describe -t commands 'rsp previous commands' commands "$@"
531}
532(( $+functions[_rsp__subcmd__queue_commands] )) ||
533_rsp__subcmd__queue_commands() {
534 local commands; commands=()
535 _describe -t commands 'rsp queue commands' commands "$@"
536}
537(( $+functions[_rsp__subcmd__restart_commands] )) ||
538_rsp__subcmd__restart_commands() {
539 local commands; commands=()
540 _describe -t commands 'rsp restart commands' commands "$@"
541}
542(( $+functions[_rsp__subcmd__resume_commands] )) ||
543_rsp__subcmd__resume_commands() {
544 local commands; commands=()
545 _describe -t commands 'rsp resume commands' commands "$@"
546}
547(( $+functions[_rsp__subcmd__scan_commands] )) ||
548_rsp__subcmd__scan_commands() {
549 local commands; commands=()
550 _describe -t commands 'rsp scan commands' commands "$@"
551}
552(( $+functions[_rsp__subcmd__settings_commands] )) ||
553_rsp__subcmd__settings_commands() {
554 local commands; commands=(
555'get:Get a setting value' \
556'set:Set a setting value' \
557'list:List all settings' \
558'unset:Unset a setting' \
559'help:Print this message or the help of the given subcommand(s)' \
560 )
561 _describe -t commands 'rsp settings commands' commands "$@"
562}
563(( $+functions[_rsp__subcmd__settings__subcmd__get_commands] )) ||
564_rsp__subcmd__settings__subcmd__get_commands() {
565 local commands; commands=()
566 _describe -t commands 'rsp settings get commands' commands "$@"
567}
568(( $+functions[_rsp__subcmd__settings__subcmd__help_commands] )) ||
569_rsp__subcmd__settings__subcmd__help_commands() {
570 local commands; commands=(
571'get:Get a setting value' \
572'set:Set a setting value' \
573'list:List all settings' \
574'unset:Unset a setting' \
575'help:Print this message or the help of the given subcommand(s)' \
576 )
577 _describe -t commands 'rsp settings help commands' commands "$@"
578}
579(( $+functions[_rsp__subcmd__settings__subcmd__help__subcmd__get_commands] )) ||
580_rsp__subcmd__settings__subcmd__help__subcmd__get_commands() {
581 local commands; commands=()
582 _describe -t commands 'rsp settings help get commands' commands "$@"
583}
584(( $+functions[_rsp__subcmd__settings__subcmd__help__subcmd__help_commands] )) ||
585_rsp__subcmd__settings__subcmd__help__subcmd__help_commands() {
586 local commands; commands=()
587 _describe -t commands 'rsp settings help help commands' commands "$@"
588}
589(( $+functions[_rsp__subcmd__settings__subcmd__help__subcmd__list_commands] )) ||
590_rsp__subcmd__settings__subcmd__help__subcmd__list_commands() {
591 local commands; commands=()
592 _describe -t commands 'rsp settings help list commands' commands "$@"
593}
594(( $+functions[_rsp__subcmd__settings__subcmd__help__subcmd__set_commands] )) ||
595_rsp__subcmd__settings__subcmd__help__subcmd__set_commands() {
596 local commands; commands=()
597 _describe -t commands 'rsp settings help set commands' commands "$@"
598}
599(( $+functions[_rsp__subcmd__settings__subcmd__help__subcmd__unset_commands] )) ||
600_rsp__subcmd__settings__subcmd__help__subcmd__unset_commands() {
601 local commands; commands=()
602 _describe -t commands 'rsp settings help unset commands' commands "$@"
603}
604(( $+functions[_rsp__subcmd__settings__subcmd__list_commands] )) ||
605_rsp__subcmd__settings__subcmd__list_commands() {
606 local commands; commands=()
607 _describe -t commands 'rsp settings list commands' commands "$@"
608}
609(( $+functions[_rsp__subcmd__settings__subcmd__set_commands] )) ||
610_rsp__subcmd__settings__subcmd__set_commands() {
611 local commands; commands=()
612 _describe -t commands 'rsp settings set commands' commands "$@"
613}
614(( $+functions[_rsp__subcmd__settings__subcmd__unset_commands] )) ||
615_rsp__subcmd__settings__subcmd__unset_commands() {
616 local commands; commands=()
617 _describe -t commands 'rsp settings unset commands' commands "$@"
618}
619(( $+functions[_rsp__subcmd__shuffle_commands] )) ||
620_rsp__subcmd__shuffle_commands() {
621 local commands; commands=()
622 _describe -t commands 'rsp shuffle commands' commands "$@"
623}
624(( $+functions[_rsp__subcmd__start_commands] )) ||
625_rsp__subcmd__start_commands() {
626 local commands; commands=()
627 _describe -t commands 'rsp start commands' commands "$@"
628}
629(( $+functions[_rsp__subcmd__status_commands] )) ||
630_rsp__subcmd__status_commands() {
631 local commands; commands=()
632 _describe -t commands 'rsp status commands' commands "$@"
633}
634(( $+functions[_rsp__subcmd__stop_commands] )) ||
635_rsp__subcmd__stop_commands() {
636 local commands; commands=()
637 _describe -t commands 'rsp stop commands' commands "$@"
638}
639(( $+functions[_rsp__subcmd__stop-playback_commands] )) ||
640_rsp__subcmd__stop-playback_commands() {
641 local commands; commands=()
642 _describe -t commands 'rsp stop-playback commands' commands "$@"
643}
644(( $+functions[_rsp__subcmd__toggle_commands] )) ||
645_rsp__subcmd__toggle_commands() {
646 local commands; commands=()
647 _describe -t commands 'rsp toggle commands' commands "$@"
648}
649(( $+functions[_rsp__subcmd__volume_commands] )) ||
650_rsp__subcmd__volume_commands() {
651 local commands; commands=()
652 _describe -t commands 'rsp volume commands' commands "$@"
653}
654
655if [ "$funcstack[1]" = "_rsp" ]; then
656 _rsp "$@"
657else
658 compdef _rsp rsp
659fi
660
661_rsp_play_artist_album_completion() {
662 local -a artists
663 artists=("$(rsp play --list 2>/dev/null)")
664 _describe -t artist-album 'artist/album' artists
665}
diff --git a/install.sh b/install.sh
index 6429345..5a1e888 100755
--- a/install.sh
+++ b/install.sh
@@ -12,33 +12,7 @@ echo "Installing to /usr/bin/rsp..."
12sudo cp target/release/rsp /usr/bin/rsp 12sudo cp target/release/rsp /usr/bin/rsp
13sudo chmod +x /usr/bin/rsp 13sudo chmod +x /usr/bin/rsp
14 14
15echo "Installing shell completions for current shell..." 15echo ""
16SHELL_NAME=$(basename "$SHELL")
17
18case "$SHELL_NAME" in
19 zsh)
20 sudo mkdir -p /usr/share/zsh/site-functions
21 sudo cp completions/rsp.zsh /usr/share/zsh/site-functions/_rsp
22 sudo chmod +x /usr/share/zsh/site-functions/_rsp
23 echo "Installed completions for $SHELL_NAME"
24 ;;
25 bash)
26 sudo mkdir -p /usr/share/bash-completion/completions
27 sudo cp completions/rsp.bash /usr/share/bash-completion/completions/rsp
28 sudo chmod +x /usr/share/bash-completion/completions/rsp
29 echo "Installed completions for $SHELL_NAME"
30 ;;
31 fish)
32 sudo mkdir -p /usr/share/fish/vendor_completions.d
33 sudo cp completions/rsp.fish /usr/share/fish/vendor_completions.d/rsp.fish
34 sudo chmod +x /usr/share/fish/vendor_completions.d/rsp.fish
35 echo "Installed completions for $SHELL_NAME"
36 ;;
37 *)
38 echo "Unknown shell: $SHELL_NAME, installing no completions..."
39 ;;
40esac
41
42echo "Installing systemd service..." 16echo "Installing systemd service..."
43mkdir -p ~/.config/systemd/user 17mkdir -p ~/.config/systemd/user
44cp rsplayer.service ~/.config/systemd/user/ 18cp rsplayer.service ~/.config/systemd/user/
diff --git a/src/daemon.rs b/src/daemon.rs
index 3379c7b..9e02e3f 100644
--- a/src/daemon.rs
+++ b/src/daemon.rs
@@ -150,8 +150,12 @@ impl Queue {
150 } 150 }
151 151
152 fn insert_after_current(&mut self, path: PathBuf) { 152 fn insert_after_current(&mut self, path: PathBuf) {
153 let insert_idx = self.position + 1; 153 if self.tracks.is_empty() {
154 self.tracks.insert(insert_idx, Track::from_path(path)); 154 self.tracks.push(Track::from_path(path));
155 } else {
156 let insert_idx = self.position + 1;
157 self.tracks.insert(insert_idx, Track::from_path(path));
158 }
155 self.update_shuffle_indices(); 159 self.update_shuffle_indices();
156 } 160 }
157 161
@@ -165,11 +169,15 @@ impl Queue {
165 } 169 }
166 170
167 fn update_shuffle_indices(&mut self) { 171 fn update_shuffle_indices(&mut self) {
168 self.shuffled_indices = (0..self.tracks.len()).collect(); 172 let len = self.tracks.len();
173 self.shuffled_indices = (0..len).collect();
169 if let ShuffleMode::All = self.shuffle { 174 if let ShuffleMode::All = self.shuffle {
170 use rand::seq::SliceRandom; 175 use rand::seq::SliceRandom;
171 let mut rng = rand::rng(); 176 let mut rng = rand::rng();
172 self.shuffled_indices.shuffle(&mut rng); 177 let pos = self.position.min(len.saturating_sub(1));
178 if pos + 1 < len {
179 self.shuffled_indices[pos + 1..].shuffle(&mut rng);
180 }
173 } 181 }
174 } 182 }
175 183
@@ -583,10 +591,13 @@ fn process_command(
583 let path = std::path::PathBuf::from(path_str.clone()); 591 let path = std::path::PathBuf::from(path_str.clone());
584 if path.is_file() { 592 if path.is_file() {
585 if let Ok(mut q) = queue.lock() { 593 if let Ok(mut q) = queue.lock() {
594 let was_empty = q.tracks.is_empty();
586 match position { 595 match position {
587 "now" => { 596 "now" => {
588 q.insert_after_current(path.clone()); 597 q.insert_after_current(path.clone());
589 q.position += 1; 598 if !was_empty {
599 q.position += 1;
600 }
590 if let Some(track) = q.track_at(q.position) { 601 if let Some(track) = q.track_at(q.position) {
591 audio.play(track.path.clone()); 602 audio.play(track.path.clone());
592 } 603 }
@@ -609,12 +620,15 @@ fn process_command(
609 match find_audio_in_dir(&path) { 620 match find_audio_in_dir(&path) {
610 Some(files) if !files.is_empty() => { 621 Some(files) if !files.is_empty() => {
611 if let Ok(mut q) = queue.lock() { 622 if let Ok(mut q) = queue.lock() {
623 let was_empty = q.tracks.is_empty();
612 match position { 624 match position {
613 "now" => { 625 "now" => {
614 for file in &files { 626 for file in &files {
615 q.insert_after_current(file.clone()); 627 q.insert_after_current(file.clone());
616 } 628 }
617 q.position += 1; 629 if !was_empty {
630 q.position += 1;
631 }
618 if let Some(track) = q.track_at(q.position) { 632 if let Some(track) = q.track_at(q.position) {
619 audio.play(track.path.clone()); 633 audio.play(track.path.clone());
620 } 634 }
@@ -638,8 +652,10 @@ fn process_command(
638 for file in &files { 652 for file in &files {
639 q.add_track(file.clone()); 653 q.add_track(file.clone());
640 } 654 }
641 if let Some(track) = q.current() { 655 if !audio.is_playing() {
642 audio.play(track.path.clone()); 656 if let Some(track) = files.first() {
657 audio.play(track.clone());
658 }
643 } 659 }
644 format!("Queued {} tracks from: {}\n", files.len(), path_str) 660 format!("Queued {} tracks from: {}\n", files.len(), path_str)
645 } 661 }