MCPcopy Index your code
hub / github.com/Harzu/iced_term

github.com/Harzu/iced_term @0.8.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release 0.8.0 ↗ · + Follow
200 symbols 312 edges 15 files 2 documented · 1%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

iced_term

GitHub License Crates.io Downloads (recent) crates.io docs.rs Rust CI

Terminal emulator widget powered by ICED framework and alacritty terminal backend.

Unstable widget API

The ICED framework does not have the stable API and this widget is also under development, so I can not promise the stable API and to document it at least while the ICED won't release the 1.0.0 version.

Features

The widget is currently under development and does not provide full terminal features make sure that widget is covered everything you want.

  • PTY content rendering (msgcat --color=test)
  • Multiple instance support
  • Basic keyboard input
  • Mouse interaction in different modes
  • Adding custom keyboard or mouse bindings
  • Resizing
  • Scrolling
  • Focusing
  • Selecting
  • Changing Font/Color scheme
  • Hyperlinks processing (hover/open)

This widget was tested on MacOS, Linux and Windows.

Installation

From crates.io

iced_term = "0.8.0"

From git

iced_term = { git = "https://github.com/Harzu/iced_term", branch = "master" }

Overview

Interacting with the widget is happened via:

Commands - you can send commands to widget for changing the widget state.

#[derive(Debug, Clone)]
pub enum Command {
    ChangeTheme(Box<ColorPalette>),
    ChangeFont(FontSettings),
    AddBindings(Vec<(Binding<InputKind>, BindingAction)>),
    ProxyToBackend(backend::Command),
}

Events - widget is produced some events that can be handled in application. Every event has the first u64 argument that is terminal instance id.

#[derive(Debug, Clone)]
pub enum Event {
    BackendCall(u64, backend::Command),
}

Right now there is the only internal CommandReceived event that is needed for backend <-> view communication. You can also handle this event unwrap the command and process command additionally if you want.

Actions - widget's method update(&mut self, cmd: Command) returns Action that you can handle after widget updated.

#[derive(Debug, Clone, PartialEq, Default)]
pub enum Action {
    Shutdown,
    ChangeTitle,
    #[default]
    Ignore,
}

For creating workable application example with this widget you need to do a several things

Step 1. Add widget to your App struct

struct App {
    title: String,
    term: iced_term::Terminal,
}

Step 2. Create instance in App constructor

impl App {
    fn new() -> (Self, Task<Event>) {
        let system_shell = std::env::var("SHELL")
            .expect("SHELL variable is not defined")
            .to_string();
        let term_id = 0;
        let term_settings = iced_term::settings::Settings {
            backend: iced_term::settings::BackendSettings {
                shell: system_shell.to_string(),
                ..Default::default()
            },
            ..Default::default()
        };

        (
            Self {
                title: String::from("Terminal app"),
                term: iced_term::Terminal::new(term_id, term_settings)
                    .expect("failed to create the new terminal instance"),
            },
            Task::none(),
        )
    }
}

Step 3. Add event kind to Events/Messages enum that will be container of internal widget events for application's Events/Messages. You will have to wrap inner widget events via .map(Event::Terminal) where it's necessary.

#[derive(Debug, Clone)]
pub enum Event {
    // ... other events
    Terminal(iced_term::Event),
}

Step 4. Add Terminal event kind processing to application update method.

impl App {
    // ... other methods
    fn update(&mut self, event: Event) -> Task<Event> {
        match event {
            Event::Terminal(iced_term::Event::BackendCall(_, cmd)) => {
                match self.term.handle(iced_term::Command::ProxyToBackend(cmd))
                {
                    iced_term::actions::Action::Shutdown => {
                        return window::latest().and_then(window::close)
                    },
                    _ => {},
                }
            },
        }

        Task::none()
    }
}

Step 5. Add view to your application

impl App {
    // ... other methods
    fn view(&self) -> Element<Event, Theme, iced::Renderer> {
        container(iced_term::TerminalView::show(&self.term).map(Event::Terminal))
            .width(Length::Fill)
            .height(Length::Fill)
            .into()
    }
}

Step 6. Add event subscription for getting internal events from backend (pty).

impl App {
    // ... other methods
    fn subscription(&self) -> Subscription<Event> {
        self.term.subscription().map(Event::Terminal)
    }
}

Step 7. Add main function

fn main() -> iced::Result {
    iced::application(App::new, App::update, App::view)
        .title(App::title)
        .window_size(Size {
            width: 1280.0,
            height: 720.0,
        })
        .subscription(App::subscription)
        .run()
}

Step 8. Run your application

cargo run --release

Step 9. To be happy!

Examples

You can also look at examples directory for more information about widget using.

  • full_screen - The basic example of terminal emulator.
  • split_view - The example based on split_view iced widget that show how multiple instance feature work.
  • custom_bindings - The example that show how you can add custom keyboard or mouse bindings to your terminal emulator app.
  • themes - The example that show how you can change terminal color scheme.
  • fonts - The examples that show how you can change font type or font size in your terminal emulator app.
  • focus - The example that show that focus between iced widgets and iced_term works correctly

You can run any example via

cargo run --package <example name>

Dependencies

dependency status

Contributing / Feedback

All feedbacks, issues and pull requests are welcomed! Guidelines is coming soon =)

Extension points exported contracts — how you extend this code

TerminalStyle (Interface)
(no doc) [1 implementers]
src/theme.rs

Core symbols most depended-on inside this repo

handle
called by 12
src/backend.rs
add_bindings
called by 8
src/bindings.rs
renderable_content
called by 7
src/backend.rs
get_color
called by 5
src/theme.rs
get_action
called by 5
src/bindings.rs
size
called by 4
src/view.rs
is_focused
called by 4
src/view.rs
build
called by 4
src/view.rs

Shape

Method 114
Function 45
Class 25
Enum 15
Interface 1

Languages

Rust100%

Modules by API surface

src/view.rs53 symbols
src/backend.rs37 symbols
src/bindings.rs17 symbols
examples/split_view/src/main.rs15 symbols
src/theme.rs14 symbols
src/terminal.rs13 symbols
examples/themes/src/main.rs8 symbols
examples/full_screen/src/main.rs8 symbols
examples/fonts/src/main.rs8 symbols
examples/focus/src/main.rs8 symbols
examples/custom_bindings/src/main.rs8 symbols
src/settings.rs6 symbols

For agents

$ claude mcp add iced_term \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact