Skip to main content

tui_lipan/widgets/text_area/
metrics.rs

1use crate::core::component::ScrollbarVisibility;
2use crate::style::{Rect, Span};
3use crate::text::line_index::TextPosition;
4
5use super::virtual_text;
6
7/// Line-number display mode for the built-in `TextArea` gutter.
8#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
9pub enum TextAreaLineNumberMode {
10    /// Show absolute one-based logical line numbers.
11    #[default]
12    Absolute,
13    /// Show Vim-style relative numbers: the cursor line is absolute and other
14    /// lines show their distance from the cursor line.
15    Relative,
16}
17
18/// Previous-frame resolved layout and cursor metrics for a keyed [`TextArea`](crate::widgets::TextArea).
19#[allow(missing_docs)]
20#[derive(Clone, Debug, PartialEq, Eq)]
21pub struct TextAreaMetrics {
22    pub rect: Rect,
23    pub inner_rect: Rect,
24    pub content_rect: Rect,
25    pub gutter_width: u16,
26    pub scroll_offset: usize,
27    pub h_scroll_offset: usize,
28    pub visible_logical_lines: std::ops::Range<usize>,
29    pub visible_visual_rows: std::ops::Range<usize>,
30    pub total_logical_lines: usize,
31    pub total_visual_lines: usize,
32    pub scrollbars: ScrollbarVisibility,
33    pub cursor: Option<TextAreaCursorMetrics>,
34    pub editor_cursor: Option<TextAreaCursorMetrics>,
35}
36
37/// Cursor cell metrics for a [`TextAreaMetrics`] snapshot.
38#[allow(missing_docs)]
39#[derive(Clone, Debug, PartialEq, Eq)]
40pub struct TextAreaCursorMetrics {
41    pub byte_offset: usize,
42    /// Buffer-based line/column position derived from the underlying value.
43    /// Virtual text affects [`rect`](Self::rect), but never this buffer position.
44    pub position: TextPosition,
45    pub rect: Rect,
46    pub visible: bool,
47}
48
49/// Non-editable styled text rendered by a [`TextArea`](crate::widgets::TextArea) without entering its value.
50///
51/// Inline virtual text is anchored before `anchor` and shifts subsequent visual
52/// columns. End-of-line virtual text is rendered after the final visual row of
53/// the anchor's logical line and does not participate in wrapping.
54#[allow(missing_docs)]
55#[derive(Clone, Debug, PartialEq, Eq, Hash)]
56pub struct TextAreaVirtualText {
57    pub anchor: usize,
58    pub content: Vec<Span>,
59    pub placement: VirtualTextPlacement,
60    pub priority: u16,
61}
62
63impl TextAreaVirtualText {
64    /// Create virtual text with explicit placement.
65    pub fn new(
66        anchor: usize,
67        content: impl Into<Vec<Span>>,
68        placement: VirtualTextPlacement,
69    ) -> Self {
70        Self {
71            anchor,
72            content: virtual_text::sanitize_virtual_text_spans(content.into()),
73            placement,
74            priority: 0,
75        }
76    }
77
78    /// Create inline virtual text inserted before the byte at `anchor`.
79    pub fn inline(anchor: usize, content: impl Into<Vec<Span>>) -> Self {
80        Self::new(anchor, content, VirtualTextPlacement::Inline)
81    }
82
83    /// Create end-of-line virtual text for the logical line containing `anchor`.
84    pub fn eol(anchor: usize, content: impl Into<Vec<Span>>) -> Self {
85        Self::new(anchor, content, VirtualTextPlacement::Eol)
86    }
87
88    /// Set ordering among virtual text segments sharing an anchor.
89    pub fn priority(mut self, priority: u16) -> Self {
90        self.priority = priority;
91        self
92    }
93}
94
95/// Placement for [`TextAreaVirtualText`].
96#[allow(missing_docs)]
97#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
98pub enum VirtualTextPlacement {
99    Inline,
100    Eol,
101}