File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -123,6 +123,39 @@ describe("@ popup narrows as you type", () => {
123123 } )
124124 } )
125125
126+ test ( "quitting mid-lookup does not write into the disposed shell" , async ( ) => {
127+ await withTestRenderer (
128+ async ( h ) => {
129+ const shell = createAppShell ( h . renderer , {
130+ terminal : { columns : 80 , rows : 24 } ,
131+ wireKeys : false ,
132+ run : "idle" ,
133+ } )
134+ let resolveLookup : ( entries : readonly string [ ] ) => void = ( ) => { }
135+ setMentionSuggestionSource (
136+ shell ,
137+ ( ) =>
138+ new Promise < readonly string [ ] > ( ( resolve ) => {
139+ resolveLookup = resolve
140+ } ) ,
141+ )
142+
143+ shell . prompt . value = "read @"
144+ shell . prompt . cursorOffset = shell . prompt . value . length
145+ const pending = openAtMentionSuggestions ( shell )
146+
147+ // The operator quits before the filesystem lookup answers.
148+ shell . dispose ( )
149+ resolveLookup ( [ "AGENTS.md" , "README.md" ] )
150+
151+ await expect ( pending ) . resolves . toBe ( false )
152+ expect ( shell . overlayKind ) . toBeNull ( )
153+ expect ( isMentionPopupOpen ( shell ) ) . toBe ( false )
154+ } ,
155+ { width : 80 , height : 24 } ,
156+ )
157+ } )
158+
126159 test ( "no match closes the popup and leaves the typed text" , async ( ) => {
127160 await withShell ( async ( shell ) => {
128161 await openAt ( shell , "@" )
Original file line number Diff line number Diff line change @@ -3931,11 +3931,15 @@ export async function openAtMentionSuggestions(shell: AppShell): Promise<boolean
39313931 await source ( token . dir ) ,
39323932 token . fragment ,
39333933 )
3934+ // Quitting mid-lookup tears down the renderer/TextBuffer this function
3935+ // writes into below; a resolved-but-stale lookup must not touch them.
3936+ if ( shell . disposed ) return false
39343937 // The source caps how many entries it returns per directory, so a large
39353938 // directory can cap out before the interior match appears. Asking it to do
39363939 // its own prefix filter puts that cap after the narrowing instead of before.
39373940 if ( suggestions . length === 0 && token . fragment . length > 0 ) {
39383941 suggestions = await source ( at . prefix )
3942+ if ( shell . disposed ) return false
39393943 }
39403944 if ( mentionGenerations . get ( shell ) !== generation ) return false
39413945
You can’t perform that action at this time.
0 commit comments