edtui

August 16, 2026 ยท View on GitHub

EdTUI

Crate Badge Continuous Integration Deps Status License Badge

Overview

EdTUI is a text editor widget for the Ratatui ecosystem. It is designed to provide a user experience inspired by Vim. Edtui is developed to be used as an editor in ratatui apps. It is not supposed to be a stand-alone code editor.

Create a new EditorState and render it using EditorView:

use edtui::{EditorState, EditorView};
use ratatui::widgets::Widget;

let mut state = EditorState::default();
EditorView::new(&mut state).render(area, buf);

The view is configured through builder methods, see Customization.

Handle events (Vim mode by default):

use edtui::EditorEventHandler;

let mut event_handler = EditorEventHandler::default();
event_handler.on_key_event(key_event, &mut state);

Or use Emacs mode (modeless editing):

use edtui::{EditorState, EditorEventHandler, Lines};

let mut state = EditorState::new(Lines::from("Hello World"));
let mut event_handler = EditorEventHandler::emacs_mode();
event_handler.on_key_event(key_event, &mut state);

Or customize keybindings:

let mut key_handler = KeyEventHandler::vim_mode();
key_handler.insert(
    KeyEventRegister::n(vec![KeyInput::ctrl('x')]),
    SwitchMode(EditorMode::Insert),
);
let event_handler = EditorEventHandler::new(key_handler);

Customization

EditorView is configured through builder methods:

MethodDescription
.theme(EditorTheme)Sets the editor theme (see Theming).
.wrap(bool)Enables line wrapping.
.tab_width(usize)Number of spaces used to render a tab.
.line_numbers(LineNumbers)Shows absolute or relative line numbers.
.single_line(bool)Restricts the editor to a single line.
.syntax_highlighter(Option<SyntaxHighlighter>)Enables syntax highlighting (syntax-highlighting feature).

Demo

Features

  • Custom theming.
  • Mouse events.
  • Vim and Emacs keybindings.
  • Copy paste using the systems clipboard.
  • Line wrapping.
  • Syntax highlighting.
  • Line numbers (absolute and relative).
  • System editor support (optional, via system-editor feature).

Theming

Customize the editor with EditorTheme:

use edtui::EditorTheme;
use ratatui::style::{Style, Color};

let theme = EditorTheme::default()
    .base(Style::default().bg(Color::Black).fg(Color::White));

The following builder methods are available:

MethodDescription
.base(Style)Base text style.
.block(Block)Surrounding block / border.
.cursor_style(Style)Cursor style.
.hide_cursor()Hides the cursor.
.selection_style(Style)Style of the selected text.
.line_numbers_style(Style)Style of the line numbers.
.status_line(EditorStatusLine)Sets and styles the status line.
.hide_status_line()Hides the status line.

Line Numbers

Display absolute or relative line numbers:

use edtui::{EditorView, EditorState, EditorTheme, LineNumbers};
use ratatui::style::{Style, Color};

EditorView::new(&mut EditorState::default())
        .theme(EditorTheme::default().line_numbers_style(Style::default().fg(Color::DarkGray)))
        .line_numbers(LineNumbers::Absolute)  // or LineNumbers::Relative
        .render(area, buf);

Single-Line Mode

For search boxes and single-line input fields, enable single-line mode to block newline insertion:

use edtui::{EditorState, EditorView};

let mut state = EditorState::default();
EditorView::new(&mut state)
        .single_line(true)
        .render(area, buf);

When enabled, newline insertion is blocked and pasting text with newlines will replace them with spaces.

Mouse Events

Edtui supports mouse input for moving the cursor and selecting text. Mouse handling is enabled by default via a feature toggle. Typically, mouse events are processed automatically when you call on_event:

let event_handler = EditorEventHandler::default();
event_handler.on_event(event, &mut state); // handles mouse events too

If you want finer control you can handle mouse events explicitly using on_mouse_event:

event_handler.on_mouse_event(mouse_event, &mut state);

Syntax highlighting

Syntax highlighting was added in version 0.8.4.

Edtui offers a number of custom themes, see [SyntaxHighlighter::theme] for a complete list. If you want to use a custom theme, see [SyntaxHighlighter::custom_theme]. Check syntect for more details about themes and extensions.

use edtui::{EditorView, EditorState, SyntaxHighlighter};

let syntax_highlighter = SyntaxHighlighter::new("dracula", "rs");
EditorView::new(&mut EditorState::default())
        .syntax_highlighter(Some(syntax_highlighter))
        .render(area, buf);

Paste Support

If you want to enable paste (via ctrl+y or cmd+y) you must explicitly enable it at the start of your app:

use ratatui::crossterm::event::EnableBracketedPaste;
let mut stdout = std::io::stdout();
ratatui::crossterm::xecute!(stdout, EnableBracketedPaste);

and disable it during cleanup:

use ratatui::crossterm::event::DisableBracketedPaste;
ratatui::crossterm::execute!(std::io::stdout(), DisableBracketedPaste);

