[][src]Crate xrl

xrl is a Tokio based library to build clients for the Xi editor. The challenge with Xi RPC is that endpoints are both client (sending requests/notifications) and server (handling incoming requests/notifications).

extern crate futures;
extern crate tokio;
extern crate xrl;

use futures::{future, Future, Stream};
use xrl::*;

// Type that represent a `xi-core` peer. It implements `Frontend`,
// which means it can handle notifications and requests from
// `xi-core`.
#[allow(dead_code)]
struct MyFrontend {
    // This is not actually used in this example, but if we wanted to
    // our frontend could use a `Client` so that it could send
    // requests and notifications to `xi-core`, instead of just
    // handling incoming messages.
    client: Client,
}

// Implement how our client handles notifications & requests from the core.
impl Frontend for MyFrontend {
    type NotificationResult = Result<(), ()>;
    fn handle_notification(&mut self, notification: XiNotification) -> Self::NotificationResult {
        use XiNotification::*;
        match notification {
            Update(update) => println!("received `update` from Xi core:\n{:?}", update),
            ScrollTo(scroll) => println!("received `scroll_to` from Xi core:\n{:?}", scroll),
            DefStyle(style) => println!("received `def_style` from Xi core:\n{:?}", style),
            AvailablePlugins(plugins) => {
                println!("received `available_plugins` from Xi core:\n{:?}", plugins)
            }
            UpdateCmds(cmds) => println!("received `update_cmds` from Xi core:\n{:?}", cmds),
            PluginStarted(plugin) => {
                println!("received `plugin_started` from Xi core:\n{:?}", plugin)
            }
            PluginStoped(plugin) => {
                println!("received `plugin_stoped` from Xi core:\n{:?}", plugin)
            }
            ConfigChanged(config) => {
                println!("received `config_changed` from Xi core:\n{:?}", config)
            }
            ThemeChanged(theme) => println!("received `theme_changed` from Xi core:\n{:?}", theme),
            Alert(alert) => println!("received `alert` from Xi core:\n{:?}", alert),
            AvailableThemes(themes) => {
                println!("received `available_themes` from Xi core:\n{:?}", themes)
            }
            FindStatus(status) => println!("received `find_status` from Xi core:\n{:?}", status),
            ReplaceStatus(status) => {
                println!("received `replace_status` from Xi core:\n{:?}", status)
            }
            AvailableLanguages(langs) => {
                println!("received `available_languages` from Xi core:\n{:?}", langs)
            }
            LanguageChanged(lang) => {
                println!("received `language_changed` from Xi core:\n{:?}", lang)
            }
        }
        Ok(())
    }

    type MeasureWidthResult = Result<Vec<Vec<f32>>, ()>;
    // we don't actually use the `request` argument in this example,
    // hence the attribute.
    #[allow(unused_variables)]
    fn handle_measure_width(&mut self, request: MeasureWidth) -> Self::MeasureWidthResult {
        Ok(Vec::new())
    }
}

struct MyFrontendBuilder;

impl FrontendBuilder for MyFrontendBuilder {
    type Frontend = MyFrontend;
    fn build(self, client: Client) -> Self::Frontend {
        MyFrontend { client }
    }
}

fn main() {
    tokio::run(future::lazy(move || {
        // spawn Xi core
        let (client, core_stderr) = spawn("xi-core", MyFrontendBuilder {}).unwrap();

        // start logging Xi core's stderr
        tokio::spawn(
            core_stderr
                .for_each(|msg| {
                    println!("xi-core stderr: {}", msg);
                    Ok(())
                })
                .map_err(|_| ()),
        );

        let client_clone = client.clone();
        client
            // Xi core expects the first notification to be
            // "client_started"
            .client_started(None, None)
            .map_err(|e| eprintln!("failed to send \"client_started\": {:?}", e))
            .and_then(move |_| {
                let client = client_clone.clone();
                client
                    .new_view(None)
                    .map(|view_name| println!("opened new view: {}", view_name))
                    .map_err(|e| eprintln!("failed to open a new view: {:?}", e))
                    .and_then(move |_| {
                        // Forces to shut down the Xi-RPC
                        // endoint. Otherwise, this example would keep
                        // running until the xi-core process
                        // terminates.
                        println!("shutting down");
                        client_clone.shutdown();
                        Ok(())
                    })
            })
    }));
}

Structs

Alert
AvailableLanguages
AvailablePlugins
AvailableThemes
Client

A client to send notifications and request to xi-core.

ConfigChanged
ConfigChanges
CoreStderr

A stream of Xi core stderr lines

FindStatus
LanguageChanged
Line
LineCache

Line cache struct to work with xi update protocol.

MeasureWidth
Operation
PluginStarted
PluginStoped
Position
Query
ReplaceStatus
ScrollTo
Status
Style
StyleDef
ThemeChanged
Update
UpdateCmds
ViewId

Enums

ClientError
ModifySelection
OperationType
ServerError
XiNotification

Represents all possible RPC messages recieved from xi-core.

Traits

Frontend

The Frontend trait must be implemented by clients. It defines how the client handles notifications and requests coming from xi-core.

FrontendBuilder

A trait to build a type that implements Frontend.

IntoStaticFuture

Class of types which can be converted into a future. This trait is only differs from futures::future::IntoFuture in that the returned future has the 'static lifetime.

Functions

spawn

Start Xi core, and spawn an RPC client on the current tokio executor.

Type Definitions

ThemeSettings