@@ -3,7 +3,7 @@ import { createEffect, on, Component, Show, onCleanup, Switch, Match, createMemo
33import { createStore } from "solid-js/store"
44import { createFocusSignal } from "@solid-primitives/active-element"
55import { useLocal } from "@/context/local"
6- import { useFile } from "@/context/file"
6+ import { selectionFromLines , type SelectedLineRange , useFile } from "@/context/file"
77import {
88 ContentPart ,
99 DEFAULT_PROMPT ,
@@ -43,6 +43,9 @@ import {
4343 canNavigateHistoryAtCursor ,
4444 navigatePromptHistory ,
4545 prependHistoryEntry ,
46+ type PromptHistoryComment ,
47+ type PromptHistoryEntry ,
48+ type PromptHistoryStoredEntry ,
4649 promptLength ,
4750} from "./prompt-input/history"
4851import { createPromptSubmit } from "./prompt-input/submit"
@@ -170,21 +173,38 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
170173 const focus = { file : item . path , id : item . commentID }
171174 comments . setActive ( focus )
172175
176+ const queueCommentFocus = ( attempts = 6 ) => {
177+ const schedule = ( left : number ) => {
178+ requestAnimationFrame ( ( ) => {
179+ comments . setFocus ( { ...focus } )
180+ if ( left <= 0 ) return
181+ requestAnimationFrame ( ( ) => {
182+ const current = comments . focus ( )
183+ if ( ! current ) return
184+ if ( current . file !== focus . file || current . id !== focus . id ) return
185+ schedule ( left - 1 )
186+ } )
187+ } )
188+ }
189+
190+ schedule ( attempts )
191+ }
192+
173193 const wantsReview = item . commentOrigin === "review" || ( item . commentOrigin !== "file" && commentInReview ( item . path ) )
174194 if ( wantsReview ) {
175195 if ( ! view ( ) . reviewPanel . opened ( ) ) view ( ) . reviewPanel . open ( )
176196 layout . fileTree . setTab ( "changes" )
177197 tabs ( ) . setActive ( "review" )
178- requestAnimationFrame ( ( ) => comments . setFocus ( focus ) )
198+ queueCommentFocus ( )
179199 return
180200 }
181201
182202 if ( ! view ( ) . reviewPanel . opened ( ) ) view ( ) . reviewPanel . open ( )
183203 layout . fileTree . setTab ( "all" )
184204 const tab = files . tab ( item . path )
185205 tabs ( ) . open ( tab )
186- files . load ( item . path )
187- requestAnimationFrame ( ( ) => comments . setFocus ( focus ) )
206+ tabs ( ) . setActive ( tab )
207+ Promise . resolve ( files . load ( item . path ) ) . finally ( ( ) => queueCommentFocus ( ) )
188208 }
189209
190210 const recent = createMemo ( ( ) => {
@@ -219,15 +239,15 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
219239 const [ store , setStore ] = createStore < {
220240 popover : "at" | "slash" | null
221241 historyIndex : number
222- savedPrompt : Prompt | null
242+ savedPrompt : PromptHistoryEntry | null
223243 placeholder : number
224244 draggingType : "image" | "@mention" | null
225245 mode : "normal" | "shell"
226246 applyingHistory : boolean
227247 } > ( {
228248 popover : null ,
229249 historyIndex : - 1 ,
230- savedPrompt : null ,
250+ savedPrompt : null as PromptHistoryEntry | null ,
231251 placeholder : Math . floor ( Math . random ( ) * EXAMPLES . length ) ,
232252 draggingType : null ,
233253 mode : "normal" ,
@@ -256,15 +276,15 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
256276 const [ history , setHistory ] = persisted (
257277 Persist . global ( "prompt-history" , [ "prompt-history.v1" ] ) ,
258278 createStore < {
259- entries : Prompt [ ]
279+ entries : PromptHistoryStoredEntry [ ]
260280 } > ( {
261281 entries : [ ] ,
262282 } ) ,
263283 )
264284 const [ shellHistory , setShellHistory ] = persisted (
265285 Persist . global ( "prompt-history-shell" , [ "prompt-history-shell.v1" ] ) ,
266286 createStore < {
267- entries : Prompt [ ]
287+ entries : PromptHistoryStoredEntry [ ]
268288 } > ( {
269289 entries : [ ] ,
270290 } ) ,
@@ -282,9 +302,66 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
282302 } ) ,
283303 )
284304
285- const applyHistoryPrompt = ( p : Prompt , position : "start" | "end" ) => {
305+ const historyComments = ( ) => {
306+ const byID = new Map ( comments . all ( ) . map ( ( item ) => [ `${ item . file } \n${ item . id } ` , item ] as const ) )
307+ return prompt . context . items ( ) . flatMap ( ( item ) => {
308+ if ( item . type !== "file" ) return [ ]
309+ const comment = item . comment ?. trim ( )
310+ if ( ! comment ) return [ ]
311+
312+ const selection = item . commentID ? byID . get ( `${ item . path } \n${ item . commentID } ` ) ?. selection : undefined
313+ const nextSelection =
314+ selection ??
315+ ( item . selection
316+ ? ( {
317+ start : item . selection . startLine ,
318+ end : item . selection . endLine ,
319+ } satisfies SelectedLineRange )
320+ : undefined )
321+ if ( ! nextSelection ) return [ ]
322+
323+ return [
324+ {
325+ id : item . commentID ?? item . key ,
326+ path : item . path ,
327+ selection : { ...nextSelection } ,
328+ comment,
329+ time : item . commentID ? ( byID . get ( `${ item . path } \n${ item . commentID } ` ) ?. time ?? Date . now ( ) ) : Date . now ( ) ,
330+ origin : item . commentOrigin ,
331+ preview : item . preview ,
332+ } satisfies PromptHistoryComment ,
333+ ]
334+ } )
335+ }
336+
337+ const applyHistoryComments = ( items : PromptHistoryComment [ ] ) => {
338+ comments . replace (
339+ items . map ( ( item ) => ( {
340+ id : item . id ,
341+ file : item . path ,
342+ selection : { ...item . selection } ,
343+ comment : item . comment ,
344+ time : item . time ,
345+ } ) ) ,
346+ )
347+ prompt . context . replaceComments (
348+ items . map ( ( item ) => ( {
349+ type : "file" as const ,
350+ path : item . path ,
351+ selection : selectionFromLines ( item . selection ) ,
352+ comment : item . comment ,
353+ commentID : item . id ,
354+ commentOrigin : item . origin ,
355+ preview : item . preview ,
356+ } ) ) ,
357+ )
358+ }
359+
360+ const applyHistoryPrompt = ( entry : PromptHistoryEntry , position : "start" | "end" ) => {
361+ const p = entry . prompt
286362 const length = position === "start" ? 0 : promptLength ( p )
287363 setStore ( "applyingHistory" , true )
364+ applyHistoryComments ( entry . comments )
288365 prompt . set ( p , length )
289366 requestAnimationFrame ( ( ) => {
290367 editorRef . focus ( )
@@ -846,7 +923,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
846923 const addToHistory = ( prompt : Prompt , mode : "normal" | "shell" ) => {
847924 const currentHistory = mode === "shell" ? shellHistory : history
848925 const setCurrentHistory = mode === "shell" ? setShellHistory : setHistory
849- const next = prependHistoryEntry ( currentHistory . entries , prompt )
926+ const next = prependHistoryEntry ( currentHistory . entries , prompt , mode === "shell" ? [ ] : historyComments ( ) )
850927 if ( next === currentHistory . entries ) return
851928 setCurrentHistory ( "entries" , next )
852929 }
@@ -857,12 +934,13 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
857934 entries : store . mode === "shell" ? shellHistory . entries : history . entries ,
858935 historyIndex : store . historyIndex ,
859936 currentPrompt : prompt . current ( ) ,
937+ currentComments : historyComments ( ) ,
860938 savedPrompt : store . savedPrompt ,
861939 } )
862940 if ( ! result . handled ) return false
863941 setStore ( "historyIndex" , result . historyIndex )
864942 setStore ( "savedPrompt" , result . savedPrompt )
865- applyHistoryPrompt ( result . prompt , result . cursor )
943+ applyHistoryPrompt ( result . entry , result . cursor )
866944 return true
867945 }
868946
0 commit comments