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