Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions shell/shellIntegration-rc.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ if [[ -f $USER_ZDOTDIR/.zshrc ]]; then
fi

__is_prompt_start() {
builtin printf '\e]6973;PS\a'
builtin printf '\e]6973;PS\a' > /dev/tty
}

__is_prompt_end() {
builtin printf '\e]6973;PE\a'
builtin printf '\e]6973;PE\a' > /dev/tty
}

__is_escape_value() {
Expand Down
1 change: 1 addition & 0 deletions shell/shellIntegration.fish
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ function __is_update_cwd --on-event fish_prompt; set __is_cwd (__is_escape_value

if [ "$ISTERM_TESTING" = "1" ]
function is_user_prompt; printf '> '; end
set -Ua fish_features no-query-term
end

function fish_prompt;
Expand Down
37 changes: 20 additions & 17 deletions src/ui/ui-root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,17 @@ const writeOutput = (data: string) => {
process.stdout.write(data);
};

const _suggestionLayout = (term: ISTerm): { direction: "above" | "below"; lines: number } => {
const maxLines = getMaxLines();
const { remainingLines, cursorY } = term.getCursorState();
const direction = remainingLines >= maxLines ? "below" : cursorY >= maxLines ? "above" : remainingLines >= cursorY ? "below" : "above";
const lines = direction === "above" ? Math.min(maxLines, cursorY) : Math.min(maxLines, remainingLines);
return { direction, lines };
};

const _render = (term: ISTerm, suggestionManager: SuggestionManager, data: string, handlingBackspace: boolean, handlingSuggestion: boolean): boolean => {
const direction = _direction(term);
const { direction, lines } = _suggestionLayout(term);
const { hidden: cursorHidden, shift: cursorShift } = term.getCursorState();
const linesOfInterest = getMaxLines();

const suggestion = suggestionManager.render(direction);
const hasSuggestion = suggestion.length != 0;
Expand All @@ -43,42 +50,38 @@ const _render = (term: ISTerm, suggestionManager: SuggestionManager, data: strin
const commandState = term.getCommandState();
const cursorTerminated = handlingBackspace ? true : commandState.cursorTerminated ?? false;
const showSuggestions = hasSuggestion && cursorTerminated && !commandState.hasOutput && !cursorShift && !!commandState.commandText;
const patch = term.getPatch(linesOfInterest, showSuggestions ? suggestion : [], direction);
const patch = term.getPatch(lines, showSuggestions ? suggestion : [], direction);

const ansiCursorShow = cursorHidden ? "" : ansi.cursorShow;
if (direction == "above") {
writeOutput(
data + ansi.cursorHide + ansi.cursorSavePosition + ansi.cursorPrevLine.repeat(linesOfInterest) + patch + ansi.cursorRestorePosition + ansiCursorShow,
);
writeOutput(data + ansi.cursorHide + ansi.cursorSavePosition + ansi.cursorPrevLine.repeat(lines) + patch + ansi.cursorRestorePosition + ansiCursorShow);
} else {
writeOutput(ansi.cursorHide + ansi.cursorSavePosition + ansi.cursorNextLine + patch + ansi.cursorRestorePosition + ansiCursorShow + data);
}
return showSuggestions;
};

const _clear = (term: ISTerm): void => {
const clearDirection = _direction(term) == "above" ? "below" : "above"; // invert direction to clear what was previously rendered
const { hidden: cursorHidden } = term.getCursorState();
const patch = term.getPatch(getMaxLines(), [], clearDirection);
const { direction } = _suggestionLayout(term);
const clearDirection = direction == "above" ? "below" : "above"; // invert direction to clear what was previously rendered
const { hidden: cursorHidden, cursorY, remainingLines } = term.getCursorState();
const lines = clearDirection === "above" ? Math.min(getMaxLines(), cursorY) : Math.min(getMaxLines(), remainingLines);
const patch = term.getPatch(lines, [], clearDirection);

const ansiCursorShow = cursorHidden ? "" : ansi.cursorShow;
if (clearDirection == "above") {
writeOutput(ansi.cursorHide + ansi.cursorSavePosition + ansi.cursorPrevLine.repeat(getMaxLines()) + patch + ansi.cursorRestorePosition + ansiCursorShow);
writeOutput(ansi.cursorHide + ansi.cursorSavePosition + ansi.cursorPrevLine.repeat(lines) + patch + ansi.cursorRestorePosition + ansiCursorShow);
} else {
writeOutput(ansi.cursorHide + ansi.cursorSavePosition + ansi.cursorNextLine + patch + ansi.cursorRestorePosition + ansiCursorShow);
}
};

const _direction = (term: ISTerm): "above" | "below" => {
return term.getCursorState().remainingLines > getMaxLines() ? "below" : "above";
};

export const render = async (program: Command, shell: Shell, underTest: boolean, login: boolean) => {
const [isterm, { SuggestionManager }] = await Promise.all([import("../isterm/index.js"), import("./suggestionManager.js")]);
const term = await isterm.default.spawn(program, { shell, rows: process.stdout.rows, cols: process.stdout.columns, underTest, login });
const suggestionManager = new SuggestionManager(term, shell);
let hasSuggestion = false;
let direction = _direction(term);
let direction = _suggestionLayout(term).direction;
let handlingBackspace = false; // backspace normally consistent of two data points (move back & delete), so on the first data point, we won't enforce the cursor terminated rule. this will help reduce flicker
const stdinStartedInRawMode = process.stdin.isRaw;
if (process.stdin.isTTY) process.stdin.setRawMode(true);
Expand All @@ -94,7 +97,7 @@ export const render = async (program: Command, shell: Shell, underTest: boolean,
term.onData(async (data) => {
data = data.replace(enableWin32InputMode, ""); // remove win32-input-mode enable sequence if it comes through data

const handlingDirectionChange = direction != _direction(term);
const handlingDirectionChange = direction != _suggestionLayout(term).direction;
// clear the previous suggestion if the direction has changed to avoid leftover suggestions
if (handlingDirectionChange) {
_clear(term);
Expand All @@ -105,7 +108,7 @@ export const render = async (program: Command, shell: Shell, underTest: boolean,
hasSuggestion = _render(term, suggestionManager, "", handlingBackspace, hasSuggestion);

handlingBackspace = false;
direction = _direction(term);
direction = _suggestionLayout(term).direction;
});

process.stdin.on("keypress", (...keyPress: KeyPressEvent) => {
Expand Down
Loading