edtui/lib.rs
1//! <div align="center">
2//!
3//! ## `EdTUI`
4//!
5//! [![Crate Badge]](https://crates.io/crates/edtui) [](https://github.com/preiter93/edtui/actions/workflows/ci.yml) [](https://deps.rs/repo/github/preiter93/edtui) [![License Badge]](./LICENSE)
6//!
7//! </div>
8//!
9//! ## Overview
10//! `EdTUI` is a text editor widget for the [Ratatui](https://github.com/ratatui-org/ratatui) ecosystem.
11//! It is designed to provide a user experience inspired by Vim. Edtui is developed to be used as an
12//! editor in ratatui apps. It is not supposed to be a stand-alone code editor.
13//!
14//! Create a new `EditorState` and render it using `EditorView`.
15//! You can customize the theme, enable line wrapping, syntax highlight the text or set the tab
16//! width:
17//! ```ignore
18//! use edtui::{EditorState, EditorTheme, EditorView};
19//! use ratatui::widgets::Widget;
20//!
21//! let mut state = EditorState::default();
22//! EditorView::new(&mut state)
23//! .theme(EditorTheme::default())
24//! .wrap(true)
25//! .syntax_highlighter(None)
26//! .tab_width(2)
27//! .render(area, buf);
28//! ```
29//!
30//! Handle events (Vim mode by default):
31//! ```ignore
32//! use edtui::EditorEventHandler;
33//!
34//! let mut event_handler = EditorEventHandler::default();
35//! event_handler.on_key_event(key_event, &mut state);
36//! ```
37//!
38//! Or use Emacs mode (modeless editing):
39//! ```ignore
40//! use edtui::{EditorState, EditorEventHandler, Lines};
41//!
42//! let mut state = EditorState::new(Lines::from("Hello World"));
43//! let mut event_handler = EditorEventHandler::emacs_mode();
44//! event_handler.on_key_event(key_event, &mut state);
45//! ```
46//!
47//! Or customize keybindings:
48//! ```ignore
49//! let mut key_handler = KeyEventHandler::vim_mode();
50//! key_handler.insert(
51//! KeyEventRegister::n(vec![KeyInput::ctrl('x')]),
52//! SwitchMode(EditorMode::Insert),
53//! );
54//! let event_handler = EditorEventHandler::new(key_handler);
55//! ```
56//!
57//! ## Demo
58//!
59//! 
60//!
61//! ## Features
62//! - Custom theming.
63//! - Mouse events.
64//! - Vim and Emacs keybindings.
65//! - Copy paste using the systems clipboard.
66//! - Line wrapping.
67//! - Syntax highlighting.
68//! - Line numbers (absolute and relative).
69//! - System editor support (optional, via `system-editor` feature).
70//!
71//! ## Theming
72//!
73//! Customize the editor `EditorTheme`:
74//!
75//! ```ignore
76//! use edtui::{EditorTheme, EditorStatusLine};
77//! use ratatui::style::{Style, Color};
78//! use ratatui::widgets::Block;
79//!
80//! let theme = EditorTheme::default()
81//! .block(Block::default())
82//! .base(Style::default().bg(Color::Black).fg(Color::White))
83//! .cursor_style(Style::default().bg(Color::White).fg(Color::Black))
84//! .selection_style(Style::default().bg(Color::Yellow).fg(Color::Black))
85//! .hide_status_line(); // or use `.status_line(..)` for styling the status line
86//! ```
87//!
88//! ## Line Numbers
89//!
90//! Display absolute or relative line numbers:
91//!
92//! ```ignore
93//! use edtui::{EditorView, EditorState, EditorTheme, LineNumbers};
94//! use ratatui::style::{Style, Color};
95//!
96//! EditorView::new(&mut EditorState::default())
97//! .theme(EditorTheme::default().line_numbers_style(Style::default().fg(Color::DarkGray)))
98//! .line_numbers(LineNumbers::Absolute) // or LineNumbers::Relative
99//! .render(area, buf);
100//! ```
101//!
102//! 
103//!
104//! ## Single-Line Mode
105//!
106//! For search boxes and single-line input fields, enable single-line mode to block newline insertion:
107//!
108//! ```ignore
109//! use edtui::{EditorState, EditorView};
110//!
111//! let mut state = EditorState::default();
112//! EditorView::new(&mut state)
113//! .single_line(true)
114//! .render(area, buf);
115//! ```
116//!
117//! When enabled, newline insertion is blocked and pasting text with newlines will replace them with spaces.
118//!
119//! ## Mouse Events
120//!
121//! `Edtui` supports mouse input for moving the cursor and selecting text.
122//! Mouse handling is **enabled by default** via a feature toggle.
123//! Typically, mouse events are processed automatically when you call `on_event`:
124//! ```ignore
125//! let event_handler = EditorEventHandler::default();
126//! event_handler.on_event(event, &mut state); // handles mouse events too
127//! ```
128//! If you want finer control you can handle mouse events explicitly using `on_mouse_event`:
129//! ```ignore
130//! event_handler.on_mouse_event(mouse_event, &mut state);
131//! ```
132//!
133//! ## Syntax highlighting
134//!
135//! Syntax highlighting was added in version `0.8.4`.
136//!
137//! `Edtui` offers a number of custom themes, see [`SyntaxHighlighter::theme`] for a complete list.
138//! If you want to use a custom theme, see [`SyntaxHighlighter::custom_theme`]. Check [syntect](https://github.com/trishume/syntect)
139//! for more details about themes and extensions.
140//!
141//! ```ignore
142//! use edtui::{EditorView, EditorState, SyntaxHighlighter};
143//!
144//! let syntax_highlighter = SyntaxHighlighter::new("dracula", "rs");
145//! EditorView::new(&mut EditorState::default())
146//! .syntax_highlighter(Some(syntax_highlighter))
147//! .render(area, buf);
148//! ```
149//!
150//! 
151//!
152//! ## Paste Support
153//!
154//! If you want to enable paste (via ctrl+y or cmd+y) you must explicitly enable it at the start of your app:
155//!
156//! ```ignore
157//! use ratatui::crossterm::event::EnableBracketedPaste;
158//! let mut stdout = std::io::stdout();
159//! ratatui::crossterm::xecute!(stdout, EnableBracketedPaste);
160//! ```
161//!
162//! and disable it during cleanup:
163//!
164//! ```ignore
165//! use ratatui::crossterm::event::DisableBracketedPaste;
166//! ratatui::crossterm::execute!(std::io::stdout(), DisableBracketedPaste);
167//! ```
168//!
169//! See `examples/app/term.rs` for a an example.
170//!
171//! ## System Editor
172//!
173//! With the `system-editor` feature enabled you can open the editor content in an external
174//! text editor (e.g., nvim) using `Ctrl+e` in normal mode (or `Alt+e` in Emacs mode).
175//!
176//! The system editor is decoupled from the event handler. After handling events, check
177//! if a system editor request is pending and call `open` yourself:
178//!
179//! ```ignore
180//! use edtui::system_editor;
181//!
182//! event_handler.on_event(event, &mut state);
183//!
184//! if system_editor::is_pending(&state) {
185//! system_editor::open(&mut state, &mut terminal)?;
186//! // Re-enable mouse capture or other terminal modes if necessary
187//! // crossterm::execute!(stdout(), EnableMouseCapture, EnableBracketedPaste)?;
188//! }
189//! ```
190//!
191//! The editor used is determined by the `VISUAL` or `EDITOR` environment variables,
192//! falling back to a platform-specific default if neither is set.
193//!
194//! ## Keybindings
195//! `EdTUI` offers Vim keybindings by default and Emacs keybindings as an alternative.
196//!
197//! ### Vim Mode (default)
198//!
199//! #### Normal Mode:
200//!
201//! | Keybinding | Description |
202//! |---------------------------|----------------------------------------------------------|
203//! | `i` | Enter Insert mode |
204//! | `v` | Enter Visual mode |
205//! | `h`, `j`, `k`, `l` | Navigate left, down, up, and right |
206//! | `w` | Move forward to the start of a word |
207//! | `e` | Move forward to the end of a word |
208//! | `b` | Move backward to the start of a word |
209//! | `ctrl+d` | Jump a half page down |
210//! | `ctrl+u` | Jump a half page up |
211//! | `PageDown` | Jump a full page down |
212//! | `PageUp` | Jump a full page up |
213//! | `x` | Delete the character under the cursor |
214//! | `u`, `ctrl+r` | Undo/Redo last action |
215//! | `Esc` | Escape Visual mode |
216//! | `0` | Move cursor to start of line |
217//! | `_` | Move cursor to first non-blank character |
218//! | `$` | Move cursor to end of line |
219//! | `gg` | Move cursor to the first row |
220//! | `G ` | Move cursor to the last row |
221//! | `%` | Move cursor to closing/opening bracket |
222//! | `a` | Append after the cursor |
223//! | `A` | Append at the end of the line |
224//! | `o` | Add a new line below and enter Insert mode |
225//! | `O` | Add a new line above and enter Insert mode |
226//! | `J` | Join current line with the line below |
227//! | `d` | Delete the selection (Visual mode) |
228//! | `dd` | Delete the current line |
229//! | `D` | Delete to the end of the line |
230//! | `viw` | Select between word. |
231//! | `ciw` | Change between word. |
232//! | `vi` + `", ', (, [ or {` | Select between delimiter `", ', (, [ or {` |
233//! | `ci` + `", ', (, [ or {` | Change between delimiter `", ', (, [ or {` |
234//! | `u` | Undo the last change |
235//! | `r` | Redo the last undone action |
236//! | `y` | Copy the selected text in visual mode |
237//! | `yy` | Copy the current line in normal mode |
238//! | `p` | Paste the copied text |
239//! | `Home` | Move cursor to start of line |
240//! | `End` | Move cursor to end of line |
241//! | `ctrl+e` | Open in system editor (requires `system-editor` feature) |
242//!
243//! #### Insert Mode:
244//!
245//! | Keybinding | Description |
246//! |-------------|-----------------------------------------|
247//! | `Esc` | Return to Normal mode |
248//! | `Backspace` | Delete the previous character |
249//! | `Delete` | Delete the character after the cursor |
250//! | `Enter` | Insert line break |
251//! | `Arrows` | Navigation |
252//! | `Home` | Move cursor to start of line |
253//! | `End` | Move cursor to end of line |
254//! | `Ctrl+Left` | Move backward to the start of a word |
255//! | `Ctrl+Right`| Move forward to the start of a word |
256//! | `PageDown` | Jump a full page down |
257//! | `PageUp` | Jump a full page up |
258//! | `ctrl+u` | Delete until first character |
259//!
260//! ### Emacs Mode
261//!
262//! Emacs Mode was added in version 0.10.1.
263//!
264//! Note that Emacs Mode is less feature complete and less tested than vim mode.
265//!
266//! | Keybinding | Description |
267//! |-----------------|----------------------------------------------------------|
268//! | `Ctrl+f` | Move forward |
269//! | `Ctrl+b` | Move backward |
270//! | `Ctrl+n` | Move to next line |
271//! | `Ctrl+p` | Move to previous line |
272//! | `Ctrl+a` | Move to start of line |
273//! | `Ctrl+e` | Move to end of line |
274//! | `Ctrl+v` | Half page down |
275//! | `Alt+v` | Half page up |
276//! | `PageDown` | Full page down |
277//! | `PageUp` | Full page up |
278//! | `Alt+f` | Forward word |
279//! | `Alt+b` | Backward word |
280//! | `Alt+<` | Beginning of buffer |
281//! | `Alt+>` | End of buffer |
282//! | `Ctrl+d` | Delete character forward |
283//! | `Ctrl+h` | Delete character backward |
284//! | `Alt+d` | Delete word forward |
285//! | `Alt+Backspace` | Delete word backward |
286//! | `Ctrl+k` | Delete to end of line |
287//! | `Alt+u` | Delete to start of line |
288//! | `Ctrl+o` | Open line (insert newline, stay) |
289//! | `Ctrl+j` | Newline |
290//! | `Ctrl+y` | Paste |
291//! | `Ctrl+u` | Undo |
292//! | `Ctrl+r` | Redo |
293//! | `Ctrl+g` | Cancel search |
294//! | `Enter` | Insert line break |
295//! | `Backspace` | Delete previous character |
296//! | `Arrows` | Navigation |
297//! | `Home` | Move to start of line |
298//! | `End` | Move to end of line |
299//! | `Ctrl+Left` | Move backward to the start of a word |
300//! | `Ctrl+Right` | Move forward to the start of a word |
301//! | `Alt+e` | Open in system editor (requires `system-editor` feature) |
302//! | `Ctrl+s` | Start search |
303//! | `Ctrl+s` | Search mode: Go to next match |
304//! | `Ctrl+r` | Search mode: Go to previous match |
305//! | `Enter` | Search mode: Select current match |
306//!
307//! ### Roadmap
308//! - [ ] Support termwiz and termion
309//!
310//! [Crate Badge]: https://img.shields.io/crates/v/edtui?logo=rust&style=flat-square&logoColor=E05D44&color=E05D44
311//! [License Badge]: https://img.shields.io/crates/l/edtui?style=flat-square&color=1370D3
312#![allow(
313 dead_code,
314 clippy::module_name_repetitions,
315 clippy::cast_possible_truncation
316)]
317pub mod actions;
318pub mod clipboard;
319mod debug;
320pub mod events;
321#[cfg(feature = "system-editor")]
322pub use actions::system_editor;
323mod helper;
324mod state;
325mod view;
326
327pub use events::EditorEventHandler;
328pub use state::{highlight::Highlight, mode::EditorMode, EditorState};
329pub use view::{theme::EditorTheme, EditorStatusLine, EditorView, LineNumbers};
330
331#[cfg(feature = "syntax-highlighting")]
332pub use view::syntax_higlighting::{
333 SyntaxHighlighter, SyntaxHighlighterError, SYNTAX_SET, THEME_SET,
334};
335
336#[cfg(feature = "syntax-highlighting")]
337pub use syntect;
338
339/// A data structure that contains chars organized in rows and columns
340pub type Lines = jagged::Jagged<char>;
341pub use jagged::index::RowIndex;
342pub use jagged::Index2;