# iced_term [![GitHub License][license-badge]][license-link] ![Crates.io Downloads (recent)](https://img.shields.io/crates/dr/iced_term) [![crates.io][crates.io-badge]][crates.io-link] [![docs.rs][docs.rs-badge]][docs.rs-link] [![Rust CI][ci-badge]][ci-link] 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](./docs/colortest)) - 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 ```toml iced_term = "0.8.0" ``` From git ```toml 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. ```rust #[derive(Debug, Clone)] pub enum Command { ChangeTheme(Box), ChangeFont(FontSettings), AddBindings(Vec<(Binding, 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**. ```rust #[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. ```rust #[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 ```rust struct App { title: String, term: iced_term::Terminal, } ``` **Step 2.** Create instance in `App` constructor ```rust impl App { fn new() -> (Self, Task) { 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. ```rust #[derive(Debug, Clone)] pub enum Event { // ... other events Terminal(iced_term::Event), } ``` **Step 4.** Add **Terminal** event kind processing to application `update` method. ```rust impl App { // ... other methods fn update(&mut self, event: Event) -> Task { 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 ```rust impl App { // ... other methods fn view(&self) -> Element { 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). ```rust impl App { // ... other methods fn subscription(&self) -> Subscription { self.term.subscription().map(Event::Terminal) } } ``` **Step 7.** Add main function ```rust 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 ```shell cargo run --release ``` **Step 9.** To be happy! ## Examples You can also look at [examples](./examples) directory for more information about widget using. - [full_screen](./examples/full_screen/) - The basic example of terminal emulator. - [split_view](./examples/split_view/) - The example based on split_view iced widget that show how multiple instance feature work. - [custom_bindings](./examples/custom_bindings/) - The example that show how you can add custom keyboard or mouse bindings to your terminal emulator app. - [themes](./examples/themes/) - The example that show how you can change terminal color scheme. - [fonts](./examples/fonts/) - The examples that show how you can change font type or font size in your terminal emulator app. - [focus](./examples/focus/) - The example that show that focus between iced widgets and iced_term works correctly You can run any example via ```shell cargo run --package ``` ## Dependencies [![dependency status][deps.rs-badge]][deps.rs-link] - [alacritty_terminal](https://github.com/alacritty/alacritty) (Apache-2.0) - [anyhow](https://github.com/dtolnay/anyhow) (MIT OR Apache-2.0) - [iced](https://github.com/iced-rs/iced) (MIT) - [iced_core](https://github.com/iced-rs/iced) (MIT) - [iced_graphics](https://github.com/iced-rs/iced) (MIT) - [open](https://github.com/Byron/open-rs) (MIT) - [tokio](https://github.com/tokio-rs/tokio) (MIT) ## Contributing / Feedback All feedbacks, issues and pull requests are welcomed! Guidelines is coming soon =) [license-badge]: https://img.shields.io/github/license/Harzu/iced_term [license-link]: https://github.com/Harzu/iced_term/blob/main/LICENSE [crates.io-badge]: https://img.shields.io/crates/v/iced_term [crates.io-link]: https://crates.io/crates/iced_term [docs.rs-badge]: https://img.shields.io/docsrs/iced_term [docs.rs-link]: https://docs.rs/iced_term [ci-badge]: https://github.com/Harzu/iced_term/actions/workflows/rust.yml/badge.svg [ci-link]: https://github.com/Harzu/iced_term/actions/workflows/rust.yml [deps.rs-badge]: https://img.shields.io/deps-rs/iced_term/latest?style=for-the-badge&label=dependency%20status [deps.rs-link]: https://deps.rs/crate/iced_term