From 03f4585424d05dd50022759c7ad098fe06277f6e Mon Sep 17 00:00:00 2001 From: salmonik Date: Thu, 7 May 2026 16:16:01 +0200 Subject: Fix queue bugs: play -i on empty queue, stale track replay after queue ends, shuffle preserving current position - insert_after_current: guard against panic on empty queue - play -i (now): skip position increment when queue was empty so track plays - directory last: use audio.is_playing() instead of q.current() to avoid replaying finished track - shuffle: only randomize tracks after current position --- AGENTS.md | 22 +- Cargo.lock | 10 + Cargo.toml | 1 + PLAN.md | 40 ++- TODO.md | 24 +- completions/rsp.bash | 920 ++++++++++++++++++++++++++++++++++++++++++++++++++- completions/rsp.fish | 114 ++++++- completions/rsp.zsh | 685 ++++++++++++++++++++++++++++++++++++-- install.sh | 28 +- src/daemon.rs | 32 +- 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: - Build: `cargo build` ## Development Workflow -- Use `rsp restart` or `rsplayer restart` to kill any running daemon and start a new one (useful during development) +- Use `rsp restart` to kill any running daemon and start a new one (useful during development) - Daemon runs in background; restart command handles cleanup automatically - After making changes to audio/playback/daemon code, always restart the daemon to test changes @@ -20,7 +20,7 @@ Run these before completing any task: - Follow standard Rust style (enforced by `cargo fmt`) - Never commit changes unless explicitly requested by the user - Update shell completions when adding/modifying CLI subcommands -- Use `rand` crate for shuffle/randomization features (added in v0.9) +- Use `rand` crate for shuffle/randomization features ## Task-Specific Guidelines - **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: - **Scrobbling changes**: Update Last.fm/ListenBrainz client implementation - **Config/Settings changes**: Update config schema, `rsp settings` subcommands, and scan interval/auto-scan logic -## Completed Features (Phase 2) +## Completed Features - [x] Unix socket daemon IPC - [x] Audio engine with play/pause/stop/volume - [x] Queue system with in-memory tracking and auto-advance @@ -42,16 +42,16 @@ Run these before completing any task: - [x] Resume CLI subcommand - [x] Directory playback - queues all audio files in folder recursively - [x] Fixed audio buffer underrun issues by using device default sample rate -- [x] Queue display with pager support (`rsplayer queue`) +- [x] Queue display with pager support (`rsp queue`) - [x] Auto-play next track when current track ends - [x] Metadata extraction and display (INDEX. ARTIST - TITLE format, falls back to filename) +- [x] `rsp scan` with `--force` and `--paths` options +- [x] `rsp settings` subcommands (get/set/list/unset) +- [x] Shell completions (`rsp completions bash|zsh|fish|powershell|elvish`) +- [x] Unit tests for Player, Track, and ShuffleMode ## Remaining Work -- Album shuffle mode (`ShuffleMode::Album`) -- Database integration for queue persistence -- `rsplayer queue` command for queue management +- Queue state persistence to disk +- Album shuffle mode with proper album/folder grouping - Scrobbling (Last.fm/ListenBrainz) -- Database scanning and schema -- Shell completion scripts -- Systemd service unit -- MPRIS/playerctl integration (zbus requires async, needs refactoring) +- Systemd service unit \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 82ef060..1a889fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -250,6 +250,15 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_complete" +version = "4.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "660c0520455b1013b9bcb0393d5f643d7e4454fb69c915b8d6d2aa0e9a45acc3" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "4.6.1" @@ -1622,6 +1631,7 @@ version = "0.1.0" dependencies = [ "chrono", "clap", + "clap_complete", "cpal", "ctrlc", "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" [dependencies] clap = { version = "4.6.1", features = ["derive", "string"] } +clap_complete = "4.6" rusqlite = { version = "0.39", features = ["bundled"] } directories = "6.0" serde = { 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 @@ # rsplayer Project Plan -## Phase 1: Setup & Core -1. Initialize Rust project, add dependencies: `clap` (CLI/autocompletion), `rusqlite` (SQLite), `symphonia`/`cpal` (audio), `directories` (XDG paths), `serde`/`toml` (config), `tokio` (daemon async), `reqwest` (scrobbling). -2. 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. -3. 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. +## Phase 1: Setup & Core ✓ +1. Initialize Rust project, add dependencies: `clap` (CLI/autocompletion), `rusqlite` (SQLite), `symphonia`/`cpal` (audio), `directories` (XDG paths), `serde`/`toml` (config), `tokio` (daemon async), `reqwest` (scrobbling). ✓ +2. 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. ✓ +3. SQLite library schema: `artists`, `albums`, `tracks` tables. Implement `rsp scan` to scan all paths in config's `music_paths`, populate/update database. ✓ -## Phase 2: Daemon -1. Unix socket daemon (path: `$XDG_RUNTIME_DIR/rsplayer/daemon.sock`) for IPC. -2. Audio engine: Symphonia decode + CPAL output, support play/pause/stop/volume/seek. -3. Queue: in-memory, `last` (append to end, default), `now` (play immediately, ending current song playback), `next` (insert after current). -4. Shuffle modes: `none` (linear playback), `all` (shuffle all tracks), `album` (shuffle within album). -5. Scrobbling: Last.fm and ListenBrainz support via configured credentials. +## Phase 2: Daemon ✓ +1. Unix socket daemon (path: `$XDG_RUNTIME_DIR/rsplayer/daemon.sock`) for IPC. ✓ +2. Audio engine: Symphonia decode + CPAL output, support play/pause/stop/volume/seek. ✓ +3. Queue: in-memory, `last` (append to end, default), `now` (play immediately, ending current song playback), `next` (insert after current). ✓ +4. Shuffle modes: `none` (linear playback), `all` (shuffle all tracks), `album` (shuffle within album, structure ready). ✓ -## Phase 3: CLI & Completion -1. Clap-based CLI with all subcommands. Generate shell completions for bash/zsh/fish, suggest database artists/albums/tracks, file paths, and config keys/values. -2. `rsp status`: show player state, current track, progress, volume, next 2-3 queue items. -3. `rsp queue`: no arguments display current queue; with arguments add items (default `last` behavior). -4. `rsp settings` subcommands: `get`, `set`, `list`, `unset` config values (music paths, scrobbling credentials, scan interval, etc.) without manual file editing. +## Phase 3: CLI & Completion ✓ +1. Clap-based CLI with all subcommands. ✓ +2. Shell completions for bash/zsh/fish/powershell/elvish (`rsp completions`). PARTIALLY +3. `rsp status`: show player state, current track, progress, volume, next 2-3 queue items. ✓ +4. `rsp queue`: no arguments display current queue; with arguments add items (default `last` behavior). BUGGED +5. `rsp settings` subcommands: `get`, `set`, `list`, `unset` config values. ✓ +6. `rsp scan`: `--force` full rescan, `--paths` override config paths. Uses symphonia for metadata. ✓ +7. `rsp play`: flexible insert options (`-i`/`--now`, `-n`/`--next`, `-l`/`--last`). ✓ ## Phase 4: Polish -1. Direct file/folder playback: prioritize database metadata if path matches known artist/album. -2. Logging, systemd service unit, unit tests. -3. Periodic rescan logic per config's `scan_interval`. +1. [ ] Queue state persistence - Save queue to disk so it survives daemon restarts. +2. [ ] Album shuffle mode - Implement proper `ShuffleMode::Album` (shuffle tracks within same album/folder). +3. [ ] Scrobbling - Last.fm and ListenBrainz support via configured credentials. +4. [ ] Logging and error handling improvements. +5. [ ] 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 @@ - [x] **Dev/release build config separation** - Store config next to binary in dev mode, use XDG in release mode. -- [x] **Volume without argument returns current volume** - `rsplayer volume` now returns current level. +- [x] **Volume without argument returns current volume** - `rsp volume` now returns current level. - [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. @@ -14,7 +14,7 @@ - [x] **Run clippy** - All linting checks pass. -- [x] **Run tests** - All tests pass (no tests exist yet). +- [x] **Run tests** - All tests pass. - [x] **Check formatting** - Code formatting is correct. @@ -24,7 +24,7 @@ - [x] **Add Resume CLI subcommand** - Added `Resume` subcommand to CLI so users can resume playback after pause. -- [x] **Implement shuffle mode** - Added shuffle on/off/album functionality with queue management in daemon. Supports `rsplayer shuffle on/off/album` commands. +- [x] **Implement shuffle mode** - Added shuffle on/off/album functionality with queue management in daemon. Supports `rsp shuffle on/off/album` commands. - [x] **Implement next/previous commands** - Next and previous track commands now work with the queue system. @@ -32,7 +32,7 @@ - [x] **Auto-play next track** - Daemon automatically plays next track when current one ends (using `poll_track_ended()`). -- [x] **Queue display with pager** - `rsplayer queue` shows all queued tracks with pager support for long lists. +- [x] **Queue display with pager** - `rsp queue` shows all queued tracks with pager support for long lists. - [x] **Album shuffle mode structure** - `ShuffleMode::Album` added to enum and queue logic (behaves like `All` until database ready). @@ -40,20 +40,20 @@ - [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. -## Potential Improvements +- [x] **Add unit tests for Player struct** - Tests added for Player, Track, PlaybackState, and ShuffleMode in `tests/playback.rs`. -- [ ] **Add error handling for audio playback** - Consider more robust error handling in the audio thread. +- [x] **Database scan command** - Implemented `rsp scan` with `--force` full rescan and `--paths` override options. Uses symphonia for metadata extraction. -- [x] **Add unit tests for Player struct** - The `Player` struct in `playback.rs` has no corresponding tests. +- [x] **Settings subcommands** - Implemented `rsp settings get/set/list/unset` for config management. -- [ ] **Persist queue state** - Save queue to disk so it survives daemon restarts. +- [x] **Shell completions** - Generate shell completions with `rsp completions bash|elvish|fish|powershell|zsh`. -- [ ] **Album shuffle mode (database)** - Implement proper `ShuffleMode::Album` when database is ready (shuffle tracks within same album/folder). +## Remaining Work -- [ ] **Scrobbling (Last.fm/ListenBrainz)** - Add scrobbling support via configured credentials. +- [ ] **Persist queue state** - Save queue to disk so it survives daemon restarts. -- [ ] **Database integration** - Scan music paths, populate SQLite database, use for metadata. +- [ ] **Scrobbling (Last.fm/ListenBrainz)** - Add scrobbling support via configured credentials. - [ ] **Shell completion scripts** - Generate bash/zsh/fish completions using clap. -- [ ] **Systemd service unit** - Create systemd service file for auto-start. +- [ ] **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 @@ -#!/usr/bin/env bash +_rsp_play_query_completions() { + local cur="${COMP_WORDS[COMP_CWORD]}" + # Only do dynamic completion if COMPREPLY is empty (no flag matched) + # and the current word doesn't start with - + if [[ ${#COMPREPLY[@]} -eq 0 && "$cur" != -* ]]; then + local -a artists + artists=($(rsp play --list 2>/dev/null)) + COMPREPLY=( $(compgen -W "${artists[*]}" -- "$cur") ) + fi +} _rsp() { - local cur prev words cword - _init_completion || return + local i cur prev opts cmd + COMPREPLY=() + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + cur="$2" + else + cur="${COMP_WORDS[COMP_CWORD]}" + fi + prev="$3" + cmd="" + opts="" + + for i in "${COMP_WORDS[@]:0:COMP_CWORD}" + do + case "${cmd},${i}" in + ",$1") + cmd="rsp" + ;; + rsp,completions) + cmd="rsp__subcmd__completions" + ;; + rsp,help) + cmd="rsp__subcmd__help" + ;; + rsp,next) + cmd="rsp__subcmd__next" + ;; + rsp,pause) + cmd="rsp__subcmd__pause" + ;; + rsp,play) + cmd="rsp__subcmd__play" + ;; + rsp,previous) + cmd="rsp__subcmd__previous" + ;; + rsp,queue) + cmd="rsp__subcmd__queue" + ;; + rsp,restart) + cmd="rsp__subcmd__restart" + ;; + rsp,resume) + cmd="rsp__subcmd__resume" + ;; + rsp,scan) + cmd="rsp__subcmd__scan" + ;; + rsp,settings) + cmd="rsp__subcmd__settings" + ;; + rsp,shuffle) + cmd="rsp__subcmd__shuffle" + ;; + rsp,start) + cmd="rsp__subcmd__start" + ;; + rsp,status) + cmd="rsp__subcmd__status" + ;; + rsp,stop) + cmd="rsp__subcmd__stop" + ;; + rsp,stop-playback) + cmd="rsp__subcmd__stop__subcmd__playback" + ;; + rsp,toggle) + cmd="rsp__subcmd__toggle" + ;; + rsp,volume) + cmd="rsp__subcmd__volume" + ;; + rsp__subcmd__help,completions) + cmd="rsp__subcmd__help__subcmd__completions" + ;; + rsp__subcmd__help,help) + cmd="rsp__subcmd__help__subcmd__help" + ;; + rsp__subcmd__help,next) + cmd="rsp__subcmd__help__subcmd__next" + ;; + rsp__subcmd__help,pause) + cmd="rsp__subcmd__help__subcmd__pause" + ;; + rsp__subcmd__help,play) + cmd="rsp__subcmd__help__subcmd__play" + ;; + rsp__subcmd__help,previous) + cmd="rsp__subcmd__help__subcmd__previous" + ;; + rsp__subcmd__help,queue) + cmd="rsp__subcmd__help__subcmd__queue" + ;; + rsp__subcmd__help,restart) + cmd="rsp__subcmd__help__subcmd__restart" + ;; + rsp__subcmd__help,resume) + cmd="rsp__subcmd__help__subcmd__resume" + ;; + rsp__subcmd__help,scan) + cmd="rsp__subcmd__help__subcmd__scan" + ;; + rsp__subcmd__help,settings) + cmd="rsp__subcmd__help__subcmd__settings" + ;; + rsp__subcmd__help,shuffle) + cmd="rsp__subcmd__help__subcmd__shuffle" + ;; + rsp__subcmd__help,start) + cmd="rsp__subcmd__help__subcmd__start" + ;; + rsp__subcmd__help,status) + cmd="rsp__subcmd__help__subcmd__status" + ;; + rsp__subcmd__help,stop) + cmd="rsp__subcmd__help__subcmd__stop" + ;; + rsp__subcmd__help,stop-playback) + cmd="rsp__subcmd__help__subcmd__stop__subcmd__playback" + ;; + rsp__subcmd__help,toggle) + cmd="rsp__subcmd__help__subcmd__toggle" + ;; + rsp__subcmd__help,volume) + cmd="rsp__subcmd__help__subcmd__volume" + ;; + rsp__subcmd__help__subcmd__settings,get) + cmd="rsp__subcmd__help__subcmd__settings__subcmd__get" + ;; + rsp__subcmd__help__subcmd__settings,list) + cmd="rsp__subcmd__help__subcmd__settings__subcmd__list" + ;; + rsp__subcmd__help__subcmd__settings,set) + cmd="rsp__subcmd__help__subcmd__settings__subcmd__set" + ;; + rsp__subcmd__help__subcmd__settings,unset) + cmd="rsp__subcmd__help__subcmd__settings__subcmd__unset" + ;; + rsp__subcmd__settings,get) + cmd="rsp__subcmd__settings__subcmd__get" + ;; + rsp__subcmd__settings,help) + cmd="rsp__subcmd__settings__subcmd__help" + ;; + rsp__subcmd__settings,list) + cmd="rsp__subcmd__settings__subcmd__list" + ;; + rsp__subcmd__settings,set) + cmd="rsp__subcmd__settings__subcmd__set" + ;; + rsp__subcmd__settings,unset) + cmd="rsp__subcmd__settings__subcmd__unset" + ;; + rsp__subcmd__settings__subcmd__help,get) + cmd="rsp__subcmd__settings__subcmd__help__subcmd__get" + ;; + rsp__subcmd__settings__subcmd__help,help) + cmd="rsp__subcmd__settings__subcmd__help__subcmd__help" + ;; + rsp__subcmd__settings__subcmd__help,list) + cmd="rsp__subcmd__settings__subcmd__help__subcmd__list" + ;; + rsp__subcmd__settings__subcmd__help,set) + cmd="rsp__subcmd__settings__subcmd__help__subcmd__set" + ;; + rsp__subcmd__settings__subcmd__help,unset) + cmd="rsp__subcmd__settings__subcmd__help__subcmd__unset" + ;; + *) + ;; + esac + done - case $prev in + case "${cmd}" in rsp) - COMPREPLY=($(compgen -W "start stop restart play pause resume toggle next previous volume shuffle queue status scan settings" -- "$cur")) + opts="-h --help start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__completions) + opts="-h --shell --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --shell) + COMPREPLY=($(compgen -W "bash elvish fish powershell zsh" -- "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help) + opts="start stop restart play pause resume toggle stop-playback next previous volume shuffle queue status scan settings completions help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__completions) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__next) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__pause) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__play) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__previous) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__queue) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__restart) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__resume) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__scan) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__settings) + opts="get set list unset" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__settings__subcmd__get) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__settings__subcmd__list) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__settings__subcmd__set) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__settings__subcmd__unset) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__shuffle) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__start) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__status) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__stop) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__stop__subcmd__playback) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__toggle) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__help__subcmd__volume) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__next) + opts="-h --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__pause) + opts="-h --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__play) + opts="-i -n -l -L -h --now --next --last --list --help [QUERY]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + + # Dynamic artist/album completion for query argument + _rsp_play_query_completions +return 0 + ;; + rsp__subcmd__previous) + opts="-h --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__queue) + opts="-h --help [POSITION] [QUERY]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__restart) + opts="-h --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__resume) + opts="-h --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__scan) + opts="-h --force --paths --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --paths) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__settings) + opts="-h --help get set list unset help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__settings__subcmd__get) + opts="-h --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__settings__subcmd__help) + opts="get set list unset help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__settings__subcmd__help__subcmd__get) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__settings__subcmd__help__subcmd__help) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__settings__subcmd__help__subcmd__list) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__settings__subcmd__help__subcmd__set) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__settings__subcmd__help__subcmd__unset) + opts="" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__settings__subcmd__list) + opts="-h --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__settings__subcmd__set) + opts="-h --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__settings__subcmd__unset) + opts="-h --help " + if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__shuffle) + opts="-h --help [MODE]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__start) + opts="-h --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + rsp__subcmd__status) + opts="-h --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 ;; - play) - _filedir + rsp__subcmd__stop) + opts="-h --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 ;; - volume) - COMPREPLY=($(compgen -W "0 10 20 30 40 50 60 70 80 90 100" -- "$cur")) + rsp__subcmd__stop__subcmd__playback) + opts="-h --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 ;; - shuffle) - COMPREPLY=($(compgen -W "on off album" -- "$cur")) + rsp__subcmd__toggle) + opts="-h --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 ;; - settings) - COMPREPLY=($(compgen -W "get set list unset" -- "$cur")) + rsp__subcmd__volume) + opts="-h --help [LEVEL]" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 ;; esac } -complete -F _rsp rsp +if [[ "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -ge 4 || "${BASH_VERSINFO[0]}" -gt 4 ]]; then + complete -F _rsp -o nosort -o bashdefault -o default rsp +else + complete -F _rsp -o bashdefault -o default rsp +fi 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 @@ -# rsp fish completion +# Print an optspec for argparse to handle cmd's options that are independent of any subcommand. +function __fish_rsp_global_optspecs + string join \n h/help +end -complete -c rsp -n '__fish_use_subcommand' -a 'start stop restart play pause resume toggle next previous volume shuffle queue status scan settings' -d 'Command' +function __fish_rsp_needs_command + # Figure out if the current invocation already has a command. + set -l cmd (commandline -opc) + set -e cmd[1] + argparse -s (__fish_rsp_global_optspecs) -- $cmd 2>/dev/null + or return + if set -q argv[1] + # Also print the command, so this can be used to figure out what it is. + echo $argv[1] + return 1 + end + return 0 +end -complete -c rsp -n '__fish_seen_subcommand_from play' -f -d 'Audio file or directory' +function __fish_rsp_using_subcommand + set -l cmd (__fish_rsp_needs_command) + test -z "$cmd" + and return 1 + contains -- $cmd[1] $argv +end -complete -c rsp -n '__fish_seen_subcommand_from volume' -a '0 10 20 30 40 50 60 70 80 90 100' -d 'Volume level' - -complete -c rsp -n '__fish_seen_subcommand_from shuffle' -a 'on off album' -d 'Shuffle mode' - -complete -c rsp -n '__fish_seen_subcommand_from settings' -a 'get set list unset' -d 'Settings command' +complete -c rsp -n "__fish_rsp_needs_command" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "start" -d 'Start the daemon' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "stop" -d 'Stop the daemon' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "restart" -d 'Restart the daemon (kill existing and start new)' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "play" -d 'Play a track, album, or artist' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "pause" -d 'Pause playback' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "resume" -d 'Resume playback' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "toggle" -d 'Toggle play/pause' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "stop-playback" -d 'Stop playback' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "next" -d 'Skip to next track' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "previous" -d 'Skip to previous track' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "volume" -d 'Set volume (0-100)' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "shuffle" -d 'Shuffle mode' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "queue" -d 'Queue management' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "status" -d 'Show player status' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "scan" -d 'Scan music paths to populate database' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "settings" -d 'Settings management' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "completions" -d 'Generate shell completions and write to completions/ directory (bash, elvish, fish, powershell, zsh)' +complete -c rsp -n "__fish_rsp_needs_command" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c rsp -n "__fish_rsp_using_subcommand start" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand stop" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand restart" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand play" -s i -l now -d 'Play immediately (add after current and skip to it)' +complete -c rsp -n "__fish_rsp_using_subcommand play" -s n -l next -d 'Add to queue after current track (don\'t skip)' +complete -c rsp -n "__fish_rsp_using_subcommand play" -s l -l last -d 'Add to end of queue (default)' +complete -c rsp -n "__fish_rsp_using_subcommand play" -s L -l list -d 'List available artists/albums' +complete -c rsp -n "__fish_rsp_using_subcommand play" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand pause" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand resume" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand toggle" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand stop-playback" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand next" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand previous" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand volume" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand shuffle" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand queue" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand status" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand scan" -l paths -r -F +complete -c rsp -n "__fish_rsp_using_subcommand scan" -l force +complete -c rsp -n "__fish_rsp_using_subcommand scan" -s h -l help -d 'Print help' +complete -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' +complete -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' +complete -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' +complete -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' +complete -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' +complete -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)' +complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from get" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from list" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from unset" -s h -l help -d 'Print help' +complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from help" -f -a "get" -d 'Get a setting value' +complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from help" -f -a "set" -d 'Set a setting value' +complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from help" -f -a "list" -d 'List all settings' +complete -c rsp -n "__fish_rsp_using_subcommand settings; and __fish_seen_subcommand_from help" -f -a "unset" -d 'Unset a setting' +complete -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)' +complete -c rsp -n "__fish_rsp_using_subcommand completions" -l shell -d 'Also print to stdout for a specific shell' -r -f -a "bash\t'' +elvish\t'' +fish\t'' +powershell\t'' +zsh\t''" +complete -c rsp -n "__fish_rsp_using_subcommand completions" -s h -l help -d 'Print help' +complete -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' +complete -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' +complete -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)' +complete -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' +complete -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' +complete -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' +complete -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' +complete -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' +complete -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' +complete -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' +complete -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)' +complete -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' +complete -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' +complete -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' +complete -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' +complete -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' +complete -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)' +complete -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)' +complete -c rsp -n "__fish_rsp_using_subcommand help; and __fish_seen_subcommand_from settings" -f -a "get" -d 'Get a setting value' +complete -c rsp -n "__fish_rsp_using_subcommand help; and __fish_seen_subcommand_from settings" -f -a "set" -d 'Set a setting value' +complete -c rsp -n "__fish_rsp_using_subcommand help; and __fish_seen_subcommand_from settings" -f -a "list" -d 'List all settings' +complete -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 @@ #compdef rsp +autoload -U is-at-least + _rsp() { - _arguments -C \ - '1:command:->cmd' \ - '*::args:->args' - - case $state in - cmd) - _values 'command' \ - 'start' 'stop' 'restart' 'play' 'pause' 'resume' 'toggle' 'next' 'previous' \ - 'volume' 'shuffle' 'queue' 'status' 'scan' 'settings' - ;; - args) - # if first word is "play", complete files/dirs - if [[ $words[1] == play || $words[2] == play ]]; then - _files - else - # default: complete nothing (or you can list other subcommand args) - return 0 - fi - ;; - esac -} - -compdef _rsp rsp + typeset -A opt_args + typeset -a _arguments_options + local ret=1 + + if is-at-least 5.2; then + _arguments_options=(-s -S -C) + else + _arguments_options=(-s -C) + fi + + local context curcontext="$curcontext" state line + _arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +":: :_rsp_commands" \ +"*::: :->rsp" \ +&& ret=0 + case $state in + (rsp) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rsp-command-$line[1]:" + case $line[1] in + (start) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(stop) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(restart) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(play) +_arguments "${_arguments_options[@]}" : \ +'-i[Play immediately (add after current and skip to it)]' \ +'--now[Play immediately (add after current and skip to it)]' \ +'-n[Add to queue after current track (don'\''t skip)]' \ +'--next[Add to queue after current track (don'\''t skip)]' \ +'-l[Add to end of queue (default)]' \ +'--last[Add to end of queue (default)]' \ +'-L[List available artists/albums]' \ +'--list[List available artists/albums]' \ +'-h[Print help]' \ +'--help[Print help]' \ +'::query -- Artist/Album or local file path:_rsp_play_artist_album_completion' \ +&& ret=0 +;; +(pause) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(resume) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(toggle) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(stop-playback) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(next) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(previous) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(volume) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +'::level:_default' \ +&& ret=0 +;; +(shuffle) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +'::mode:_default' \ +&& ret=0 +;; +(queue) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +'::position:_default' \ +'::query:_default' \ +&& ret=0 +;; +(status) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(scan) +_arguments "${_arguments_options[@]}" : \ +'*--paths=[]:PATHS:_files' \ +'--force[]' \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(settings) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +":: :_rsp__subcmd__settings_commands" \ +"*::: :->settings" \ +&& ret=0 + + case $state in + (settings) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rsp-settings-command-$line[1]:" + case $line[1] in + (get) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +':key:_default' \ +&& ret=0 +;; +(set) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +':key:_default' \ +':value:_default' \ +&& ret=0 +;; +(list) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(unset) +_arguments "${_arguments_options[@]}" : \ +'-h[Print help]' \ +'--help[Print help]' \ +':key:_default' \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" : \ +":: :_rsp__subcmd__settings__subcmd__help_commands" \ +"*::: :->help" \ +&& ret=0 + + case $state in + (help) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rsp-settings-help-command-$line[1]:" + case $line[1] in + (get) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(set) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(list) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(unset) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; + esac + ;; +esac +;; + esac + ;; +esac +;; +(completions) +_arguments "${_arguments_options[@]}" : \ +'--shell=[Also print to stdout for a specific shell]:SHELL:(bash elvish fish powershell zsh)' \ +'-h[Print help]' \ +'--help[Print help]' \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" : \ +":: :_rsp__subcmd__help_commands" \ +"*::: :->help" \ +&& ret=0 + + case $state in + (help) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rsp-help-command-$line[1]:" + case $line[1] in + (start) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(stop) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(restart) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(play) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(pause) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(resume) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(toggle) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(stop-playback) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(next) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(previous) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(volume) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(shuffle) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(queue) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(status) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(scan) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(settings) +_arguments "${_arguments_options[@]}" : \ +":: :_rsp__subcmd__help__subcmd__settings_commands" \ +"*::: :->settings" \ +&& ret=0 + + case $state in + (settings) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:rsp-help-settings-command-$line[1]:" + case $line[1] in + (get) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(set) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(list) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(unset) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; + esac + ;; +esac +;; +(completions) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; +(help) +_arguments "${_arguments_options[@]}" : \ +&& ret=0 +;; + esac + ;; +esac +;; + esac + ;; +esac +} + +(( $+functions[_rsp_commands] )) || +_rsp_commands() { + local commands; commands=( +'start:Start the daemon' \ +'stop:Stop the daemon' \ +'restart:Restart the daemon (kill existing and start new)' \ +'play:Play a track, album, or artist' \ +'pause:Pause playback' \ +'resume:Resume playback' \ +'toggle:Toggle play/pause' \ +'stop-playback:Stop playback' \ +'next:Skip to next track' \ +'previous:Skip to previous track' \ +'volume:Set volume (0-100)' \ +'shuffle:Shuffle mode' \ +'queue:Queue management' \ +'status:Show player status' \ +'scan:Scan music paths to populate database' \ +'settings:Settings management' \ +'completions:Generate shell completions and write to completions/ directory (bash, elvish, fish, powershell, zsh)' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rsp commands' commands "$@" +} +(( $+functions[_rsp__subcmd__completions_commands] )) || +_rsp__subcmd__completions_commands() { + local commands; commands=() + _describe -t commands 'rsp completions commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help_commands] )) || +_rsp__subcmd__help_commands() { + local commands; commands=( +'start:Start the daemon' \ +'stop:Stop the daemon' \ +'restart:Restart the daemon (kill existing and start new)' \ +'play:Play a track, album, or artist' \ +'pause:Pause playback' \ +'resume:Resume playback' \ +'toggle:Toggle play/pause' \ +'stop-playback:Stop playback' \ +'next:Skip to next track' \ +'previous:Skip to previous track' \ +'volume:Set volume (0-100)' \ +'shuffle:Shuffle mode' \ +'queue:Queue management' \ +'status:Show player status' \ +'scan:Scan music paths to populate database' \ +'settings:Settings management' \ +'completions:Generate shell completions and write to completions/ directory (bash, elvish, fish, powershell, zsh)' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rsp help commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__completions_commands] )) || +_rsp__subcmd__help__subcmd__completions_commands() { + local commands; commands=() + _describe -t commands 'rsp help completions commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__help_commands] )) || +_rsp__subcmd__help__subcmd__help_commands() { + local commands; commands=() + _describe -t commands 'rsp help help commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__next_commands] )) || +_rsp__subcmd__help__subcmd__next_commands() { + local commands; commands=() + _describe -t commands 'rsp help next commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__pause_commands] )) || +_rsp__subcmd__help__subcmd__pause_commands() { + local commands; commands=() + _describe -t commands 'rsp help pause commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__play_commands] )) || +_rsp__subcmd__help__subcmd__play_commands() { + local commands; commands=() + _describe -t commands 'rsp help play commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__previous_commands] )) || +_rsp__subcmd__help__subcmd__previous_commands() { + local commands; commands=() + _describe -t commands 'rsp help previous commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__queue_commands] )) || +_rsp__subcmd__help__subcmd__queue_commands() { + local commands; commands=() + _describe -t commands 'rsp help queue commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__restart_commands] )) || +_rsp__subcmd__help__subcmd__restart_commands() { + local commands; commands=() + _describe -t commands 'rsp help restart commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__resume_commands] )) || +_rsp__subcmd__help__subcmd__resume_commands() { + local commands; commands=() + _describe -t commands 'rsp help resume commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__scan_commands] )) || +_rsp__subcmd__help__subcmd__scan_commands() { + local commands; commands=() + _describe -t commands 'rsp help scan commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__settings_commands] )) || +_rsp__subcmd__help__subcmd__settings_commands() { + local commands; commands=( +'get:Get a setting value' \ +'set:Set a setting value' \ +'list:List all settings' \ +'unset:Unset a setting' \ + ) + _describe -t commands 'rsp help settings commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__settings__subcmd__get_commands] )) || +_rsp__subcmd__help__subcmd__settings__subcmd__get_commands() { + local commands; commands=() + _describe -t commands 'rsp help settings get commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__settings__subcmd__list_commands] )) || +_rsp__subcmd__help__subcmd__settings__subcmd__list_commands() { + local commands; commands=() + _describe -t commands 'rsp help settings list commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__settings__subcmd__set_commands] )) || +_rsp__subcmd__help__subcmd__settings__subcmd__set_commands() { + local commands; commands=() + _describe -t commands 'rsp help settings set commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__settings__subcmd__unset_commands] )) || +_rsp__subcmd__help__subcmd__settings__subcmd__unset_commands() { + local commands; commands=() + _describe -t commands 'rsp help settings unset commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__shuffle_commands] )) || +_rsp__subcmd__help__subcmd__shuffle_commands() { + local commands; commands=() + _describe -t commands 'rsp help shuffle commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__start_commands] )) || +_rsp__subcmd__help__subcmd__start_commands() { + local commands; commands=() + _describe -t commands 'rsp help start commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__status_commands] )) || +_rsp__subcmd__help__subcmd__status_commands() { + local commands; commands=() + _describe -t commands 'rsp help status commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__stop_commands] )) || +_rsp__subcmd__help__subcmd__stop_commands() { + local commands; commands=() + _describe -t commands 'rsp help stop commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__stop-playback_commands] )) || +_rsp__subcmd__help__subcmd__stop-playback_commands() { + local commands; commands=() + _describe -t commands 'rsp help stop-playback commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__toggle_commands] )) || +_rsp__subcmd__help__subcmd__toggle_commands() { + local commands; commands=() + _describe -t commands 'rsp help toggle commands' commands "$@" +} +(( $+functions[_rsp__subcmd__help__subcmd__volume_commands] )) || +_rsp__subcmd__help__subcmd__volume_commands() { + local commands; commands=() + _describe -t commands 'rsp help volume commands' commands "$@" +} +(( $+functions[_rsp__subcmd__next_commands] )) || +_rsp__subcmd__next_commands() { + local commands; commands=() + _describe -t commands 'rsp next commands' commands "$@" +} +(( $+functions[_rsp__subcmd__pause_commands] )) || +_rsp__subcmd__pause_commands() { + local commands; commands=() + _describe -t commands 'rsp pause commands' commands "$@" +} +(( $+functions[_rsp__subcmd__play_commands] )) || +_rsp__subcmd__play_commands() { + local commands; commands=() + _describe -t commands 'rsp play commands' commands "$@" +} +(( $+functions[_rsp__subcmd__previous_commands] )) || +_rsp__subcmd__previous_commands() { + local commands; commands=() + _describe -t commands 'rsp previous commands' commands "$@" +} +(( $+functions[_rsp__subcmd__queue_commands] )) || +_rsp__subcmd__queue_commands() { + local commands; commands=() + _describe -t commands 'rsp queue commands' commands "$@" +} +(( $+functions[_rsp__subcmd__restart_commands] )) || +_rsp__subcmd__restart_commands() { + local commands; commands=() + _describe -t commands 'rsp restart commands' commands "$@" +} +(( $+functions[_rsp__subcmd__resume_commands] )) || +_rsp__subcmd__resume_commands() { + local commands; commands=() + _describe -t commands 'rsp resume commands' commands "$@" +} +(( $+functions[_rsp__subcmd__scan_commands] )) || +_rsp__subcmd__scan_commands() { + local commands; commands=() + _describe -t commands 'rsp scan commands' commands "$@" +} +(( $+functions[_rsp__subcmd__settings_commands] )) || +_rsp__subcmd__settings_commands() { + local commands; commands=( +'get:Get a setting value' \ +'set:Set a setting value' \ +'list:List all settings' \ +'unset:Unset a setting' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rsp settings commands' commands "$@" +} +(( $+functions[_rsp__subcmd__settings__subcmd__get_commands] )) || +_rsp__subcmd__settings__subcmd__get_commands() { + local commands; commands=() + _describe -t commands 'rsp settings get commands' commands "$@" +} +(( $+functions[_rsp__subcmd__settings__subcmd__help_commands] )) || +_rsp__subcmd__settings__subcmd__help_commands() { + local commands; commands=( +'get:Get a setting value' \ +'set:Set a setting value' \ +'list:List all settings' \ +'unset:Unset a setting' \ +'help:Print this message or the help of the given subcommand(s)' \ + ) + _describe -t commands 'rsp settings help commands' commands "$@" +} +(( $+functions[_rsp__subcmd__settings__subcmd__help__subcmd__get_commands] )) || +_rsp__subcmd__settings__subcmd__help__subcmd__get_commands() { + local commands; commands=() + _describe -t commands 'rsp settings help get commands' commands "$@" +} +(( $+functions[_rsp__subcmd__settings__subcmd__help__subcmd__help_commands] )) || +_rsp__subcmd__settings__subcmd__help__subcmd__help_commands() { + local commands; commands=() + _describe -t commands 'rsp settings help help commands' commands "$@" +} +(( $+functions[_rsp__subcmd__settings__subcmd__help__subcmd__list_commands] )) || +_rsp__subcmd__settings__subcmd__help__subcmd__list_commands() { + local commands; commands=() + _describe -t commands 'rsp settings help list commands' commands "$@" +} +(( $+functions[_rsp__subcmd__settings__subcmd__help__subcmd__set_commands] )) || +_rsp__subcmd__settings__subcmd__help__subcmd__set_commands() { + local commands; commands=() + _describe -t commands 'rsp settings help set commands' commands "$@" +} +(( $+functions[_rsp__subcmd__settings__subcmd__help__subcmd__unset_commands] )) || +_rsp__subcmd__settings__subcmd__help__subcmd__unset_commands() { + local commands; commands=() + _describe -t commands 'rsp settings help unset commands' commands "$@" +} +(( $+functions[_rsp__subcmd__settings__subcmd__list_commands] )) || +_rsp__subcmd__settings__subcmd__list_commands() { + local commands; commands=() + _describe -t commands 'rsp settings list commands' commands "$@" +} +(( $+functions[_rsp__subcmd__settings__subcmd__set_commands] )) || +_rsp__subcmd__settings__subcmd__set_commands() { + local commands; commands=() + _describe -t commands 'rsp settings set commands' commands "$@" +} +(( $+functions[_rsp__subcmd__settings__subcmd__unset_commands] )) || +_rsp__subcmd__settings__subcmd__unset_commands() { + local commands; commands=() + _describe -t commands 'rsp settings unset commands' commands "$@" +} +(( $+functions[_rsp__subcmd__shuffle_commands] )) || +_rsp__subcmd__shuffle_commands() { + local commands; commands=() + _describe -t commands 'rsp shuffle commands' commands "$@" +} +(( $+functions[_rsp__subcmd__start_commands] )) || +_rsp__subcmd__start_commands() { + local commands; commands=() + _describe -t commands 'rsp start commands' commands "$@" +} +(( $+functions[_rsp__subcmd__status_commands] )) || +_rsp__subcmd__status_commands() { + local commands; commands=() + _describe -t commands 'rsp status commands' commands "$@" +} +(( $+functions[_rsp__subcmd__stop_commands] )) || +_rsp__subcmd__stop_commands() { + local commands; commands=() + _describe -t commands 'rsp stop commands' commands "$@" +} +(( $+functions[_rsp__subcmd__stop-playback_commands] )) || +_rsp__subcmd__stop-playback_commands() { + local commands; commands=() + _describe -t commands 'rsp stop-playback commands' commands "$@" +} +(( $+functions[_rsp__subcmd__toggle_commands] )) || +_rsp__subcmd__toggle_commands() { + local commands; commands=() + _describe -t commands 'rsp toggle commands' commands "$@" +} +(( $+functions[_rsp__subcmd__volume_commands] )) || +_rsp__subcmd__volume_commands() { + local commands; commands=() + _describe -t commands 'rsp volume commands' commands "$@" +} + +if [ "$funcstack[1]" = "_rsp" ]; then + _rsp "$@" +else + compdef _rsp rsp +fi + +_rsp_play_artist_album_completion() { + local -a artists + artists=("$(rsp play --list 2>/dev/null)") + _describe -t artist-album 'artist/album' artists +} 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..." sudo cp target/release/rsp /usr/bin/rsp sudo chmod +x /usr/bin/rsp -echo "Installing shell completions for current shell..." -SHELL_NAME=$(basename "$SHELL") - -case "$SHELL_NAME" in - zsh) - sudo mkdir -p /usr/share/zsh/site-functions - sudo cp completions/rsp.zsh /usr/share/zsh/site-functions/_rsp - sudo chmod +x /usr/share/zsh/site-functions/_rsp - echo "Installed completions for $SHELL_NAME" - ;; - bash) - sudo mkdir -p /usr/share/bash-completion/completions - sudo cp completions/rsp.bash /usr/share/bash-completion/completions/rsp - sudo chmod +x /usr/share/bash-completion/completions/rsp - echo "Installed completions for $SHELL_NAME" - ;; - fish) - sudo mkdir -p /usr/share/fish/vendor_completions.d - sudo cp completions/rsp.fish /usr/share/fish/vendor_completions.d/rsp.fish - sudo chmod +x /usr/share/fish/vendor_completions.d/rsp.fish - echo "Installed completions for $SHELL_NAME" - ;; - *) - echo "Unknown shell: $SHELL_NAME, installing no completions..." - ;; -esac - +echo "" echo "Installing systemd service..." mkdir -p ~/.config/systemd/user cp 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 { } fn insert_after_current(&mut self, path: PathBuf) { - let insert_idx = self.position + 1; - self.tracks.insert(insert_idx, Track::from_path(path)); + if self.tracks.is_empty() { + self.tracks.push(Track::from_path(path)); + } else { + let insert_idx = self.position + 1; + self.tracks.insert(insert_idx, Track::from_path(path)); + } self.update_shuffle_indices(); } @@ -165,11 +169,15 @@ impl Queue { } fn update_shuffle_indices(&mut self) { - self.shuffled_indices = (0..self.tracks.len()).collect(); + let len = self.tracks.len(); + self.shuffled_indices = (0..len).collect(); if let ShuffleMode::All = self.shuffle { use rand::seq::SliceRandom; let mut rng = rand::rng(); - self.shuffled_indices.shuffle(&mut rng); + let pos = self.position.min(len.saturating_sub(1)); + if pos + 1 < len { + self.shuffled_indices[pos + 1..].shuffle(&mut rng); + } } } @@ -583,10 +591,13 @@ fn process_command( let path = std::path::PathBuf::from(path_str.clone()); if path.is_file() { if let Ok(mut q) = queue.lock() { + let was_empty = q.tracks.is_empty(); match position { "now" => { q.insert_after_current(path.clone()); - q.position += 1; + if !was_empty { + q.position += 1; + } if let Some(track) = q.track_at(q.position) { audio.play(track.path.clone()); } @@ -609,12 +620,15 @@ fn process_command( match find_audio_in_dir(&path) { Some(files) if !files.is_empty() => { if let Ok(mut q) = queue.lock() { + let was_empty = q.tracks.is_empty(); match position { "now" => { for file in &files { q.insert_after_current(file.clone()); } - q.position += 1; + if !was_empty { + q.position += 1; + } if let Some(track) = q.track_at(q.position) { audio.play(track.path.clone()); } @@ -638,8 +652,10 @@ fn process_command( for file in &files { q.add_track(file.clone()); } - if let Some(track) = q.current() { - audio.play(track.path.clone()); + if !audio.is_playing() { + if let Some(track) = files.first() { + audio.play(track.clone()); + } } format!("Queued {} tracks from: {}\n", files.len(), path_str) } -- cgit v1.2.3