@@ -5,7 +5,14 @@ import { wrapAnsi } from 'fast-wrap-ansi';
55import { cursor , erase } from 'sisteransi' ;
66import type { ClackEvents , ClackState } from '../types.js' ;
77import type { Action } from '../utils/index.js' ;
8- import { CANCEL_SYMBOL , diffLines , isActionKey , setRawMode , settings } from '../utils/index.js' ;
8+ import {
9+ CANCEL_SYMBOL ,
10+ diffLines ,
11+ getRows ,
12+ isActionKey ,
13+ setRawMode ,
14+ settings ,
15+ } from '../utils/index.js' ;
916
1017export interface PromptOptions < TValue , Self extends Prompt < TValue > > {
1118 render ( this : Omit < Self , 'prompt' > ) : string | undefined ;
@@ -274,28 +281,44 @@ export default class Prompt<TValue> {
274281 this . output . write ( cursor . hide ) ;
275282 } else {
276283 const diff = diffLines ( this . _prevFrame , frame ) ;
284+ const rows = getRows ( this . output ) ;
277285 this . restoreCursor ( ) ;
278- // If a single line has changed, only update that line
279- if ( diff && diff ?. length === 1 ) {
280- const diffLine = diff [ 0 ] ;
281- this . output . write ( cursor . move ( 0 , diffLine ) ) ;
282- this . output . write ( erase . lines ( 1 ) ) ;
283- const lines = frame . split ( '\n' ) ;
284- this . output . write ( lines [ diffLine ] ) ;
285- this . _prevFrame = frame ;
286- this . output . write ( cursor . move ( 0 , lines . length - diffLine - 1 ) ) ;
287- return ;
288- // If many lines have changed, rerender everything past the first line
289- }
290- if ( diff && diff ?. length > 1 ) {
291- const diffLine = diff [ 0 ] ;
292- this . output . write ( cursor . move ( 0 , diffLine ) ) ;
293- this . output . write ( erase . down ( ) ) ;
294- const lines = frame . split ( '\n' ) ;
295- const newLines = lines . slice ( diffLine ) ;
296- this . output . write ( newLines . join ( '\n' ) ) ;
297- this . _prevFrame = frame ;
298- return ;
286+ if ( diff ) {
287+ const diffOffsetAfter = Math . max ( 0 , diff . numLinesAfter - rows ) ;
288+ const diffOffsetBefore = Math . max ( 0 , diff . numLinesBefore - rows ) ;
289+ let diffLine = diff . lines . find ( ( line ) => line >= diffOffsetAfter ) ;
290+
291+ if ( diffLine === undefined ) {
292+ this . _prevFrame = frame ;
293+ return ;
294+ }
295+
296+ // If a single line has changed, only update that line
297+ if ( diff . lines . length === 1 ) {
298+ this . output . write ( cursor . move ( 0 , diffLine - diffOffsetBefore ) ) ;
299+ this . output . write ( erase . lines ( 1 ) ) ;
300+ const lines = frame . split ( '\n' ) ;
301+ this . output . write ( lines [ diffLine ] ) ;
302+ this . _prevFrame = frame ;
303+ this . output . write ( cursor . move ( 0 , lines . length - diffLine - 1 ) ) ;
304+ return ;
305+ // If many lines have changed, rerender everything past the first line
306+ } else if ( diff . lines . length > 1 ) {
307+ if ( diffOffsetAfter < diffOffsetBefore ) {
308+ diffLine = diffOffsetAfter ;
309+ } else {
310+ const adjustedDiffLine = diffLine - diffOffsetBefore ;
311+ if ( adjustedDiffLine > 0 ) {
312+ this . output . write ( cursor . move ( 0 , adjustedDiffLine ) ) ;
313+ }
314+ }
315+ this . output . write ( erase . down ( ) ) ;
316+ const lines = frame . split ( '\n' ) ;
317+ const newLines = lines . slice ( diffLine ) ;
318+ this . output . write ( newLines . join ( '\n' ) ) ;
319+ this . _prevFrame = frame ;
320+ return ;
321+ }
299322 }
300323
301324 this . output . write ( erase . down ( ) ) ;
0 commit comments