diff --git a/README.md b/README.md index a904c2d..71e4731 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,7 @@ Behavior details: - free-form answer editors support pi-style `@` file path autocomplete for quickly mentioning project files - `Esc` closes the editor and returns to navigation mode - `Ctrl+C` dismisses the entire ask flow immediately, even from note/free-form editing, without saving the current draft +- use `n` for the active option note and `Shift+N` for the current question note - `Space` toggles the active option on single-select questions too, but does not auto-advance ## Local development diff --git a/docs/contract.md b/docs/contract.md index bfc64ae..2c44d1d 100644 --- a/docs/contract.md +++ b/docs/contract.md @@ -80,8 +80,8 @@ This document defines the stable external behavior. It does not explain internal - single-select, multi-select, and preview questions - inline free-form answers for non-preview questions - pi-style `@` file path autocomplete inside free-form answer and note editors -- question notes via `Ctrl+N` -- option notes via `N` +- question notes via `Shift+N` +- option notes via `n` - number-key quick selection - submit/cancel review tab - transcript-friendly call and result rendering @@ -97,8 +97,8 @@ Main flow: - `Ctrl+C`: dismiss the entire flow immediately, even while editing a note or free-form answer - `1..9`: select or toggle the matching option - `Space`: toggle the active option -- `N`: edit the active option note -- `Ctrl+N`: edit the current question note +- `n`: edit the active option note +- `Shift+N`: edit the current question note Editing flow: diff --git a/src/ui/constants.ts b/src/ui/constants.ts index 6525243..ab12cc6 100644 --- a/src/ui/constants.ts +++ b/src/ui/constants.ts @@ -12,17 +12,17 @@ export const UI_DIMENSIONS = { } as const; export const UI_TEXT = { - questionNoteTitle: "Question note", - reviewTitle: "Review your answers", - readyToSubmit: "Ready to submit your answers?", - unanswered: "→ (unanswered)", - footerInput: " Enter submit · Esc save and close", - footerNote: " Enter save · Esc save and close", + questionNoteTitle: "Note", + reviewTitle: "Review answers", + readyToSubmit: "Submit answers?", + unanswered: "→ unanswered", + footerInput: " Enter submit · Esc close", + footerNote: " Enter save · Esc close", footerSubmit: " ↑↓ select · Enter confirm · Esc cancel", footerMulti: - " ⇆ tab · ↑↓ select · Space toggle · Enter continue · N option note · Ctrl+N question note · Esc dismiss · 1-9 quick toggle", + " ⇆ tab · ↑↓ select · Space toggle · Enter continue · N/Shift+N note · Esc dismiss", footerDefault: - " ⇆ tab · ↑↓ select · Enter confirm · N option note · Ctrl+N question note · Esc dismiss", - editorPlaceholderInput: "Type your answer...", - editorPlaceholderNote: "Add a note...", + " ⇆ tab · ↑↓ select · Enter confirm · N/Shift+N note · Esc dismiss", + editorPlaceholderInput: "Type answer...", + editorPlaceholderNote: "Add note...", } as const; diff --git a/src/ui/input.ts b/src/ui/input.ts index 7708d0b..33d65f8 100644 --- a/src/ui/input.ts +++ b/src/ui/input.ts @@ -89,11 +89,11 @@ function getNavigationInputCommand(data: string): AskInputCommand { } function isOptionNoteShortcut(data: string): boolean { - return data === "n" || data === "N"; + return data === "n"; } function isQuestionNoteShortcut(data: string): boolean { - return matchesKey(data, Key.ctrl("n")); + return data === "N"; } function parseDigit(data: string): number | null { diff --git a/tests/input.test.ts b/tests/input.test.ts index 6e40871..e29071d 100644 --- a/tests/input.test.ts +++ b/tests/input.test.ts @@ -103,3 +103,22 @@ test("ctrl+c dismisses the flow from both navigation and editing modes", () => { kind: "dismiss", }); }); + +test("note shortcuts use n for option notes and Shift+N for question notes", () => { + const navigation = createInitialState({ + questions: [ + { + id: "q1", + prompt: "Question?", + options: [{ value: "a", label: "A" }], + }, + ], + }); + + assert.deepEqual(getInputCommand(navigation, "n"), { + kind: "openOptionNote", + }); + assert.deepEqual(getInputCommand(navigation, "N"), { + kind: "openQuestionNote", + }); +}); diff --git a/tests/render-helpers.test.ts b/tests/render-helpers.test.ts index a22e82a..5048119 100644 --- a/tests/render-helpers.test.ts +++ b/tests/render-helpers.test.ts @@ -74,6 +74,6 @@ test("renderEditorBlock reapplies background after editor reset sequences", () = }); test("editing footers do not advertise tab navigation", () => { - assert.equal(renderFooterText("input"), " Enter submit · Esc save and close"); - assert.equal(renderFooterText("note"), " Enter save · Esc save and close"); + assert.equal(renderFooterText("input"), " Enter submit · Esc close"); + assert.equal(renderFooterText("note"), " Enter save · Esc close"); }); diff --git a/tests/render-question.test.ts b/tests/render-question.test.ts index be9c89e..3a21fe1 100644 --- a/tests/render-question.test.ts +++ b/tests/render-question.test.ts @@ -80,7 +80,7 @@ test("selected custom option keeps its label and renders editor below", () => { }); assert(lines.some((line) => line.includes("Type your own"))); - assert(lines.some((line) => line.includes("Type your answer..."))); + assert(lines.some((line) => line.includes("Type answer..."))); }); test("selected multiline custom option renders full editor block", () => {