Skip to main content

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