@@ -26,10 +26,17 @@ const writeOutput = (data: string) => {
2626 process . stdout . write ( data ) ;
2727} ;
2828
29+ const _suggestionLayout = ( term : ISTerm ) : { direction : "above" | "below" ; lines : number } => {
30+ const maxLines = getMaxLines ( ) ;
31+ const { remainingLines, cursorY } = term . getCursorState ( ) ;
32+ const direction = remainingLines >= maxLines ? "below" : cursorY >= maxLines ? "above" : remainingLines >= cursorY ? "below" : "above" ;
33+ const lines = direction === "above" ? Math . min ( maxLines , cursorY ) : Math . min ( maxLines , remainingLines ) ;
34+ return { direction, lines } ;
35+ } ;
36+
2937const _render = ( term : ISTerm , suggestionManager : SuggestionManager , data : string , handlingBackspace : boolean , handlingSuggestion : boolean ) : boolean => {
30- const direction = _direction ( term ) ;
38+ const { direction, lines } = _suggestionLayout ( term ) ;
3139 const { hidden : cursorHidden , shift : cursorShift } = term . getCursorState ( ) ;
32- const linesOfInterest = getMaxLines ( ) ;
3340
3441 const suggestion = suggestionManager . render ( direction ) ;
3542 const hasSuggestion = suggestion . length != 0 ;
@@ -43,12 +50,12 @@ const _render = (term: ISTerm, suggestionManager: SuggestionManager, data: strin
4350 const commandState = term . getCommandState ( ) ;
4451 const cursorTerminated = handlingBackspace ? true : commandState . cursorTerminated ?? false ;
4552 const showSuggestions = hasSuggestion && cursorTerminated && ! commandState . hasOutput && ! cursorShift && ! ! commandState . commandText ;
46- const patch = term . getPatch ( linesOfInterest , showSuggestions ? suggestion : [ ] , direction ) ;
53+ const patch = term . getPatch ( lines , showSuggestions ? suggestion : [ ] , direction ) ;
4754
4855 const ansiCursorShow = cursorHidden ? "" : ansi . cursorShow ;
4956 if ( direction == "above" ) {
5057 writeOutput (
51- data + ansi . cursorHide + ansi . cursorSavePosition + ansi . cursorPrevLine . repeat ( linesOfInterest ) + patch + ansi . cursorRestorePosition + ansiCursorShow ,
58+ data + ansi . cursorHide + ansi . cursorSavePosition + ansi . cursorPrevLine . repeat ( lines ) + patch + ansi . cursorRestorePosition + ansiCursorShow ,
5259 ) ;
5360 } else {
5461 writeOutput ( ansi . cursorHide + ansi . cursorSavePosition + ansi . cursorNextLine + patch + ansi . cursorRestorePosition + ansiCursorShow + data ) ;
@@ -57,28 +64,26 @@ const _render = (term: ISTerm, suggestionManager: SuggestionManager, data: strin
5764} ;
5865
5966const _clear = ( term : ISTerm ) : void => {
60- const clearDirection = _direction ( term ) == "above" ? "below" : "above" ; // invert direction to clear what was previously rendered
61- const { hidden : cursorHidden } = term . getCursorState ( ) ;
62- const patch = term . getPatch ( getMaxLines ( ) , [ ] , clearDirection ) ;
67+ const { direction } = _suggestionLayout ( term ) ;
68+ const clearDirection = direction == "above" ? "below" : "above" ; // invert direction to clear what was previously rendered
69+ const { hidden : cursorHidden , cursorY, remainingLines } = term . getCursorState ( ) ;
70+ const lines = clearDirection === "above" ? Math . min ( getMaxLines ( ) , cursorY ) : Math . min ( getMaxLines ( ) , remainingLines ) ;
71+ const patch = term . getPatch ( lines , [ ] , clearDirection ) ;
6372
6473 const ansiCursorShow = cursorHidden ? "" : ansi . cursorShow ;
6574 if ( clearDirection == "above" ) {
66- writeOutput ( ansi . cursorHide + ansi . cursorSavePosition + ansi . cursorPrevLine . repeat ( getMaxLines ( ) ) + patch + ansi . cursorRestorePosition + ansiCursorShow ) ;
75+ writeOutput ( ansi . cursorHide + ansi . cursorSavePosition + ansi . cursorPrevLine . repeat ( lines ) + patch + ansi . cursorRestorePosition + ansiCursorShow ) ;
6776 } else {
6877 writeOutput ( ansi . cursorHide + ansi . cursorSavePosition + ansi . cursorNextLine + patch + ansi . cursorRestorePosition + ansiCursorShow ) ;
6978 }
7079} ;
7180
72- const _direction = ( term : ISTerm ) : "above" | "below" => {
73- return term . getCursorState ( ) . remainingLines > getMaxLines ( ) ? "below" : "above" ;
74- } ;
75-
7681export const render = async ( program : Command , shell : Shell , underTest : boolean , login : boolean ) => {
7782 const [ isterm , { SuggestionManager } ] = await Promise . all ( [ import ( "../isterm/index.js" ) , import ( "./suggestionManager.js" ) ] ) ;
7883 const term = await isterm . default . spawn ( program , { shell, rows : process . stdout . rows , cols : process . stdout . columns , underTest, login } ) ;
7984 const suggestionManager = new SuggestionManager ( term , shell ) ;
8085 let hasSuggestion = false ;
81- let direction = _direction ( term ) ;
86+ let direction = _suggestionLayout ( term ) . direction ;
8287 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
8388 const stdinStartedInRawMode = process . stdin . isRaw ;
8489 if ( process . stdin . isTTY ) process . stdin . setRawMode ( true ) ;
@@ -94,7 +99,7 @@ export const render = async (program: Command, shell: Shell, underTest: boolean,
9499 term . onData ( async ( data ) => {
95100 data = data . replace ( enableWin32InputMode , "" ) ; // remove win32-input-mode enable sequence if it comes through data
96101
97- const handlingDirectionChange = direction != _direction ( term ) ;
102+ const handlingDirectionChange = direction != _suggestionLayout ( term ) . direction ;
98103 // clear the previous suggestion if the direction has changed to avoid leftover suggestions
99104 if ( handlingDirectionChange ) {
100105 _clear ( term ) ;
@@ -105,7 +110,7 @@ export const render = async (program: Command, shell: Shell, underTest: boolean,
105110 hasSuggestion = _render ( term , suggestionManager , "" , handlingBackspace , hasSuggestion ) ;
106111
107112 handlingBackspace = false ;
108- direction = _direction ( term ) ;
113+ direction = _suggestionLayout ( term ) . direction ;
109114 } ) ;
110115
111116 process . stdin . on ( "keypress" , ( ...keyPress : KeyPressEvent ) => {
0 commit comments