v0.8.3: tab-completion trailing-space no longer breaks command dispatch

The slash-command completer (__larry_complete_slash) intentionally appends
a trailing space after a unique match for arg-command ergonomics, but the
main_loop dispatcher matched exact `case` globs — so a completed `/quit `
missed the `/quit)` arm and fell through to "unknown command". Latent since
v0.6.6 (tab completion). Fixed by rtrimming the dispatch key once at the
`case "$input"` boundary, which also transitively protects the sub-command
dispatchers (/origin, /phi-auto, /phi-sidecar, /mouse) that consume the
same $input via _slash_args. Interior `/load FILE` spacing is preserved.
Added a shared rtrim() helper to lib/cygwin-safe.sh next to strip_cr.

Co-Authored-By: Clover (Claude Opus 4.7) <noreply@anthropic.com>
This commit is contained in:
Bryan Johnson 2026-05-27 20:11:19 -07:00
parent 60b8f0e1c8
commit d4c382dc6d
4 changed files with 50 additions and 2 deletions

View File

@ -4,6 +4,19 @@ All notable changes to `cloverleaf-larry` / `larry-anywhere` are recorded here.
Versioning is loose-semver; bumps trigger the in-process self-update on every
running client via `LARRY_BASE_URL` + `MANIFEST`.
## v0.8.3 — 2026-05-27
- **Tab-completion trailing space no longer breaks command dispatch.** The
slash-command completer intentionally appends a trailing space after a
unique match (so arg-taking commands feel snappy), but the main_loop
dispatcher matched exact `case` globs, so `/quit ` (completed) missed the
`/quit)` arm and fell through to "unknown command". Latent since v0.6.6
when tab completion shipped. Fixed by rtrimming the dispatch key once at
the `case "$input"` boundary (`larry.sh`), which tolerates the completer's
space, a user-typed trailing space, and any CR remnant while preserving
interior `/load FILE` argument spacing. Added a shared `rtrim()` helper to
`lib/cygwin-safe.sh` (and the inline fallback) next to `strip_cr`.
## v0.8.2 — 2026-05-27
Microsoft Presidio sidecar for free-text NER. Closes V1 from Vera's audit —

View File

@ -1 +1 @@
0.8.2
0.8.3

View File

@ -57,7 +57,7 @@ set -o pipefail
# ─────────────────────────────────────────────────────────────────────────────
# Config
# ─────────────────────────────────────────────────────────────────────────────
LARRY_VERSION="0.8.2"
LARRY_VERSION="0.8.3"
LARRY_HOME="${LARRY_HOME:-$HOME/.larry}"
# ─────────────────────────────────────────────────────────────────────────────
@ -850,6 +850,7 @@ if [ -n "$LARRY_LIB_DIR" ] && [ -r "$LARRY_LIB_DIR/cygwin-safe.sh" ]; then
else
coerce_int() { local r="${1:-}" d="${2:-0}" c; c=$(printf '%s' "$r" | tr -cd '0-9'); printf '%s' "${c:-$d}"; }
strip_cr() { local v="${1:-}"; printf '%s' "${v//$'\r'/}"; }
rtrim() { local v="${1:-}"; printf '%s' "${v%"${v##*[![:space:]]}"}"; }
fi
# v0.7.0: HL7 v2.x schema for inline tab completion + /hl7 / /hl7-fields slash
@ -4742,6 +4743,17 @@ main_loop() {
local input="$LARRY_INPUT"
[ -z "$input" ] && continue
# v0.8.3 — rtrim the dispatch key before the exact-match `case` below.
# Tab completion (__larry_complete_slash) intentionally appends a trailing
# space after a unique match, but bash `case` globs are literal: "/quit "
# never matches the "/quit)" arm and falls through to "unknown command".
# Stripping trailing whitespace here tolerates the completer's space, a
# user-typed trailing space, and any CR remnant in one defensive line.
# Trailing-only: interior "/load FILE" spacing is preserved, so argument
# parsing (${input#/load } etc.) is unaffected. Pure parameter expansion,
# no subshell. See lib/cygwin-safe.sh rtrim() for the shared helper.
input="${input%"${input##*[![:space:]]}"}"
case "$input" in
/quit|/exit|/q) larry_say "bye."; break ;;
/help) print_help; continue ;;

View File

@ -66,6 +66,29 @@ strip_cr() {
printf '%s' "${v//$'\r'/}"
}
# rtrim VAL — return VAL with all TRAILING whitespace removed (spaces, tabs,
# and CR — anything in [:space:]). Leading and interior whitespace untouched.
#
# Use immediately before a `case "$X" in ...) esac` pattern dispatcher whose
# arms are exact-string globs (e.g. /quit) /help)). Bash case patterns are
# literal globs, so a trailing space makes "/quit " miss "/quit)" and fall
# through to the catch-all. This bites tab completion: __larry_complete_slash
# intentionally appends a friendly trailing space after a unique match (so
# arg-taking commands feel snappy), which the exact-match dispatcher then
# rejects for no-arg commands. rtrim at the dispatch boundary tolerates the
# completer's space, a user-typed trailing space, and any CR remnant in one
# defensive line — without removing the completer's UX nicety.
#
# Trailing-only by design: interior spaces separate a command from its
# argument (/load FILE), so we must never collapse those. The expansion
# below strips the run of trailing whitespace chars only.
#
# Pure bash parameter expansion — no subshell, no external tools.
rtrim() {
local v="${1:-}"
printf '%s' "${v%"${v##*[![:space:]]}"}"
}
# read_clean VAR [PROMPT] — like `read -r VAR`, but every captured byte that
# is \r gets stripped before the assignment.
#