1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! `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).
//!
//!
//! ```rust
//! 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(())
//!                     })
//!             })
//!     }));
//! }
//! ```

#![deny(clippy::all)]
#![allow(clippy::type_complexity)]

#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate serde_json;

mod cache;
mod client;
mod core;
mod errors;
mod frontend;
mod protocol;
mod structs;

pub use crate::cache::LineCache;
pub use crate::client::Client;
pub use crate::core::{spawn, CoreStderr};
pub use crate::errors::{ClientError, ServerError};
pub use crate::frontend::{Frontend, FrontendBuilder, XiNotification};
pub use crate::protocol::IntoStaticFuture;
pub use crate::structs::{
    Alert, AvailableLanguages, AvailablePlugins, AvailableThemes, ConfigChanged, ConfigChanges,
    FindStatus, LanguageChanged, Line, MeasureWidth, ModifySelection, Operation, OperationType,
    PluginStarted, PluginStoped, Position, Query, ReplaceStatus, ScrollTo, Status, Style, StyleDef,
    ThemeChanged, ThemeSettings, Update, UpdateCmds, ViewId,
};