diff --git a/scarf/Scarf iOS/Chat/ChatView.swift b/scarf/Scarf iOS/Chat/ChatView.swift index 5cddf27..483b1a3 100644 --- a/scarf/Scarf iOS/Chat/ChatView.swift +++ b/scarf/Scarf iOS/Chat/ChatView.swift @@ -1270,7 +1270,12 @@ private struct PermissionSheet: View { } Section("Your response") { - ForEach(permission.options, id: \.optionId) { opt in + // Visual numbering 1-9 matches the Mac sheet's + // keyboard shortcuts; on iPhone the numbers serve + // as a hierarchy hint rather than an accelerator + // (no hardware keyboard binding). Mirrors the new + // Hermes v2026.4.23 TUI pattern. + ForEach(Array(permission.options.enumerated()), id: \.element.optionId) { idx, opt in Button { Task { await onRespond(opt.optionId) @@ -1278,6 +1283,11 @@ private struct PermissionSheet: View { } } label: { HStack { + if idx < 9 { + Text("\(idx + 1).") + .font(.body.monospaced()) + .foregroundStyle(.secondary) + } Text(opt.name) Spacer() Image(systemName: "chevron.right") diff --git a/scarf/scarf/Features/Chat/Views/ChatView.swift b/scarf/scarf/Features/Chat/Views/ChatView.swift index 5011258..9d48610 100644 --- a/scarf/scarf/Features/Chat/Views/ChatView.swift +++ b/scarf/scarf/Features/Chat/Views/ChatView.swift @@ -444,21 +444,33 @@ struct PermissionApprovalView: View { .multilineTextAlignment(.center) .padding(.horizontal) + // Numbered keyboard shortcuts (1–9) on the option buttons. + // Mirrors the new TUI pattern Hermes v2026.4.23 ships — + // power users approve / deny without reaching for the + // mouse. Visible "1." prefixes act as discoverability + // hints; the actual key binding goes through + // `.keyboardShortcut`. Capped at 9 — extra options stay + // tappable but unbound (they'd need modifiers to + // disambiguate beyond 9, which isn't worth it). HStack(spacing: 12) { - ForEach(options, id: \.optionId) { option in - if option.optionId == "deny" { - Button(option.name) { - onRespond(option.optionId) - dismiss() + ForEach(Array(options.enumerated()), id: \.element.optionId) { idx, option in + let label = idx < 9 ? "\(idx + 1). \(option.name)" : option.name + Group { + if option.optionId == "deny" { + Button(label) { + onRespond(option.optionId) + dismiss() + } + .buttonStyle(.bordered) + } else { + Button(label) { + onRespond(option.optionId) + dismiss() + } + .buttonStyle(.borderedProminent) } - .buttonStyle(.bordered) - } else { - Button(option.name) { - onRespond(option.optionId) - dismiss() - } - .buttonStyle(.borderedProminent) } + .applyingNumberShortcut(index: idx) } } } @@ -484,3 +496,17 @@ struct PermissionApprovalView: View { } } } + +private extension View { + /// Bind the digit `idx + 1` (1-9) to this view as a no-modifier + /// keyboard shortcut. Indices ≥ 9 silently skip — there are only + /// nine numeric shortcut keys without modifier conflicts. + @ViewBuilder + func applyingNumberShortcut(index idx: Int) -> some View { + if idx < 9, let scalar = Unicode.Scalar(48 + idx + 1) { + self.keyboardShortcut(KeyEquivalent(Character(scalar)), modifiers: []) + } else { + self + } + } +}