See examples/app/term.rs for a an example.

System Editor

With the system-editor feature enabled you can open the editor content in an external text editor (e.g., nvim) using Ctrl+e in normal mode (or Alt+e in Emacs mode).

The system editor is decoupled from the event handler. After handling events, check if a system editor request is pending and call open yourself:

use edtui::system_editor;

event_handler.on_event(event, &mut state);

if system_editor::is_pending(&state) {
    system_editor::open(&mut state, &mut terminal)?;
    // Re-enable mouse capture or other terminal modes if necessary
    // crossterm::execute!(stdout(), EnableMouseCapture, EnableBracketedPaste)?;
}

The editor used is determined by the VISUAL or EDITOR environment variables, falling back to a platform-specific default if neither is set.

Keybindings

EdTUI offers Vim keybindings by default and Emacs keybindings as an alternative.

Vim Mode (default)

Normal Mode:
KeybindingDescription
iEnter Insert mode
vEnter Visual mode
h, j, k, lNavigate left, down, up, and right
wMove forward to the start of a word
eMove forward to the end of a word
bMove backward to the start of a word
f + <char>Move to the next occurrence of <char> on the line
t + <char>Move just before the next occurrence of <char>
ctrl+dJump a half page down
ctrl+uJump a half page up
PageDownJump a full page down
PageUpJump a full page up
xDelete the character under the cursor
u, ctrl+rUndo/Redo last action
EscEscape Visual mode
0Move cursor to start of line
_Move cursor to first non-blank character
$Move cursor to end of line
ggMove cursor to the first row
G Move cursor to the last row
%Move cursor to closing/opening bracket
{,}Move cursor to next/previous paragraph
aAppend after the cursor
AAppend at the end of the line
oAdd a new line below and enter Insert mode
OAdd a new line above and enter Insert mode
JJoin current line with the line below
dDelete the selection (Visual mode)
ddDelete the current line
dwDelete word forward
dWDelete WORD forward (whitespace-delimited)
diwDelete inner word
diWDelete inner WORD (whitespace-delimited)
df + <char>Delete up to and including the next <char> on the line
dt + <char>Delete up to (but not including) the next <char>
cwChange to the end of the word
cWChange to the end of the WORD (whitespace-delimited)
cf + <char>Change up to and including the next <char> on the line
ct + <char>Change up to (but not including) the next <char>
DDelete to the end of the line
viwSelect between word.
ciwChange between word.
ciWChange between WORD (whitespace-delimited)
vi + ", ', (, [ or {Select between delimiter ", ', (, [ or {
di + ", ', (, [ or {Delete between delimiter ", ', (, [ or {
ci + ", ', (, [ or {Change between delimiter ", ', (, [ or {
.Repeat the last change
uUndo the last change
rRedo the last undone action
yCopy the selected text in visual mode
yyCopy the current line in normal mode
pPaste the copied text after the cursor
PPaste the copied text before the cursor
HomeMove cursor to start of line
EndMove cursor to end of line
ctrl+eOpen in system editor (requires system-editor feature)
Insert Mode:
KeybindingDescription
EscReturn to Normal mode
Backspace/Ctrl-hDelete the previous character
DeleteDelete the character after the cursor
EnterInsert line break
ArrowsNavigation
HomeMove cursor to start of line
EndMove cursor to end of line
Ctrl+LeftMove backward to the start of a word
Ctrl+RightMove forward to the start of a word
PageDownJump a full page down
PageUpJump a full page up
ctrl+uDelete until first character

Emacs Mode

Emacs Mode was added in version 0.10.1.

Note that Emacs Mode is less feature complete and less tested than vim mode.

KeybindingDescription
Ctrl+fMove forward
Ctrl+bMove backward
Ctrl+nMove to next line
Ctrl+pMove to previous line
Ctrl+aMove to start of line
Ctrl+eMove to end of line
Ctrl+vHalf page down
Alt+vHalf page up
PageDownFull page down
PageUpFull page up
Alt+fForward word
Alt+bBackward word
Alt+<Beginning of buffer
Alt+>End of buffer
Ctrl+dDelete character forward
Ctrl+hDelete character backward
Alt+dDelete word forward
Alt+BackspaceDelete word backward
Ctrl+kDelete to end of line
Alt+uDelete to start of line
Ctrl+oOpen line (insert newline, stay)
Ctrl+jNewline
Ctrl+yPaste
Ctrl+uUndo
Ctrl+rRedo
Ctrl+gCancel search
EnterInsert line break
BackspaceDelete previous character
ArrowsNavigation
HomeMove to start of line
EndMove to end of line
Ctrl+LeftMove backward to the start of a word
Ctrl+RightMove forward to the start of a word
Alt+eOpen in system editor (requires system-editor feature)
Ctrl+sStart search
Ctrl+sSearch mode: Go to next match
Ctrl+rSearch mode: Go to previous match
EnterSearch mode: Select current match

License: MIT