salvation_cosmic_text/
cursor.rs

1/// Current cursor location
2#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
3pub struct Cursor {
4    /// Index of [`BufferLine`] in [`Buffer::lines`]
5    pub line: usize,
6    /// First-byte-index of glyph at cursor (will insert behind this glyph)
7    pub index: usize,
8    /// Whether to associate the cursor with the run before it or the run after it if placed at the
9    /// boundary between two runs
10    pub affinity: Affinity,
11}
12
13impl Cursor {
14    /// Create a new cursor
15    pub const fn new(line: usize, index: usize) -> Self {
16        Self::new_with_affinity(line, index, Affinity::Before)
17    }
18
19    /// Create a new cursor, specifying the affinity
20    pub const fn new_with_affinity(line: usize, index: usize, affinity: Affinity) -> Self {
21        Self {
22            line,
23            index,
24            affinity,
25        }
26    }
27}
28
29/// Whether to associate cursors placed at a boundary between runs with the run before or after it.
30#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
31pub enum Affinity {
32    #[default]
33    Before,
34    After,
35}
36
37impl Affinity {
38    pub fn before(&self) -> bool {
39        *self == Self::Before
40    }
41
42    pub fn after(&self) -> bool {
43        *self == Self::After
44    }
45
46    pub fn from_before(before: bool) -> Self {
47        if before {
48            Self::Before
49        } else {
50            Self::After
51        }
52    }
53
54    pub fn from_after(after: bool) -> Self {
55        if after {
56            Self::After
57        } else {
58            Self::Before
59        }
60    }
61}
62
63/// The position of a cursor within a [`Buffer`].
64#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
65pub struct LayoutCursor {
66    /// Index of [`BufferLine`] in [`Buffer::lines`]
67    pub line: usize,
68    /// Index of [`LayoutLine`] in [`BufferLine::layout`]
69    pub layout: usize,
70    /// Index of [`LayoutGlyph`] in [`LayoutLine::glyphs`]
71    pub glyph: usize,
72}
73
74impl LayoutCursor {
75    /// Create a new [`LayoutCursor`]
76    pub const fn new(line: usize, layout: usize, glyph: usize) -> Self {
77        Self {
78            line,
79            layout,
80            glyph,
81        }
82    }
83}
84
85/// A motion to perform on a [`Cursor`]
86#[derive(Clone, Copy, Debug, Eq, PartialEq)]
87pub enum Motion {
88    /// Apply specific [`LayoutCursor`]
89    LayoutCursor(LayoutCursor),
90    /// Move cursor to previous character ([Self::Left] in LTR, [Self::Right] in RTL)
91    Previous,
92    /// Move cursor to next character ([Self::Right] in LTR, [Self::Left] in RTL)
93    Next,
94    /// Move cursor left
95    Left,
96    /// Move cursor right
97    Right,
98    /// Move cursor up
99    Up,
100    /// Move cursor down
101    Down,
102    /// Move cursor to start of line
103    Home,
104    /// Move cursor to start of line, skipping whitespace
105    SoftHome,
106    /// Move cursor to end of line
107    End,
108    /// Move cursor to start of paragraph
109    ParagraphStart,
110    /// Move cursor to end of paragraph
111    ParagraphEnd,
112    /// Move cursor to start of document
113    DocumentStart,
114    /// Move cursor to end of document
115    DocumentEnd,
116    /// Move cursor up one page
117    PageUp,
118    /// Move cursor down one page
119    PageDown,
120    /// Move cursor up or down by a number of pixels
121    Vertical(i32),
122    /// Move cursor to previous word boundary
123    PreviousWord,
124    /// Move cursor to next word boundary
125    NextWord,
126    /// Move cursor to next word boundary to the left
127    LeftWord,
128    /// Move cursor to next word boundary to the right
129    RightWord,
130    /// Move cursor to the start of the document
131    BufferStart,
132    /// Move cursor to the end of the document
133    BufferEnd,
134    /// Move cursor to specific line
135    GotoLine(usize),
136}
137
138/// Scroll position in [`Buffer`]
139#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
140pub struct Scroll {
141    /// Index of [`BufferLine`] in [`Buffer::lines`]. This will be adjusted as needed if layout is
142    /// out of bounds
143    pub line: usize,
144    /// Index of [`LayoutLine`] in [`BufferLine::layout`]. This will be adjusted as needed
145    /// if it is negative or exceeds the number of layout lines
146    pub layout: i32,
147}
148
149impl Scroll {
150    /// Create a new cursor
151    pub const fn new(line: usize, layout: i32) -> Self {
152        Self { line, layout }
153    }
154}