| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | "path/filepath" |
| 6 | "strings" |
| 7 | ) |
| 8 | |
| 9 | // Content refs from a bound window never fall back to whichever source or |
| 10 | // controller now occupies the tab. Missing/released handles are stale reads. |
| 11 | func (a *App) boundNativeHistoryContent(tabID string, ref HistoryContentRef, chunkIndex int) HistoryContentChunk { |
| 12 | out := HistoryContentChunk{EntryID: ref.EntryID, Field: ref.Field, Chunk: max(chunkIndex, 0), Stale: true} |
| 13 | r, err := a.historyReader(ref.ReadHandleID) |
| 14 | if err != nil || r.tabID != tabID || r.native == nil || entryIDSession(ref.EntryID) != strings.TrimSuffix(filepath.Base(r.path), ".jsonl") { |
| 15 | return out |
| 16 | } |
| 17 | position, sub, legacyRow, ok := parseHistoryEntryID(ref.EntryID) |
| 18 | if !ok || legacyRow != -1 { |
| 19 | return out |
| 20 | } |
| 21 | pager, err := nativeNavigationPager(r) |
| 22 | if err != nil { |
| 23 | return out |
| 24 | } |
| 25 | src := historySourceFromPager(r.ctx, pager, r.path, r.native.key) |
| 26 | if ref.EntryID != fmt.Sprintf("s%s:r%d:m%d:o%d", src.sessionID, src.epoch, position, sub) { |
| 27 | return out |
| 28 | } |
| 29 | dir := filepath.Dir(r.path) |
| 30 | value, found, stale := a.historyFieldValueForSource(src, position, sub, ref, sessionDisplayResolver(dir, r.path), sessionPlannerDisplayTurns(dir, r.path), nil) |
| 31 | if stale || !found || src.readErr != nil || len(value) != ref.Size || pager.Validate() != nil || r.ctx.Err() != nil || !a.historyReaderCurrent(r) { |
| 32 | return out |
| 33 | } |
| 34 | out.Data, out.Chunks = historyContentChunkAt(value, chunkIndex) |
| 35 | out.Done, out.Stale = chunkIndex >= out.Chunks-1, false |
| 36 | return out |
| 37 | } |
| 38 |