From 5c35624fc506425fd8d7653806f99652121bcd52 Mon Sep 17 00:00:00 2001 From: Chapman Pendery <35637443+cpendery@users.noreply.github.com> Date: Wed, 13 Dec 2023 17:52:16 -0800 Subject: [PATCH] fix: description positioning (#119) Signed-off-by: Chapman Pendery --- src/ui/suggestionManager.ts | 47 +++++++++++++++++++++++++++---------- src/ui/ui-root.ts | 20 ++++++++-------- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/ui/suggestionManager.ts b/src/ui/suggestionManager.ts index 7cb43db..8c0b8f9 100644 --- a/src/ui/suggestionManager.ts +++ b/src/ui/suggestionManager.ts @@ -18,7 +18,7 @@ const activeSuggestionBackgroundColor = "#7D56F4"; export const MAX_LINES = borderWidth + Math.max(maxSuggestions, descriptionHeight); type SuggestionsSequence = { data: string; - columns: number; + rows: number; }; export class SuggestionManager { @@ -58,6 +58,11 @@ export class SuggestionManager { return renderBox(truncateMultilineText(description, descriptionWidth - borderWidth, descriptionHeight), descriptionWidth, x); } + private _descriptionRows(description: string | undefined) { + if (!description) return 0; + return truncateMultilineText(description, descriptionWidth - borderWidth, descriptionHeight).length; + } + private _renderSuggestions(suggestions: Suggestion[], activeSuggestionIdx: number, x: number) { return renderBox( suggestions.map((suggestion, idx) => { @@ -70,9 +75,9 @@ export class SuggestionManager { ); } - async render(): Promise { + async render(remainingLines: number): Promise { await this._loadSuggestions(); - if (!this.#suggestBlob) return { data: "", columns: 0 }; + if (!this.#suggestBlob) return { data: "", rows: 0 }; const { suggestions, argumentDescription } = this.#suggestBlob; const page = Math.min(Math.floor(this.#activeSuggestionIdx / maxSuggestions) + 1, Math.floor(suggestions.length / maxSuggestions) + 1); @@ -98,21 +103,37 @@ export class SuggestionManager { ansi.cursorUp(2) + ansi.cursorForward(clampedLeftPadding) + this._renderArgumentDescription(argumentDescription, clampedLeftPadding), - columns: 3, + rows: 3, }; } - return { data: "", columns: 0 }; + return { data: "", rows: 0 }; } - const columnsUsed = pagedSuggestions.length + borderWidth; - const ui = swapDescription - ? this._renderDescription(activeDescription, clampedLeftPadding) + - this._renderSuggestions(pagedSuggestions, activePagedSuggestionIndex, clampedLeftPadding + descriptionWidth) - : this._renderSuggestions(pagedSuggestions, activePagedSuggestionIndex, clampedLeftPadding) + - this._renderDescription(activeDescription, clampedLeftPadding + suggestionWidth); + const suggestionRowsUsed = pagedSuggestions.length + borderWidth; + let descriptionRowsUsed = this._descriptionRows(activeDescription) + borderWidth; + let rows = Math.max(descriptionRowsUsed, suggestionRowsUsed); + if (rows <= remainingLines) { + descriptionRowsUsed = suggestionRowsUsed; + rows = suggestionRowsUsed; + } + + const descriptionUI = + ansi.cursorUp(descriptionRowsUsed - 1) + + (swapDescription + ? this._renderDescription(activeDescription, clampedLeftPadding) + : this._renderDescription(activeDescription, clampedLeftPadding + suggestionWidth)) + + ansi.cursorDown(descriptionRowsUsed - 1); + const suggestionUI = + ansi.cursorUp(suggestionRowsUsed - 1) + + (swapDescription + ? this._renderSuggestions(pagedSuggestions, activePagedSuggestionIndex, clampedLeftPadding + descriptionWidth) + : this._renderSuggestions(pagedSuggestions, activePagedSuggestionIndex, clampedLeftPadding)) + + ansi.cursorDown(suggestionRowsUsed - 1); + + const ui = swapDescription ? descriptionUI + suggestionUI : suggestionUI + descriptionUI; return { - data: ansi.cursorHide + ansi.cursorUp(columnsUsed - 1) + ansi.cursorForward(clampedLeftPadding) + ui + ansi.cursorShow, - columns: columnsUsed, + data: ansi.cursorHide + ansi.cursorForward(clampedLeftPadding) + ui + ansi.cursorShow, + rows, }; } diff --git a/src/ui/ui-root.ts b/src/ui/ui-root.ts index ad6fea1..8fa5fa3 100644 --- a/src/ui/ui-root.ts +++ b/src/ui/ui-root.ts @@ -13,7 +13,7 @@ export const render = async (shell: Shell) => { const term = await isterm.spawn({ shell, rows: process.stdout.rows, cols: process.stdout.columns }); const suggestionManager = new SuggestionManager(term); let hasActiveSuggestions = false; - let previousSuggestionsColumns = 0; + let previousSuggestionsRows = 0; process.stdin.setRawMode(true); const writeOutput = (data: string) => { @@ -26,7 +26,7 @@ export const render = async (shell: Shell) => { term.onData((data) => { const commandState = term.getCommandState(); if ((commandState.hasOutput || hasActiveSuggestions) && !commandState.persistentOutput) { - if (term.getCursorState().remainingLines < previousSuggestionsColumns) { + if (term.getCursorState().remainingLines < previousSuggestionsRows) { writeOutput( ansi.cursorHide + ansi.cursorSavePosition + @@ -44,12 +44,12 @@ export const render = async (shell: Shell) => { } setImmediate(async () => { - const suggestion = await suggestionManager.render(); + const suggestion = await suggestionManager.render(term.getCursorState().remainingLines); const commandState = term.getCommandState(); if (suggestion.data != "" && commandState.cursorTerminated && !commandState.hasOutput) { if (hasActiveSuggestions) { - if (term.getCursorState().remainingLines < suggestion.columns) { + if (term.getCursorState().remainingLines < suggestion.rows) { writeOutput( ansi.cursorHide + ansi.cursorSavePosition + @@ -63,7 +63,7 @@ export const render = async (shell: Shell) => { ansi.cursorShow, ); } else { - const offset = MAX_LINES - suggestion.columns; + const offset = MAX_LINES - suggestion.rows; writeOutput( ansi.cursorHide + ansi.cursorSavePosition + @@ -75,13 +75,13 @@ export const render = async (shell: Shell) => { ); } } else { - if (term.getCursorState().remainingLines < suggestion.columns) { + if (term.getCursorState().remainingLines < suggestion.rows) { writeOutput(ansi.cursorHide + ansi.cursorSavePosition + ansi.cursorUp() + suggestion.data + ansi.cursorRestorePosition + ansi.cursorShow); } else { writeOutput( ansi.cursorHide + ansi.cursorSavePosition + - ansi.cursorNextLine.repeat(suggestion.columns) + + ansi.cursorNextLine.repeat(suggestion.rows) + suggestion.data + ansi.cursorRestorePosition + ansi.cursorShow, @@ -91,7 +91,7 @@ export const render = async (shell: Shell) => { hasActiveSuggestions = true; } else { if (hasActiveSuggestions) { - if (term.getCursorState().remainingLines < previousSuggestionsColumns) { + if (term.getCursorState().remainingLines < previousSuggestionsRows) { writeOutput( ansi.cursorHide + ansi.cursorSavePosition + @@ -106,12 +106,12 @@ export const render = async (shell: Shell) => { } hasActiveSuggestions = false; } - previousSuggestionsColumns = suggestion.columns; + previousSuggestionsRows = suggestion.rows; }); }); process.stdin.on("data", (d: Buffer) => { const suggestionResult = suggestionManager.update(d); - if (previousSuggestionsColumns > 0 && suggestionResult == "handled") { + if (previousSuggestionsRows > 0 && suggestionResult == "handled") { term.noop(); } else if (suggestionResult != "fully-handled") { term.write(inputModifier(d));