iced_core/text/
editor.rs

1//! Edit text.
2use crate::text::highlighter::{self, Highlighter};
3use crate::text::{LineHeight, Wrapping};
4use crate::{Pixels, Point, Rectangle, Size};
5
6use std::borrow::Cow;
7use std::sync::Arc;
8
9/// A component that can be used by widgets to edit multi-line text.
10pub trait Editor: Sized + Default {
11    /// The font of the [`Editor`].
12    type Font: Copy + PartialEq + Default;
13
14    /// Creates a new [`Editor`] laid out with the given text.
15    fn with_text(text: &str) -> Self;
16
17    /// Returns true if the [`Editor`] has no contents.
18    fn is_empty(&self) -> bool;
19
20    /// Returns the current [`Cursor`] of the [`Editor`].
21    fn cursor(&self) -> Cursor;
22
23    /// Returns the current [`Selection`] of the [`Editor`].
24    fn selection(&self) -> Selection;
25
26    /// Returns the current selected text of the [`Editor`].
27    fn copy(&self) -> Option<String>;
28
29    /// Returns the text of the given line in the [`Editor`], if it exists.
30    fn line(&self, index: usize) -> Option<Line<'_>>;
31
32    /// Returns the amount of lines in the [`Editor`].
33    fn line_count(&self) -> usize;
34
35    /// Performs an [`Action`] on the [`Editor`].
36    fn perform(&mut self, action: Action);
37
38    /// Moves the cursor to the given position.
39    fn move_to(&mut self, cursor: Cursor);
40
41    /// Returns the current boundaries of the [`Editor`].
42    fn bounds(&self) -> Size;
43
44    /// Returns the minimum boundaries to fit the current contents of
45    /// the [`Editor`].
46    fn min_bounds(&self) -> Size;
47
48    /// Updates the [`Editor`] with some new attributes.
49    fn update(
50        &mut self,
51        new_bounds: Size,
52        new_font: Self::Font,
53        new_size: Pixels,
54        new_line_height: LineHeight,
55        new_wrapping: Wrapping,
56        new_highlighter: &mut impl Highlighter,
57    );
58
59    /// Runs a text [`Highlighter`] in the [`Editor`].
60    fn highlight<H: Highlighter>(
61        &mut self,
62        font: Self::Font,
63        highlighter: &mut H,
64        format_highlight: impl Fn(&H::Highlight) -> highlighter::Format<Self::Font>,
65    );
66}
67
68/// An interaction with an [`Editor`].
69#[derive(Debug, Clone, PartialEq)]
70pub enum Action {
71    /// Apply a [`Motion`].
72    Move(Motion),
73    /// Select text with a given [`Motion`].
74    Select(Motion),
75    /// Select the word at the current cursor.
76    SelectWord,
77    /// Select the line at the current cursor.
78    SelectLine,
79    /// Select the entire buffer.
80    SelectAll,
81    /// Perform an [`Edit`].
82    Edit(Edit),
83    /// Click the [`Editor`] at the given [`Point`].
84    Click(Point),
85    /// Drag the mouse on the [`Editor`] to the given [`Point`].
86    Drag(Point),
87    /// Scroll the [`Editor`] a certain amount of lines.
88    Scroll {
89        /// The amount of lines to scroll.
90        lines: i32,
91    },
92}
93
94impl Action {
95    /// Returns whether the [`Action`] is an editing action.
96    pub fn is_edit(&self) -> bool {
97        matches!(self, Self::Edit(_))
98    }
99}
100
101/// An action that edits text.
102#[derive(Debug, Clone, PartialEq)]
103pub enum Edit {
104    /// Insert the given character.
105    Insert(char),
106    /// Paste the given text.
107    Paste(Arc<String>),
108    /// Break the current line.
109    Enter,
110    /// Indent the current line.
111    Indent,
112    /// Unindent the current line.
113    Unindent,
114    /// Delete the previous character.
115    Backspace,
116    /// Delete the next character.
117    Delete,
118}
119
120/// A cursor movement.
121#[derive(Debug, Clone, Copy, PartialEq)]
122pub enum Motion {
123    /// Move left.
124    Left,
125    /// Move right.
126    Right,
127    /// Move up.
128    Up,
129    /// Move down.
130    Down,
131    /// Move to the left boundary of a word.
132    WordLeft,
133    /// Move to the right boundary of a word.
134    WordRight,
135    /// Move to the start of the line.
136    Home,
137    /// Move to the end of the line.
138    End,
139    /// Move to the start of the previous window.
140    PageUp,
141    /// Move to the start of the next window.
142    PageDown,
143    /// Move to the start of the text.
144    DocumentStart,
145    /// Move to the end of the text.
146    DocumentEnd,
147}
148
149impl Motion {
150    /// Widens the [`Motion`], if possible.
151    pub fn widen(self) -> Self {
152        match self {
153            Self::Left => Self::WordLeft,
154            Self::Right => Self::WordRight,
155            Self::Home => Self::DocumentStart,
156            Self::End => Self::DocumentEnd,
157            _ => self,
158        }
159    }
160
161    /// Returns the [`Direction`] of the [`Motion`].
162    pub fn direction(&self) -> Direction {
163        match self {
164            Self::Left
165            | Self::Up
166            | Self::WordLeft
167            | Self::Home
168            | Self::PageUp
169            | Self::DocumentStart => Direction::Left,
170            Self::Right
171            | Self::Down
172            | Self::WordRight
173            | Self::End
174            | Self::PageDown
175            | Self::DocumentEnd => Direction::Right,
176        }
177    }
178}
179
180/// A direction in some text.
181#[derive(Debug, Clone, Copy, PartialEq, Eq)]
182pub enum Direction {
183    /// <-
184    Left,
185    /// ->
186    Right,
187}
188
189/// The cursor of an [`Editor`].
190#[derive(Debug, Clone)]
191pub enum Selection {
192    /// Cursor without a selection
193    Caret(Point),
194
195    /// Cursor selecting a range of text
196    Range(Vec<Rectangle>),
197}
198
199/// The range of an [`Editor`].
200#[derive(Debug, Clone, Copy, PartialEq)]
201pub struct Cursor {
202    /// The cursor position.
203    pub position: Position,
204
205    /// The selection position, if any.
206    pub selection: Option<Position>,
207}
208
209/// A cursor position in an [`Editor`].
210#[derive(Debug, Clone, Copy, PartialEq)]
211pub struct Position {
212    /// The line of text.
213    pub line: usize,
214    /// The column in the line.
215    pub column: usize,
216}
217
218/// A line of an [`Editor`].
219#[derive(Clone, Debug, Default, Eq, PartialEq)]
220pub struct Line<'a> {
221    /// The raw text of the [`Line`].
222    pub text: Cow<'a, str>,
223    /// The line ending of the [`Line`].
224    pub ending: LineEnding,
225}
226
227/// The line ending of a [`Line`].
228#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
229pub enum LineEnding {
230    /// Use `\n` for line ending (POSIX-style)
231    #[default]
232    Lf,
233    /// Use `\r\n` for line ending (Windows-style)
234    CrLf,
235    /// Use `\r` for line ending (many legacy systems)
236    Cr,
237    /// Use `\n\r` for line ending (some legacy systems)
238    LfCr,
239    /// No line ending
240    None,
241}
242
243impl LineEnding {
244    /// Gets the string representation of the [`LineEnding`].
245    pub fn as_str(self) -> &'static str {
246        match self {
247            Self::Lf => "\n",
248            Self::CrLf => "\r\n",
249            Self::Cr => "\r",
250            Self::LfCr => "\n\r",
251            Self::None => "",
252        }
253    }
254}