diff --git a/.changeset/fix-select-prompt-clear.md b/.changeset/fix-select-prompt-clear.md
new file mode 100644
index 00000000000..dcc347f97d9
--- /dev/null
+++ b/.changeset/fix-select-prompt-clear.md
@@ -0,0 +1,7 @@
+---
+"@effect/cli": patch
+---
+
+Fix `Prompt.select` rendering issue when choice descriptions cause terminal line wrapping.
+
+The `handleClear` function now correctly calculates the number of terminal rows to erase by accounting for the actual rendered content length of each choice, including descriptions that are only shown for the selected item.
diff --git a/packages/cli/src/internal/prompt/select.ts b/packages/cli/src/internal/prompt/select.ts
index beb4e3942dc..bae66d32e58 100644
--- a/packages/cli/src/internal/prompt/select.ts
+++ b/packages/cli/src/internal/prompt/select.ts
@@ -175,12 +175,25 @@ function handleRender(options: SelectOptions) {
}
}
-export function handleClear(options: SelectOptions) {
+export function handleClear(options: SelectOptions, state: State) {
return Effect.gen(function*() {
const terminal = yield* Terminal.Terminal
const columns = yield* terminal.columns
const clearPrompt = Doc.cat(Doc.eraseLine, Doc.cursorLeft)
- const text = "\n".repeat(Math.min(options.choices.length, options.maxPerPage)) + options.message
+ // Calculate actual content length per displayed choice to account for line wrapping
+ const toDisplay = entriesToDisplay(state, options.choices.length, options.maxPerPage)
+ const choiceLines: Array = []
+ for (let i = toDisplay.startIndex; i < toDisplay.endIndex; i++) {
+ const choice = options.choices[i]
+ const isSelected = state === i
+ // Approximate rendered line: prefix (2 chars) + title + description (only shown when selected)
+ let line = " " + choice.title
+ if (isSelected && choice.description) {
+ line += " - " + choice.description
+ }
+ choiceLines.push(line)
+ }
+ const text = choiceLines.join("\n") + "\n" + options.message
const clearOutput = InternalAnsiUtils.eraseText(text, columns)
return clearOutput.pipe(
Doc.cat(clearPrompt),
@@ -243,6 +256,6 @@ export const select = (options: Prompt.Prompt.SelectOptions): Prompt
return InternalPrompt.custom(initialIndex, {
render: handleRender(opts),
process: handleProcess(opts),
- clear: () => handleClear(opts)
+ clear: (state) => handleClear(opts, state)
})
}