返回 CodeWhale
selection.rs
根目录 / crates / tui / src / tui / selection.rs
1 //! Text selection state for the transcript view.
2
3 use std::time::Instant;
4
5 // === Types ===
6
7 /// A selection endpoint in the transcript (line/column).
8 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
9 pub struct TranscriptSelectionPoint {
10 pub line_index: usize,
11 pub column: usize,
12 }
13
14 /// Current selection state in the transcript view.
15 #[derive(Debug, Clone, Copy, Default)]
16 pub struct TranscriptSelection {
17 pub anchor: Option<TranscriptSelectionPoint>,
18 pub head: Option<TranscriptSelectionPoint>,
19 pub dragging: bool,
20 }
21
22 /// Drag-past-edge auto-scroll state. While the user holds the left button
23 /// and the cursor is above or below the transcript rect, the main loop
24 /// advances `pending_scroll_delta` and extends the selection head on a
25 /// fixed cadence so a long passage can be selected in one drag (#1163).
26 #[derive(Debug, Clone, Copy)]
27 pub struct SelectionAutoscroll {
28 /// `-1` scrolls up, `+1` scrolls down. Never `0`.
29 pub direction: i32,
30 /// Last in-bounds mouse column, in absolute terminal coordinates.
31 pub column: u16,
32 /// When the next tick is allowed to fire.
33 pub next_tick: Instant,
34 }
35
36 impl TranscriptSelection {
37 /// Clear any active selection.
38 pub fn clear(&mut self) {
39 self.anchor = None;
40 self.head = None;
41 self.dragging = false;
42 }
43
44 /// Whether a full selection is active.
45 #[must_use]
46 pub fn is_active(&self) -> bool {
47 self.anchor.is_some() && self.head.is_some()
48 }
49
50 /// Return selection endpoints ordered from start to end.
51 #[must_use]
52 pub fn ordered_endpoints(
53 &self,
54 ) -> Option<(TranscriptSelectionPoint, TranscriptSelectionPoint)> {
55 let anchor = self.anchor?;
56 let head = self.head?;
57 if (head.line_index, head.column) < (anchor.line_index, anchor.column) {
58 Some((head, anchor))
59 } else {
60 Some((anchor, head))
61 }
62 }
63 }
64
64 lines RUST