#modal #readline #tui #vim

modalkit

A library for building applications that use modal editing

10 releases

0.0.10 Jan 23, 2023
0.0.9 Jan 6, 2023
0.0.7 Dec 28, 2022
0.0.5 Oct 2, 2022
0.0.1 Aug 25, 2021

#209 in Command-line interface

Download history 2/week @ 2022-10-09 4/week @ 2022-10-23 5/week @ 2022-11-13 6/week @ 2022-11-20 1/week @ 2022-12-04 33/week @ 2022-12-11 1/week @ 2022-12-18 46/week @ 2022-12-25 82/week @ 2023-01-01 47/week @ 2023-01-08 10/week @ 2023-01-15 79/week @ 2023-01-22

221 downloads per month
Used in iamb

Apache-2.0

1.5MB
33K SLoC

modalkit

Build Status License: Apache 2.0 Latest Version Docs Status

About

This is a Rust library for building modal editing applications.

Usage

This crate is on crates.io and can be used by adding modalkit to your dependencies in your project's Cargo.toml.

[dependencies]
modalkit = "0.0.6"

License

modalkit is released under the Apache License, Version 2.0.


lib.rs:

modalkit

Overview

This crate allows building terminal applications that support modal input, such as the Vim text editor.

Example

The following example shows a program that opens a single textbox where the user can enter text using Vim keybindings.

For a more complete example that includes a command bar and window splitting, see examples/editor.rs in the source repository.

use modalkit::{
    editing::{context::Resolve, key::KeyManager, store::Store},
    editing::action::{Action, Editable, Jumpable, Scrollable, UIResult},
    editing::application::EmptyInfo,
    env::vim::keybindings::VimMachine,
    input::{bindings::BindingMachine, key::TerminalKey},
    widgets::textbox::{TextBoxState, TextBox},
    widgets::TerminalExtOps,
};

use modalkit::crossterm::event::{read, Event};
use modalkit::crossterm::terminal::EnterAlternateScreen;
use modalkit::tui::{backend::CrosstermBackend, Terminal};
use std::io::stdout;

fn main() -> UIResult<(), EmptyInfo> {
    let mut stdout = stdout();

    crossterm::terminal::enable_raw_mode()?;
    crossterm::execute!(stdout, EnterAlternateScreen)?;

    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;
    let mut store = Store::default();
    let mut bindings = KeyManager::new(VimMachine::<TerminalKey>::default());
    let mut tbox = TextBoxState::new(store.load_buffer(String::from("*scratch*")));

    terminal.clear()?;

    loop {
        terminal.draw(|f| f.render_stateful_widget(TextBox::new(), f.size(), &mut tbox))?;

        if let Event::Key(key) = read()? {
            bindings.input_key(key.into());
        } else {
            continue;
        };

        while let Some((act, ctx)) = bindings.pop() {
            let store = &mut store;

            let _ = match act {
                Action::Editor(act) => tbox.editor_command(&act, &ctx, store)?,
                Action::Macro(act) => bindings.macro_command(&act, &ctx, store)?,
                Action::Scroll(style) => tbox.scroll(&style, &ctx, store)?,
                Action::Repeat(rt) => {
                    bindings.repeat(rt, Some(ctx));
                    None
                },
                Action::Jump(l, dir, count) => {
                    let _ = tbox.jump(l, dir, ctx.resolve(&count), &ctx)?;
                    None
                },
                Action::Suspend => terminal.program_suspend()?,
                Action::NoOp => None,
                _ => continue,
            };
        }
    }
}

Dependencies

~3–8.5MB
~159K SLoC