fix: description positioning (#119)

Signed-off-by: Chapman Pendery <cpendery@vt.edu>
This commit is contained in:
Chapman Pendery
2023-12-13 17:52:16 -08:00
committed by GitHub
parent 481f18e86c
commit 5c35624fc5
2 changed files with 44 additions and 23 deletions
+34 -13
View File
@@ -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<SuggestionsSequence> {
async render(remainingLines: number): Promise<SuggestionsSequence> {
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,
};
}
+10 -10
View File
@@ -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));