* Prompt for input with a timeout. * Uses raw mode for character-by-character input handling. * * @param prompt - The prompt text to display * @param timeoutMs - Timeout in milliseconds * @param defaultValue - Value to use if timed out * @returns TimedPromptResult with value, timedOut fl
(prompt: string, timeoutMs: number, defaultValue: string)
| 155 | * @returns TimedPromptResult with value, timedOut flag, and cancelled flag |
| 156 | */ |
| 157 | async promptWithTimeout(prompt: string, timeoutMs: number, defaultValue: string): Promise<TimedPromptResult> { |
| 158 | return new Promise((resolve) => { |
| 159 | this.beforePrompt() |
| 160 | this.isPrompting = true |
| 161 | |
| 162 | // Track the original raw mode state to restore it later |
| 163 | const wasRaw = this.stdin.isRaw |
| 164 | |
| 165 | // Enable raw mode for character-by-character input if TTY |
| 166 | if (this.stdin.isTTY) { |
| 167 | this.stdin.setRawMode(true) |
| 168 | } |
| 169 | |
| 170 | this.stdin.resume() |
| 171 | |
| 172 | let inputBuffer = "" |
| 173 | let timeoutCancelled = false |
| 174 | let resolved = false |
| 175 | |
| 176 | // Set up timeout |
| 177 | const timeout = setTimeout(() => { |
| 178 | if (!resolved) { |
| 179 | resolved = true |
| 180 | cleanup() |
| 181 | this.stdout.write(`\n[Timeout - using default: ${defaultValue || "(empty)"}]\n`) |
| 182 | resolve({ value: defaultValue, timedOut: true, cancelled: false }) |
| 183 | } |
| 184 | }, timeoutMs) |
| 185 | |
| 186 | // Display prompt |
| 187 | this.stdout.write(prompt) |
| 188 | |
| 189 | // Cleanup function to restore state |
| 190 | const cleanup = () => { |
| 191 | clearTimeout(timeout) |
| 192 | this.stdin.removeListener("data", onData) |
| 193 | |
| 194 | if (this.stdin.isTTY && wasRaw !== undefined) { |
| 195 | this.stdin.setRawMode(wasRaw) |
| 196 | } |
| 197 | |
| 198 | this.stdin.pause() |
| 199 | this.isPrompting = false |
| 200 | this.afterPrompt() |
| 201 | } |
| 202 | |
| 203 | // Handle incoming data |
| 204 | const onData = (data: Buffer) => { |
| 205 | const char = data.toString() |
| 206 | |
| 207 | // Handle Ctrl+C |
| 208 | if (char === "\x03") { |
| 209 | cleanup() |
| 210 | resolved = true |
| 211 | this.stdout.write("\n[cancelled]\n") |
| 212 | resolve({ value: defaultValue, timedOut: false, cancelled: true }) |
| 213 | return |
| 214 | } |
no test coverage detected