1
0
зеркало из https://github.com/glebtv/tui-textarea.git synced 2026-08-28 11:36:17 +03:00
Files
tui-textarea/CHANGELOG.md
Gleb Tv b542e179ae feat(keymap): bind Ctrl+Backspace/Ctrl+Delete to word deletion
Add the de-facto standard terminal/editor hotkeys to the default key map:
- Ctrl+Backspace -> delete_word
- Ctrl+Delete -> delete_next_word

Previously only Alt+Backspace/Ctrl+w and Alt+Delete/Alt+d were bound,
which conflicts with muscle memory from readline, VS Code and other TUIs.
2026-08-17 20:47:38 +03:00

33 KiB

Changelog

[0.12.2] - 2026-08-17 [Changes][v0.12.2]

Features

  • Common word-deletion hotkeys: Bind Ctrl+Backspace to [TextArea::delete_word] and Ctrl+Delete to [TextArea::delete_next_word] in the default key map, matching the de-facto terminal/editor convention (readline, VS Code, opencode).

[0.12.1] - 2026-07-10 Changes

Features

  • Native cursor integration (#26, @srothgan): Add opt-in CursorRenderMode::Hidden and TextArea::rendered_cursor_position() for placing backend-owned terminal cursors while preserving the default buffer-drawn cursor behavior.

[0.12.0] - 2026-06-30 Changes

Features

  • Atomic range editing (#19, @srothgan): Add indivisible spans for cursor movement, insertion normalization, and deletion expansion.

Maintenance

  • Repository setup refresh (#23, @srothgan): Add CODEOWNERS, code of conduct, security policy, Dependabot coverage, and workflow metadata.

CI and Dependencies

  • Rust 1.88 MSRV (#23, @srothgan): Raise rust-version to 1.88.0 and run CI/release workflows on that toolchain.

[0.11.0] - 2026-05-03 Changes

  • BREAKING: Remove legacy tui-rs feature support and the tuirs-* examples; this fork now supports ratatui integrations only.
  • Add a screen/data cursor mapping layer to preserve visual columns correctly across wrapped rows containing tabs or wide Unicode characters.
  • Rework wrapped cursor movement and rendering to use the cached screen map shared by the widget and cursor logic.
  • Add regression tests for wrapped cursor movement across mixed-width text.
  • Add an opt-in fixed-size recording mode for crossterm examples via TUI_TEXTAREA_RECORDING and TUI_TEXTAREA_RECORDING_SIZE.

[0.10.2] - 2026-03-13 Changes

  • Add TextArea::set_lines(lines, cursor) for direct whole-buffer replacement without rebuilding widget configuration.
  • Preserve textarea configuration across set_lines() while resetting history, active selection, custom highlights, viewport scroll, and cached measurement state.
  • Cache TextArea::measure(width_cols) results by width and invalidate the cache on content edits, undo() / redo(), and measure-affecting setters.
  • Add tests covering set_lines() semantics, cursor clamping, and measure() cache correctness.

[0.10.1] - 2026-03-05 Changes

  • Fix Up/Down arrow keys to navigate between visual (wrapped) lines instead of jumping between logical lines when word wrapping is active.
  • Preserve visual column offset when moving between wrapped rows so the cursor moves straight vertically.
  • Fix cursor_at_visual_row() boundary clamping for non-last wrapped segments to prevent the cursor landing on the wrong visual line.

[0.10.0] - 2026-02-25 Changes

  • Add row-based measurement API via TextArea::measure(width_cols) and TextAreaMeasure.
  • Include content rows and preferred rows (with block chrome such as borders/padding) in measurement results.
  • Add configurable row bounds via TextArea::set_min_rows / set_max_rows with getters.
  • Clamp preferred_rows to effective [min_rows, max_rows] while keeping wrapping and viewport behavior unchanged.
  • Update the variable-height example to size from measure().preferred_rows instead of raw line count.
  • Add integration tests covering measurement semantics, wrapping/line-number effects, and min/max normalization.

[0.9.2] - 2026-02-19 Changes

  • Migrate to Rust 2024 edition; bump rust-version to 1.85.0.
  • Replace floating-point num_digits with usize::ilog10 for correctness on large values.
  • Expand watch-check alias to cover crossterm_0_28, no-backend, tuirs-crossterm, tuirs-no-backend, serde, and arbitrary feature paths.
  • Expand watch-test alias to cover crossterm_0_28, tuirs-crossterm, serde, and arbitrary features.
  • Expand CI test and clippy workflows to full feature matrix including termion and tuirs-termion on Ubuntu.

[0.9.1] - 2026-02-18 Changes

  • Fix panic on Ctrl+U/undo() after oversized delete_str() (including select_all() + delete_str(usize::MAX) on empty buffers).
  • Fix root cause by clamping exhausted delete_str() ranges to EOF so history never stores out-of-bounds rows.
  • Add defensive cursor clamping in undo()/redo() when restoring from history.
  • Add regression tests for the reported panic paths and invalid-history cursor restore edge cases.

[0.9.0] - 2026-02-18 Changes

  • Add opt-in soft-wrap modes via WrapMode::{None, Word, Glyph, WordOrGlyph} and TextArea::set_wrap_mode.
  • Add Unicode-aware wrapped rendering with logical-to-visual row mapping.
  • Keep backward-compatible behavior in WrapMode::None (existing horizontal scrolling path).
  • Make wrapped width calculations tab-aware to prevent hidden text on lines containing \t.
  • Fix wrapped continuation rendering for cursor-line style and selection boundaries.
  • Add comprehensive wrap regression tests for long text, newlines, tabs, tiny widths, and wrapped highlight behavior.

[0.8.0] - 2026-02-18 Changes

  • Add TextArea::clear() API to clear all text content with undo/redo coverage. (upstream PR #113)
  • Add custom highlight ranges with priority via TextArea::custom_highlight() and TextArea::clear_custom_highlight(). (upstream PR #93)
  • Fix horizontal scrolling with wide Unicode characters by using display width for cursor column calculations. (upstream PR #94)
  • Treat _ as part of words for word navigation/edit operations. (upstream PR #98)
  • Fix editor examples to preserve modified state across multiple inputs. (upstream PR #100)
  • Use portable-atomic for viewport atomics to improve target compatibility. (upstream PR #111)
  • Fix README wording for line-number default behavior. (upstream PR #116)

[0.7.1] - 2026-02-18 Changes

  • Update compatibility for ratatui v0.30.0.
  • Publish maintained fork under srothgan/tui-textarea.
  • Rename published crate to tui-textarea-2.
  • Add CI/collaboration baseline (workflows, templates, contributing guide).

[0.7.0] - 2024-10-22 Changes

[0.6.1] - 2024-08-08 Changes

  • Add TextArea::selection_range method to get the range of the current selection. Please read the document for more details. (#81, thanks @achristmascarl)
    let mut textarea = TextArea::from(["aaa"]);
    
    // It returns `None` when the text selection is not ongoing
    assert_eq!(textarea.selection_range(), None);
    
    textarea.start_selection();
    assert_eq!(textarea.selection_range(), Some(((0, 0), (0, 0))));
    
    textarea.move_cursor(CursorMove::Forward);
    assert_eq!(textarea.selection_range(), Some(((0, 0), (0, 1))));
    
    // The first element of the pair is always smaller than the second one.
    textarea.start_selection();
    textarea.move_cursor(CursorMove::Back);
    assert_eq!(textarea.selection_range(), Some(((0, 0), (0, 1))));
    
  • Fix depending on the incorrect version of termion crate when tuirs-termion feature is enabled. Since tui crate depends on older version of termion crate v1.5.6, tui-textarea should depend on the same version but actually it depended on the latest version v4.0.0.
    • If you use tui-textarea with tui crate and termion crate, please ensure that your project also depends on termion v1.5. Otherwise your project accidentally depends on multiple versions of termion crate.

[0.6.0] - 2024-08-07 Changes

  • BREAKING: Update ratatui crate dependency from v0.27 to v0.28.
  • BREAKING: Update crossterm crate dependency from v0.27 to v0.28 because ratatui crate depends on the new version.
    • Note: If you use tui crate, crossterm crate dependency remains at v0.25.

[0.5.3] - 2024-08-03 Changes

  • &TextArea now implements Widget trait. (#78)
    • Now the reference can be passed to ratatui::terminal::Frame::render_widget method call directly.
      // v0.5.2 or earlier
      f.render_widget(textarea.widget(), rect);
      
      // v0.5.3 or later
      f.render_widget(&textarea, rect);
      
    • This means that TextArea::widget method is no longer necessary. To maintain the compatibility the method is not removed but using it starts to report a deprecation warning from v0.5.3.
  • Fix a cursor can leave the viewport on horizontal scroll when line number is displayed. (#77)
  • Support some key combinations added at termion v4 for termion feature. (#68)
    • termion::event::Key::CtrlLeft
    • termion::event::Key::CtrlRight
    • termion::event::Key::CtrlUp
    • termion::event::Key::CtrlDown
    • termion::event::Key::CtrlHome
    • termion::event::Key::CtrlEnd
    • termion::event::Key::AltLeft
    • termion::event::Key::AltRight
    • termion::event::Key::AltUp
    • termion::event::Key::AltDown
    • termion::event::Key::ShiftLeft
    • termion::event::Key::ShiftRight
    • termion::event::Key::ShiftUp
    • termion::event::Key::ShiftDown
  • Fix the border color is not applied in single_line example. (#79, thanks @fmorroni)
  • Improve vim example's Vim emulation.
    • Fix the range of text selection on e mapping in operator-pending mode. (#76)
    • Fix the text selection on y, d, c mappings in visual mode is not inclusive.

[0.5.2] - 2024-08-01 Changes

  • Do not hide a cursor when a placeholder text is printed. (#73, thanks @kyu08)
    • demo
  • Add CursorMove::WordEnd which moves a cursor to the end of the next word inclusively. (#75, thanks @achristmascarl)
    • The behavior is similar to e mapping of Vim in normal mode. vim example implements the mapping for demonstration.

[0.5.1] - 2024-07-12 Changes

  • Add serde optional feature. When it is enabled, some types support the serialization/deserialization with serde crate. See the document for more details. (#62, thanks @cestef)
    use tui_textarea::Input;
    
    let json = r#"
        {
            "key": { "Char": "a" },
            "ctrl": true,
            "alt": false,
            "shift": true
        }
    "#;
    
    let input: Input = serde_json::from_str(json).unwrap();
    println!("{input}");
    // Input {
    //     key: Key::Char('a'),
    //     ctrl: true,
    //     alt: false,
    //     shift: true,
    // }
    

[0.5.0] - 2024-07-07 Changes

This is a maintenance release for supporting recent versions of ratatui crate.

  • BREAKING CHANGE: Bump the minimal versions of the following dependencies. If you're depending on the crates older than the following versions, please upgrade them before upgrading this crate. (#69, thanks @joshka)
    • ratatui 0.27.0
    • termion 0.4.0
    • termwiz 0.22.0
  • YankText now implements Display instead of ToString directly. Since ToString is implemented for any types which implement Display, this is not a breaking change.

[0.4.0] - 2023-11-19 Changes

This release introduces text selection feature. The internal implementation was largely refactored to handle multi-line text for this feature. As the side effect, several APIs now can handle a multi-line string (string contains newlines) correctly.

  • Text selection has been implemented. (#6, #45, thanks @pm100 for the first implementation) minimal example
    • Default key shortcuts now support text selection. When moving the cursor with pressing a shift key, a textarea starts to select the text under the cursor. The selected text can be copied/cut by the following key shortcuts. Modifying some text while text selection deletes the selected text. Doing undo/redo cancels the ongoing text selection.
      Mappings Description
      Ctrl+C, Copy Copy selected text
      Ctrl+X, Cut Cut selected text
    • The following APIs are added
      • TextArea::copy keeps the selected text as a yanked text
      • TextArea::cut deletes the selected text and keeps it as a yanked text
      • TextArea::start_selection starts text selection
      • TextArea::cancel_selection cancels text selection
      • TextArea::select_all selects the entire text
      • TextArea::set_selection_style sets the style of selected text
      • TextArea::selection_style returns the current style for selected text
  • BREAKING CHANGE: col argument of TextArea::delete_str was removed. Instead, current cursor position is used. This change is for aligninig the API signature with TextArea::insert_str.
    • Before: fn delete_str(&mut self, col: usize, chars: usize) -> bool
    • After: fn delete_str(&mut self, chars: usize) -> bool
  • BREAKING CHANGE: TextArea::yank_text now returns String instead of &str. This change was caused to handle yanking multiple-line text correctly.
    • Before: fn yank_text<'a>(&'a self) -> &'a str
    • After: fn yank_text(&self) -> String
  • BREAKING CHANGE: shift field was added to Input to support the Shift modifier key.
  • Add Key::Paste, Key::Copy, and Key::Cut. They are only supported by termwiz crate.
  • Fix TextArea::insert_char didn't handle newline ('\n') correctly.
  • Allow passing multi-line string to TextArea::insert_str. A string joined with newlines is inserted as multiple lines correctly.
  • Allow TextArea::delete_str to delete multiple lines (#42).
  • Fix TextArea::set_yank_text didn't handle multiple lines correctly.
  • Fix editor example didn't handle terminal raw mode on Windows (#44).
  • modal example was rebuilt as vim example. It implements Vim emulation to some level as a state machine. It adds the support for very basic visual mode and operator-pending mode. This example aims to show how to implement complicated and stateful key shortcuts.
  • Add many unit test cases. Several edge cases found by them were fixed. The code coverage of this crate reached 90%.

[0.3.1] - 2023-11-04 Changes

  • Fix the width of rendered tab character (\t) is wrong in some cases when hard tab is enabled by TextArea::set_hard_tab_indent (#43).
  • Fix key inputs are doubled on Windows when converting from crossterm::event::KeyEvent into tui_textarea::Input. Note that the conversion from crossterm::event::Event into tui_textarea::Input does not have this issue.
  • Support converting the following type instances into tui_textarea::Input.
    • crossterm::event::KeyCode
    • crossterm::event::KeyEvent
    • crossterm::event::MouseEvent
    • crossterm::event::MouseKind
    • termwiz::input::KeyCode
    • termwiz::input::KeyEvent
    • termion::event::MouseButton
  • Fix typos in API document and error message (#40, thanks @fritzrehde).

[0.3.0] - 2023-10-24 Changes

  • BREAKING CHANGE: Enable ratatui support by default instead of inactive tui-rs.
    • ratatui- prefix is removed from all ratatui-* features. crossterm, termion, and termwiz features are for ratatui:
      # ratatui with crossterm backend
      tui-textarea = "0.3"
      # ratatui with termwiz backend
      tui-textarea = { version = "0.3", features = ["termwiz"], default-features = false }
      # ratatui with termion backend
      tui-textarea = { version = "0.3", features = ["termion"], default-features = false }
      
    • Instead, features for tui-rs support are now prefixed with tuirs-:
      # tui-rs with crossterm backend
      tui-textarea = { version = "0.3", features = ["tuirs-crossterm"], default-features = false }
      # Use proper version of crossterm
      crossterm = "0.2.5"
      
    • Examples and documents are now implemented and described with ratatui by default
  • BREAKING CHANGE: Rename your-backend features to no-backend. You need to update the feature names if you're using tui-textarea with your own backend.
  • Relax the restriction of ratatui crate dependency from 0.23.0 to >=0.23.0, <1, which means 'v0.23.0 or later and earlier than v1'. The latest version of ratatui (v0.24.0) now works with tui-textarea (#36).
  • Enable termwiz and termion features on generating the API document. APIs to convert from input events of termwiz/termion to tui_textarea::Input are now listed in the document.

Previous Backend features table (v0.2.4):

crossterm termion termwiz Your own backend
tui-rs crossterm (enabled by default) termion N/A your-backend
ratatui ratatui-crossterm ratatui-termion ratatui-termwiz ratatui-your-backend

New backend features table (v0.3.0):

crossterm termion termwiz Your own backend
tui-rs tuirs-crossterm tuirs-termion N/A tuirs-no-backend
ratatui crossterm (enabled by default) termion termwiz no-backend

[0.2.4] - 2023-10-21 Changes

  • Support the ratatui's termwiz backend. ratatui-termwiz feature was newly added for this.
    • Add the following dependencies in your Cargo.toml to use termwiz support.
      termwiz = "0.20"
      ratatui = { version = "0.23", default-features = false, features = ["termwiz"] }
      tui-textarea = { version = "0.2.4", default-features = false, features = ["ratatui-termwiz"] }
      
    • Read and run the termwiz example to know the API usage.
      cargo run --example termwiz --no-default-features --features=ratatui-termwiz
      
  • Fix calculating the length of tab character when the line contains wide characters. Now the length of wide characters like あ are calculated as 2 correctly.

[0.2.3] - 2023-10-20 Changes

  • Add APIs to mask text with a character (#32, thanks @pm100).
    • TextArea::set_mask_char, TextArea::clear_mask_char, TextArea::mask_char are added. See the documentation for more details.
    • The password example was added to show the usage. password example
  • Fix the length of displayed hard tab in text (#33, thanks @pm100).

[0.2.2] - 2023-10-01 Changes

Very small patch release only for fixing the build failure on docs.rs. No implementation has been changed.

[0.2.1] - 2023-10-01 Changes

  • Add the support for ratatui crate in addition to tui-rs. The ratatui crate is a community fork of inactive tui-rs crate. (#12)
    • The latest version of ratatui v0.23 is supported.
    • tui-textarea still uses tui-rs by default to keep the compatibility at this moment. ratatui users explicitly need to set features for it. See the installation document for the features matrix. For example, when you want to use ratatui and crossterm, write the following in your Cargo.toml:
      [dependencies]
      ratatui = "*"
      tui-textarea = { version = "*", features = ["ratatui-crossterm"], default-features = false }
      
    • tui-rs is no longer maintained and the repository was archived. At the next minor version bump, tui-textarea will switch the default features from tui-rs to ratatui. If you use tui-rs, I recommend to switch your dependency to ratatui.
    • Examples with ratatui are added to the examples directory. For example, the following command runs ratatui version of editor example:
      cargo run --example ratatui_editor --no-default-features --features=ratatui-crossterm,search file.txt
      
  • Add support for the placeholder text which is rendered when no text is input in the textarea. (#16, thanks @pm100)
    • Use TextArea::set_placeholder_text to set the text. To change the text style, use TextArea::set_placeholder_style. See the API documentation for more details.
    • popup_placeholder example was added to show the usage.
      cargo run --example popup_placeholder
      
  • Derive Debug trait for TextArea struct. (#23)
  • Fix a key input is received twice on Windows. (#17, thanks @pm100)

[0.2.0] - 2022-10-18 Changes

  • Add Scrolling enum to provide more flexible scrolling via TextArea::scroll method. It has the following enum variants.
    • BREAKING Scrolling::Delta scrolls the textarea by given rows and cols. This variant can be converted from (i16, i16) so migrating from v0.1.6 is very easy.
      let rows: i16 = ...;
      let cols: i16 = ...;
      
      // Until v0.1.6
      textarea.scroll(rows, cols);
      
      // Since v0.2.0
      textarea.scroll((rows, cols));
      
    • Scrolling::PageDown and Scrolling::PageUp scroll the textarea by page.
    • Scrolling::HalfPageDown and Scrolling::HalfPageUp scroll the textarea by half-page.
  • Update default key mappings handled by TextArea::input method.
    • BREAKING Change PageDown and PageUp keys to scroll down/up the textarea by page since v0.2.0. Until v0.1.6, it moved the cursor down/up by one paragraph.
    • Add Ctrl+V and Alt+V keys to scroll down/up the textarea by page as Emacs-like key mappings.
    • Add Alt+] and Alt+[ keys to move the cursor down/up by one paragraph as Emacs-like key mappings.
  • BREAKING Add #[non_exhaustive] attribute to CursorMove enum. This is because more cursor move variations may be added in the future.
  • Fix panic when the max history size is zero (which means the edit history is disabled). (#4)

[0.1.6] - 2022-09-28 Changes

  • Support mouse scroll. (#2)
    • Handle mouse events for both crossterm and termion backends.
    • TextArea::scroll method was added.
    • Key::MouseScrollUp and Key::MouseScrollDown virtual keys are added to Key enum so that custom backends can support mouse scrolling.
    • CursorMove::InViewport variant was added to CursorMove enum, which ensures the cursor to be within the viewport.
  • Add TextArea::alignment and TextArea::set_alignment to set the text alignment of textarea. Note that right and center alignments don't work well with line number so calling TextArea::set_alignment with them automatically disables it. (#3, thanks @Volkalex28)
  • Set rust-version to 1.56.1 in Cargo.toml to show MSRV explicitly.

[0.1.5] - 2022-07-18 Changes

  • Improve performance to render a textarea widget. When number of lines increases, now rendering lines is about 2~8x faster according to our benchmark suites. See the commit for more details of the benchmark results. This was archived by managing a vertical scroll position by ourselves instead of scroll handling by Paragraph. Previously, a cost of rendering lines was O(n) where n was number of all lines. Now the cost is O(1).
  • Implement Clone for TextArea so that textarea instances can be copied easily. It is useful when you create multiple textarea instances with the same configuration. Create a first TextArea instance with configuring blocks and styles, then simply clone it.
  • Add arbitrary feature which is disabled by default. By enabling it, Input, Key and CursorMove can be randomly generated via arbitrary crate. This feature aims to be used by fuzzing tests.
  • Add many benchmark suites to track performance; insert/delete lines/characters, text search, moving a cursor.
  • Improve fuzzing tests to include rendering a textarea to a dummy terminal backend and moving a cursor randomly.
  • Refactor TextArea implementation. The implementation of text search was separated to src/search.rs. The implementation of highlighting was separated to src/highlight.rs. And the implementation of widget rendered by tui-rs was separated to src/widget.rs. These refactorings changed no public API.

[0.1.4] - 2022-07-10 Changes

  • Fix the cursor line style was not applied when a cursor is at the end of line.
  • Fix the cursor position after undoing the modification by 'delete until head of line' (^J by default).

[0.1.3] - 2022-07-08 Changes

  • Text search was implemented. Text search is gated behind search feature flag to avoid depending on regex crate until it is necessary. See the usage document, the API document, and the working example for more details.
    • TextArea::set_search_pattern sets a search pattern in regular expression. This updates highlights at matches in textarea, but does not move the cursor.
    • TextArea::search_forward moves cursor to the next match of the text search based on current cursor position.
    • TextArea::search_back moves cursor to the previous match of the text search based on current cursor position.
    • TextArea::set_search_style sets the text style for highlighting matches of text search. search in editor example

[0.1.2] - 2022-06-25 Changes

  • Indent with hard tab is now supported. TextArea::set_hard_tab_indent method enables indentation with a hard tab on hitting a tab key.
    let mut textarea = TextArea::default();
    
    textarea.set_hard_tab_indent(true);
    textarea.insert_tab();
    assert_eq!(textarea.lines(), ["\t"]);
    
    Demo with cargo run --example editor: screencast
  • Add TextArea::indent method to get an indent string of textarea.
    let mut textarea = TextArea::default();
    
    assert_eq!(textarea.indent(), "    ");
    textarea.set_tab_length(2);
    assert_eq!(textarea.indent(), "  ");
    textarea.set_hard_tab_indent(true);
    assert_eq!(textarea.indent(), "\t");
    

[0.1.1] - 2022-06-21 Changes

  • Add TextArea::yank_text and TextArea::set_yank_text to set/get yanked text of the textarea.
    let mut textarea = TextArea::default();
    textarea.set_yank_text("hello, world");
    assert_eq!(textarea.yank_text(), "hello, world");
    textarea.paste();
    assert_eq!(textarea.lines(), ["hello, world"]);
    
  • Add CursorMove::Jump(row, col) variant to move cursor to arbitrary (row, col) position with TextArea::move_cursor.
    let mut textarea = TextArea::from(["aaaa", "bbbb"]);
    textarea.move_cursor(CursorMove::Jump(1, 2));
    assert_eq!(textarea.cursor(), (1, 2));
    
  • Fix hard tabs are not rendered (#1)

[0.1.0] - 2022-06-19 Changes

First release 🎉