import type { HistoryEntry } from './types.js'; /** * Selection rectangle in viewport cell coordinates, normalized so * `topLeft.row <= bottomRight.row` and the column pairs are likewise ordered. * Both endpoints are inclusive — the cell at `bottomRight` is selected. */ export interface SelectionRect { topLeft: { row: number; col: number; }; bottomRight: { row: number; col: number; }; /** True while the user is still dragging; false after left-release but * before either clearSelection or commitSelection runs. */ inProgress: boolean; } /** Canonicalize two viewport cells into a SelectionRect. Pure. */ export declare function normalizeSelection(a: { row: number; col: number; }, b: { row: number; col: number; }, inProgress: boolean): SelectionRect; /** True when the column lies outside the rendered card band. Inside the band * the layout reserves `SCROLLBAR_HIT_WIDTH` columns for the rail AFTER the * band, so `0..termWidth-1` is always in-band and nothing inside needs to be * excluded. The mouse handler must already have excluded the rail before * calling into the controller — we only check the band bounds here. */ export declare function isOutOfBand(col: number, termWidth: number): boolean; /** * One entry's contribution to a drag-selected range. Returned in document * (row-index-in-card) coordinates so the caller decides how to slice into * the entry's source text. `start` is the column inside the card (0-based * from the left edge of the card's visible rectangle, NOT the terminal * column — the gutter is excluded by the caller before reaching here). * `end` is inclusive. When `startRow === endRow`, the slice is one row; the * caller is responsible for translating text columns into source offsets. */ export interface SelectionSlice { entryId: number; /** Inclusive row-in-card for the start of the slice. */ startRow: number; /** Inclusive column, 0-based, inside the card's text area (gutter excluded). */ startCol: number; /** Inclusive end row. */ endRow: number; /** Inclusive end column, 0-based. */ endCol: number; } /** * Translate a viewport-cell selection into per-entry row/col slices, walking * the same mounted-group geometry the copy-hit registry uses so the two * systems share one row index. Entries wholly outside the selection return * nothing. Entries whose vertical span is wholly inside the selection are * returned as a single row-range; entries the selection clips at the top or * bottom are returned with row bounds matching the clip. * * `cardVisibleCols` is the number of columns inside the card the user can * see — the band width minus the right gutter (`viewportWidth - SCROLLBAR_HIT_WIDTH`). * Slices never include the gutter or any column to its right; the caller has * already validated that. * * Returned slices are in document (entry-local) coordinates: `startRow`/`endRow` * are rows inside the entry's own geometry, NOT viewport cells. This is what * the assembler needs to recover text — slicing into the raw entry text uses * per-row layout, which the caller resolves via the layout store. */ export declare function selectionToSlices(opts: { selection: SelectionRect; cards: ReadonlyArray<{ entryId: number; /** 0-based viewport row of the card's first visible row. */ viewportStartRow: number; /** 0-based viewport row just past the card's last visible row. */ viewportEndRow: number; }>; cardVisibleCols: number; }): SelectionSlice[]; /** * Build the clipboard payload for a selection by slicing into each affected * entry's full renderable text. The v1 contract is line-then-column on the * entry's source text: each slice exposes `startRow`/`endRow` and * `startCol`/`endCol` in card-local coordinates; we split the entry's * text on `\n`, keep only the rows inside the row range, and within those * rows apply the column range. The matrix matches what the source line * index would be when no wrapping occurs — i.e. one card row maps to one * source line. Wrap-geometry translation is intentionally absent in v1 * because the layout store does not yet expose per-card-row wrap segments; * it returns when those segments exist and a v1.1 test demands it. * * `toolGroupsByHeadId` lets a multi-member tool-group expand: when the * head id appears with `entryIds.length > 1`, the assembler copies via * `copyableTextForEntries` (raw ordered JSON of every member, matching * the existing copy-icon contract). A single-entry head falls through * to `copyableTextForEntry`. * * Multi-entry selections are joined with `\n---\n` so the user can see * where one card ends and the next begins. Empty selections and * selections that resolve to no text return `""` so the caller can fall * through silently. */ export declare function assembleSelectionText(opts: { slices: readonly SelectionSlice[]; entriesById: ReadonlyMap; toolGroupsByHeadId?: ReadonlyMap | undefined; /** * Render width used to build the wrap-aware row→line translation for * assistant/thinking cards (v1.1 M4). When omitted, wrapped kinds fall * back to the v1 naive mapping below — callers that cannot know the * width keep their existing behavior. */ termWidth?: number | undefined; }): string; //# sourceMappingURL=selection-helpers.d.ts.map