├── .github ├── README.png └── python.png ├── src ├── widgets │ ├── view │ │ ├── mod.rs │ │ ├── cfg.rs │ │ ├── style.rs │ │ ├── window.rs │ │ ├── client.rs │ │ └── view.rs │ ├── mod.rs │ ├── command_prompt.rs │ └── editor.rs ├── core │ ├── mod.rs │ ├── cmd.rs │ ├── terminal.rs │ └── tui.rs └── main.rs ├── Cargo.toml ├── .travis.yml ├── .gitignore ├── LICENSE ├── README.md └── Cargo.lock /.github/README.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xi-frontend/xi-term/HEAD/.github/README.png -------------------------------------------------------------------------------- /.github/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xi-frontend/xi-term/HEAD/.github/python.png -------------------------------------------------------------------------------- /src/widgets/view/mod.rs: -------------------------------------------------------------------------------- 1 | mod cfg; 2 | mod client; 3 | mod style; 4 | #[allow(clippy::module_inception)] 5 | mod view; 6 | mod window; 7 | 8 | pub use self::client::Client as ViewClient; 9 | pub use self::view::View; 10 | -------------------------------------------------------------------------------- /src/core/mod.rs: -------------------------------------------------------------------------------- 1 | mod terminal; 2 | pub use self::terminal::{RenderTarget, Terminal, TerminalEvent}; 3 | 4 | mod tui; 5 | pub use self::tui::{CoreEvent, Tui, TuiService, TuiServiceBuilder}; 6 | 7 | mod cmd; 8 | pub use self::cmd::{Command, ParseCommandError}; 9 | -------------------------------------------------------------------------------- /src/widgets/mod.rs: -------------------------------------------------------------------------------- 1 | /// A widget is something that can be displayed on screen 2 | mod view; 3 | pub use self::view::View; 4 | pub use self::view::ViewClient; 5 | 6 | mod editor; 7 | pub use self::editor::Editor; 8 | 9 | mod command_prompt; 10 | pub use self::command_prompt::CommandPrompt; 11 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Corentin Henry "] 3 | name = "xi-term" 4 | version = "0.1.0" 5 | 6 | [dependencies] 7 | clap = "2.33.0" 8 | failure = "0.1.5" 9 | futures = "0.1.27" 10 | log = "0.4.6" 11 | log4rs = "0.8.3" 12 | termion = "1.5.3" 13 | tokio = "0.1.21" 14 | xdg = "2.2.0" 15 | indexmap = "1.0.2" 16 | xrl = "0.0.8" 17 | -------------------------------------------------------------------------------- /src/widgets/view/cfg.rs: -------------------------------------------------------------------------------- 1 | pub struct ViewConfig { 2 | // Gutter Settings 3 | pub display_gutter: bool, 4 | pub gutter_size: u16, 5 | // Tab Settings 6 | pub tab_size: u16, 7 | } 8 | 9 | impl Default for ViewConfig { 10 | fn default() -> ViewConfig { 11 | ViewConfig { 12 | display_gutter: true, 13 | gutter_size: 0, 14 | tab_size: 4, 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: [stable, beta, nightly] 3 | cache: cargo 4 | 5 | before_script: 6 | - bash -c 'if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]] ; then rustup component add clippy-preview --toolchain=nightly ; fi' 7 | 8 | script: 9 | - bash -c 'if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]] ; then cargo clippy ; else cargo build ; fi' 10 | 11 | matrix: 12 | allow_failures: 13 | - rust: nightly 14 | fast_finish: true 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Numerous always-ignore extensions 2 | *.bak 3 | *.diff 4 | *.err 5 | *.orig 6 | *.log 7 | *.rej 8 | *.swo 9 | *.swp 10 | *.vi 11 | *~ 12 | 13 | # OS or Editor folders 14 | .DS_Store 15 | ._* 16 | Thumbs.db 17 | .cache 18 | .project 19 | .settings 20 | .tmproj 21 | nbproject 22 | *.sublime-project 23 | *.sublime-workspace 24 | 25 | # Generated by Cargo 26 | # will have compiled files and executables 27 | /target/ 28 | 29 | # These are backup files generated by rustfmt 30 | **/*.rs.bk 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Corentin Henry 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/widgets/view/style.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Write; 2 | use termion; 3 | use termion::color; 4 | use xrl::Style; 5 | 6 | use failure::Error; 7 | 8 | fn get_color(argb_color: u32) -> color::Rgb { 9 | let r = ((argb_color & 0x00ff_0000) >> 16) as u8; 10 | let g = ((argb_color & 0x0000_ff00) >> 8) as u8; 11 | let b = (argb_color & 0x0000_00ff) as u8; 12 | color::Rgb(r, g, b) 13 | } 14 | 15 | pub fn set_style(style: &Style) -> Result { 16 | if style.id == 0 { 17 | return Ok(format!("{}", termion::style::Invert)); 18 | } 19 | 20 | let mut s = String::new(); 21 | 22 | if let Some(fg_color) = style.fg_color { 23 | write!(&mut s, "{}", color::Fg(get_color(fg_color)))?; 24 | } 25 | 26 | if let Some(bg_color) = style.bg_color { 27 | if bg_color != 0 { 28 | write!(&mut s, "{}", color::Bg(get_color(bg_color)))?; 29 | } 30 | } 31 | 32 | if let Some(italic) = style.italic { 33 | if italic { 34 | write!(&mut s, "{}", termion::style::Italic)?; 35 | } 36 | } 37 | 38 | if let Some(underline) = style.underline { 39 | if underline { 40 | write!(&mut s, "{}", termion::style::Underline)?; 41 | } 42 | } 43 | 44 | Ok(s) 45 | } 46 | 47 | pub fn reset_style(style: &Style) -> Result { 48 | if style.id == 0 { 49 | return Ok(format!("{}", termion::style::NoInvert)); 50 | } 51 | 52 | let mut s = String::new(); 53 | 54 | if style.fg_color.is_some() { 55 | write!(&mut s, "{}", color::Fg(color::Reset))?; 56 | } 57 | 58 | if let Some(bg_color) = style.bg_color { 59 | if bg_color != 0 { 60 | write!(&mut s, "{}", color::Bg(color::Reset))?; 61 | } 62 | } 63 | 64 | if let Some(italic) = style.italic { 65 | if italic { 66 | write!(&mut s, "{}", termion::style::NoItalic)?; 67 | } 68 | } 69 | 70 | if let Some(underline) = style.underline { 71 | if underline { 72 | write!(&mut s, "{}", termion::style::NoUnderline)?; 73 | } 74 | } 75 | Ok(s) 76 | } 77 | -------------------------------------------------------------------------------- /src/widgets/command_prompt.rs: -------------------------------------------------------------------------------- 1 | //! Command prompt for xi-term. currently this is 2 | //! heavily inspired by vim and is just designed to 3 | //! get a simple base to work off of. 4 | 5 | use std::io::Error; 6 | use std::io::Write; 7 | use termion::event::{Event, Key}; 8 | 9 | use core::{Command, ParseCommandError}; 10 | use termion::clear::CurrentLine as ClearLine; 11 | use termion::cursor::Goto; 12 | 13 | use std::str::FromStr; 14 | 15 | #[derive(Debug, Default)] 16 | pub struct CommandPrompt { 17 | dex: usize, 18 | chars: String, 19 | } 20 | 21 | impl CommandPrompt { 22 | /// Process a terminal event for the command prompt. 23 | pub fn handle_input(&mut self, input: &Event) -> Result, ParseCommandError> { 24 | match input { 25 | Event::Key(Key::Char('\n')) => self.finalize(), 26 | Event::Key(Key::Backspace) | Event::Key(Key::Ctrl('h')) => Ok(self.back()), 27 | Event::Key(Key::Delete) => Ok(self.delete()), 28 | Event::Key(Key::Left) => Ok(self.left()), 29 | Event::Key(Key::Right) => Ok(self.right()), 30 | Event::Key(Key::Char(chr)) => Ok(self.new_key(*chr)), 31 | _ => Ok(None), 32 | } 33 | } 34 | 35 | fn left(&mut self) -> Option { 36 | if self.dex > 0 { 37 | self.dex -= 1; 38 | } 39 | None 40 | } 41 | 42 | fn right(&mut self) -> Option { 43 | if self.dex < self.chars.len() { 44 | self.dex += 1; 45 | } 46 | None 47 | } 48 | 49 | fn delete(&mut self) -> Option { 50 | if self.dex < self.chars.len() { 51 | self.chars.remove(self.dex); 52 | } 53 | None 54 | } 55 | 56 | fn back(&mut self) -> Option { 57 | if !self.chars.is_empty() { 58 | self.dex -= 1; 59 | self.chars.remove(self.dex); 60 | None 61 | } else { 62 | Some(Command::Cancel) 63 | } 64 | } 65 | 66 | /// Gets called when any character is pressed. 67 | fn new_key(&mut self, chr: char) -> Option { 68 | self.chars.insert(self.dex, chr); 69 | self.dex += 1; 70 | None 71 | } 72 | 73 | /// Gets called when return is pressed, 74 | fn finalize(&mut self) -> Result, ParseCommandError> { 75 | Ok(Some(FromStr::from_str(&self.chars)?)) 76 | } 77 | 78 | pub fn render(&mut self, w: &mut W, row: u16) -> Result<(), Error> { 79 | if let Err(err) = write!( 80 | w, 81 | "{}{}:{}{}", 82 | Goto(1, row), 83 | ClearLine, 84 | self.chars, 85 | Goto(self.dex as u16 + 2, row) 86 | ) { 87 | error!("faile to render status bar: {:?}", err); 88 | } 89 | Ok(()) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/widgets/view/window.rs: -------------------------------------------------------------------------------- 1 | use super::view::Cursor; 2 | 3 | #[derive(Clone, Debug)] 4 | pub struct Window { 5 | start: u64, 6 | size: u16, 7 | } 8 | 9 | impl Window { 10 | pub fn new() -> Self { 11 | Window { start: 0, size: 0 } 12 | } 13 | 14 | pub fn set_cursor(&mut self, cursor: &Cursor) { 15 | info!("Setting cursor to {:?}", cursor); 16 | if cursor.line < self.start() { 17 | self.start = cursor.line; 18 | } else if cursor.line >= self.end() { 19 | self.start = 1 + cursor.line - u64::from(self.size); 20 | } 21 | info!("new window: {:?}", self); 22 | } 23 | 24 | pub fn resize(&mut self, height: u16) { 25 | self.size = height; 26 | } 27 | 28 | pub fn update(&mut self, cursor: u64, nb_line: u64) { 29 | info!( 30 | "resizing window: height={}, cursor={}, nb_line={}", 31 | self.size, cursor, nb_line 32 | ); 33 | 34 | // We have no way to know if the screen was resized from the top or the bottom, so we 35 | // balance the change between both end. Basically we want: 36 | // 1) new_height = new_end - new_start 37 | // 2) new_end - old_end = new_start - old_start 38 | // which leads to: 39 | // 1) new_end = (new_height + old_start + old_end) / 2 40 | // 2) new_start = (old_start + old_end - new_height) / 2 41 | let mut new_start = if u64::from(self.size) > self.start() + self.end() { 42 | // Of course, new_start must be >=0, so we have this special case: 43 | 0 44 | } else { 45 | (self.start() + self.end() - u64::from(self.size)) / 2 46 | }; 47 | 48 | // Handle a first corner case where the previous operation gave us a window that end after 49 | // the last line. We don't want to waste this space, so we translate the window so that the 50 | // last line correspond to the end of the window. 51 | if new_start + u64::from(self.size) > nb_line { 52 | if nb_line < u64::from(self.size) { 53 | new_start = 0; 54 | } else { 55 | new_start = nb_line - u64::from(self.size); 56 | } 57 | } 58 | 59 | // Handle a second corner case where the previous operations left the cursor out of scope. 60 | // We want to keep the cursor in the window. 61 | if cursor < new_start { 62 | new_start = cursor; 63 | } else if cursor > new_start + u64::from(self.size) { 64 | new_start = cursor - u64::from(self.size); 65 | } 66 | 67 | self.start = new_start; 68 | info!("done resizing the window: {:?}", self); 69 | } 70 | 71 | pub fn size(&self) -> u16 { 72 | self.size 73 | } 74 | 75 | pub fn start(&self) -> u64 { 76 | self.start 77 | } 78 | 79 | pub fn end(&self) -> u64 { 80 | u64::from(self.size) + self.start 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/widgets/view/client.rs: -------------------------------------------------------------------------------- 1 | use futures::Future; 2 | use tokio::spawn; 3 | use xrl; 4 | 5 | pub struct Client { 6 | inner: xrl::Client, 7 | view_id: xrl::ViewId, 8 | } 9 | 10 | impl Client { 11 | pub fn new(client: xrl::Client, view_id: xrl::ViewId) -> Self { 12 | Client { 13 | inner: client, 14 | view_id, 15 | } 16 | } 17 | 18 | pub fn insert(&mut self, character: char) { 19 | let f = self.inner.char(self.view_id, character).map_err(|_| ()); 20 | spawn(f); 21 | } 22 | 23 | pub fn insert_newline(&mut self) { 24 | let f = self.inner.insert_newline(self.view_id).map_err(|_| ()); 25 | spawn(f); 26 | } 27 | 28 | pub fn insert_tab(&mut self) { 29 | let f = self.inner.insert_tab(self.view_id).map_err(|_| ()); 30 | spawn(f); 31 | } 32 | 33 | pub fn scroll(&mut self, start: u64, end: u64) { 34 | let f = self.inner.scroll(self.view_id, start, end).map_err(|_| ()); 35 | spawn(f); 36 | } 37 | 38 | pub fn down(&mut self) { 39 | let f = self.inner.down(self.view_id).map_err(|_| ()); 40 | spawn(f); 41 | } 42 | 43 | pub fn up(&mut self) { 44 | let f = self.inner.up(self.view_id).map_err(|_| ()); 45 | spawn(f); 46 | } 47 | 48 | pub fn right(&mut self) { 49 | let f = self.inner.right(self.view_id).map_err(|_| ()); 50 | spawn(f); 51 | } 52 | 53 | pub fn left(&mut self) { 54 | let f = self.inner.left(self.view_id).map_err(|_| ()); 55 | spawn(f); 56 | } 57 | 58 | pub fn page_down(&mut self) { 59 | let f = self.inner.page_down(self.view_id).map_err(|_| ()); 60 | spawn(f); 61 | } 62 | 63 | pub fn page_up(&mut self) { 64 | let f = self.inner.page_up(self.view_id).map_err(|_| ()); 65 | spawn(f); 66 | } 67 | 68 | pub fn home(&mut self) { 69 | let f = self.inner.line_start(self.view_id).map_err(|_| ()); 70 | spawn(f); 71 | } 72 | 73 | pub fn end(&mut self) { 74 | let f = self.inner.line_end(self.view_id).map_err(|_| ()); 75 | spawn(f); 76 | } 77 | 78 | pub fn delete(&mut self) { 79 | let f = self.inner.delete(self.view_id).map_err(|_| ()); 80 | spawn(f); 81 | } 82 | 83 | pub fn backspace(&mut self) { 84 | let f = self.inner.backspace(self.view_id).map_err(|_| ()); 85 | spawn(f); 86 | } 87 | 88 | pub fn save(&mut self, file: &str) { 89 | let f = self.inner.save(self.view_id, file).map_err(|_| ()); 90 | spawn(f); 91 | } 92 | 93 | pub fn click(&mut self, line: u64, column: u64) { 94 | let f = self 95 | .inner 96 | .click_point_select(self.view_id, line, column) 97 | .map_err(|_| ()); 98 | spawn(f); 99 | } 100 | 101 | pub fn drag(&mut self, line: u64, column: u64) { 102 | let f = self.inner.drag(self.view_id, line, column).map_err(|_| ()); 103 | spawn(f); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xi-term 2 | 3 | [![Build Status](https://travis-ci.org/xi-frontend/xi-term.svg?branch=master)](https://travis-ci.org/xi-frontend/xi-term) 4 | 5 | Formerly `xi-tui`, `xi-term` is a terminal frontend for [xi](https://github.com/xi-editor/xi-editor/). 6 | 7 | It is experimental and under development, so don't expect anything magical (yet!). 8 | 9 | ## Installation 10 | 11 | The frontend assumes that you have installed the 12 | [core editor](https://github.com/xi-editor/xi-editor) 13 | and is available in your PATH. The following should suffice: 14 | 15 | ```bash 16 | git clone https://github.com/xi-editor/xi-editor 17 | cd xi-editor/rust 18 | cargo install --path . 19 | 20 | # if you want syntax highlighting, you need to install the syntect plugin: 21 | cd syntect-plugin 22 | make install 23 | 24 | # You need to add ~/.cargo/bin to your PATH 25 | # (this is where `cargo install` places binaries). 26 | # In your .bashrc (or equivalent), add `export PATH=$PATH:~/.cargo/bin` 27 | ``` 28 | 29 | Then you can clone this repository and run the frontend with 30 | `cargo run --release -- `. 31 | `your_file` can be an existing file or any dummy name. 32 | 33 | ## Logging 34 | 35 | For debugging, it can be useful to have logs. 36 | You can specify a location for log files `xi-term` with `-l `. 37 | Two files will be written: 38 | 39 | - ``: all the `xi-term` logs 40 | - `.rpc`: the RPC messages exchanged between the core and the frontend 41 | 42 | ## Screenshots 43 | 44 | ![a python file](.github/python.png) 45 | 46 | ![the README file](.github/README.png) 47 | 48 | ## Shortcuts 49 | 50 | For now, there are only two shortcuts: 51 | 52 | - `^w` saves the current view 53 | - `^c` exits 54 | 55 | ## Commands 56 | `xi-term` supports a vim-like command prompt for executing commands, accessed 57 | via Alt-X. 58 | 59 | Currently supported commands: 60 | 61 | | Short form | Long form | Description | 62 | | ---------- | --------- | ----------- | 63 | | q | quit | Quits xi-term | 64 | | s | save | Saves the current file | 65 | | o `filename` | open `filename` | Open `filename` for editing | 66 | | b | backspace | Delete the previous character and move the cursor one position back | 67 | | d | delete | Delete the character under the cursor | 68 | | bn | next-buffer | Switch to the next buffer | 69 | | bp | prev-buffer | Switch to the previous buffer | 70 | | pd | page-down | Advance the current view by one page | 71 | | pu | page-up | Move the current view back by one page | 72 | | ml | move-left | Move the cursor one position left | 73 | | mr | move-right | Move the cursor one position right | 74 | | mu | move-up | Move the cursor one line up | 75 | | md | move-down | Move the cursor one line down | 76 | | t `theme` | theme `theme-name` | Set the theme to `theme`| 77 | | ln | line-numbers | Toggle displaying line numbers | 78 | 79 | Future commands: 80 | 81 | | Short form | Long form | Description | 82 | | ---------- | --------- | ----------- | 83 | | c | close | Closes the current view | 84 | | ? `string` | search `string` | Search for `string` | 85 | | sl | select-left | Move the cursor one position left and update the current selection accordingly | 86 | | sr | select-right | Move the cursor one position right and update the current selection accordingly | 87 | | su | select-up | Move the cursor one line up and update the current selection accordingly | 88 | | sd | select-down | Move the cursor one line down and update the current selection accordingly | 89 | 90 | ## Preferences 91 | Xi-core supports several user-configurable options through a `preferences.xiconfig` file. 92 | The default location for this is `$XDG_CONFIG_HOME/xi/preferences.xiconfig`, or, if 93 | `$XDG_CONFIG_HOME` is not set, it defaults to `$HOME/xi/preferences.xiconfig`. 94 | 95 | ## Caveats 96 | 97 | ### Colors 98 | 99 | If you have the `syntect` plugin installed, colors will be enabled by default, with two caveats: 100 | 101 | - you must have true colors enabled. Otherwise, some portions of text won't be displayed 102 | - the default theme is for dark backgrounds 103 | -------------------------------------------------------------------------------- /src/core/cmd.rs: -------------------------------------------------------------------------------- 1 | //! Command system for xi-term. A command represents 2 | //! a task the user wants the editor to preform, 3 | /// currently commands can only be input through the CommandPrompt. Vim style. 4 | use xrl::ViewId; 5 | 6 | use std::str::FromStr; 7 | 8 | #[derive(Debug)] 9 | pub enum Command { 10 | /// Close the CommandPrompt. 11 | Cancel, 12 | /// Quit editor. 13 | Quit, 14 | /// Save the current file buffer. 15 | Save(Option), 16 | /// Backspace 17 | Back, 18 | /// Delete 19 | Delete, 20 | /// Open A new file. 21 | Open(Option), 22 | /// Cycle to the next View. 23 | NextBuffer, 24 | /// Cycle to the previous buffer. 25 | PrevBuffer, 26 | /// Move cursor left. 27 | MoveLeft, 28 | /// Move cursor right. 29 | MoveRight, 30 | /// Move cursor up. 31 | MoveUp, 32 | /// Move cursor down. 33 | MoveDown, 34 | /// Page down 35 | PageDown, 36 | /// Page up 37 | PageUp, 38 | /// Change the syntax theme. 39 | SetTheme(String), 40 | /// Toggle displaying line numbers. 41 | ToggleLineNumbers, 42 | } 43 | 44 | #[derive(Debug)] 45 | pub enum ParseCommandError { 46 | /// Didnt expect a command to take an argument. 47 | UnexpectedArgument, 48 | /// The given command expected an argument. 49 | ExpectedArgument { 50 | cmd: String, 51 | expected: usize, 52 | found: usize, 53 | }, 54 | /// The given command was given to many arguments. 55 | TooManyArguments { 56 | cmd: String, 57 | expected: usize, 58 | found: usize, 59 | }, 60 | /// Invalid input was received. 61 | UnknownCommand(String), 62 | } 63 | 64 | impl FromStr for Command { 65 | type Err = ParseCommandError; 66 | 67 | fn from_str(s: &str) -> Result { 68 | match &s[..] { 69 | "s" | "save" => Ok(Command::Save(None)), 70 | "q" | "quit" => Ok(Command::Quit), 71 | "b" | "back" => Ok(Command::Back), 72 | "d" | "delete" => Ok(Command::Delete), 73 | "bn" | "next-buffer" => Ok(Command::NextBuffer), 74 | "bp" | "prev-buffer" => Ok(Command::PrevBuffer), 75 | "pd" | "page-down" => Ok(Command::PageDown), 76 | "pu" | "page-up" => Ok(Command::PageUp), 77 | "ml" | "move-left" => Ok(Command::MoveLeft), 78 | "mr" | "move-right" => Ok(Command::MoveRight), 79 | "mu" | "move-up" => Ok(Command::MoveUp), 80 | "md" | "move-down" => Ok(Command::MoveDown), 81 | "ln" | "line-numbers" => Ok(Command::ToggleLineNumbers), 82 | command => { 83 | let mut parts: Vec<&str> = command.split(' ').collect(); 84 | 85 | let cmd = parts.remove(0); 86 | match cmd { 87 | "t" | "theme" => { 88 | if parts.is_empty() { 89 | Err(ParseCommandError::ExpectedArgument { 90 | cmd: "theme".into(), 91 | expected: 1, 92 | found: 0, 93 | }) 94 | } else if parts.len() > 1 { 95 | Err(ParseCommandError::TooManyArguments { 96 | cmd: cmd.to_owned(), 97 | expected: 1, 98 | found: parts.len(), 99 | }) 100 | } else { 101 | Ok(Command::SetTheme(parts[0].to_owned())) 102 | } 103 | } 104 | "o" | "open" => { 105 | if parts.is_empty() { 106 | Ok(Command::Open(None)) 107 | } else if parts.len() > 1 { 108 | Err(ParseCommandError::UnexpectedArgument) 109 | } else { 110 | Ok(Command::Open(Some(parts[0].to_owned()))) 111 | } 112 | } 113 | _ => Err(ParseCommandError::UnknownCommand(command.into())), 114 | } 115 | } 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(feature = "clippy", feature(plugin))] 2 | #![cfg_attr(feature = "clippy", plugin(clippy))] 3 | #![cfg_attr(feature = "clippy", deny(clippy))] 4 | 5 | #[macro_use] 6 | extern crate clap; 7 | 8 | extern crate failure; 9 | 10 | #[macro_use] 11 | extern crate log; 12 | extern crate log4rs; 13 | 14 | extern crate futures; 15 | extern crate indexmap; 16 | extern crate termion; 17 | extern crate tokio; 18 | extern crate xdg; 19 | extern crate xrl; 20 | 21 | mod core; 22 | mod widgets; 23 | use xdg::BaseDirectories; 24 | 25 | use failure::Error; 26 | use futures::{future, Future, Stream}; 27 | use log::LevelFilter; 28 | use log4rs::append::file::FileAppender; 29 | use log4rs::config::{Appender, Config, Logger, Root}; 30 | use xrl::spawn; 31 | 32 | use core::{Command, Tui, TuiServiceBuilder}; 33 | 34 | fn configure_logs(logfile: &str) { 35 | let tui = FileAppender::builder().build(logfile).unwrap(); 36 | let rpc = FileAppender::builder() 37 | .build(&format!("{}.rpc", logfile)) 38 | .unwrap(); 39 | let config = Config::builder() 40 | .appender(Appender::builder().build("tui", Box::new(tui))) 41 | .appender(Appender::builder().build("rpc", Box::new(rpc))) 42 | .logger( 43 | Logger::builder() 44 | .appender("tui") 45 | .additive(false) 46 | .build("xi_tui", LevelFilter::Debug), 47 | ) 48 | .logger( 49 | Logger::builder() 50 | .appender("tui") 51 | .additive(false) 52 | .build("xrl", LevelFilter::Info), 53 | ) 54 | .logger( 55 | Logger::builder() 56 | .appender("rpc") 57 | .additive(false) 58 | .build("xrl::protocol::codec", LevelFilter::Trace), 59 | ) 60 | .build(Root::builder().appender("tui").build(LevelFilter::Info)) 61 | .unwrap(); 62 | let _ = log4rs::init_config(config).unwrap(); 63 | } 64 | 65 | fn main() { 66 | if let Err(ref e) = run() { 67 | use std::io::Write; 68 | let stderr = &mut ::std::io::stderr(); 69 | 70 | writeln!(stderr, "error: {}", e).unwrap(); 71 | error!("error: {}", e); 72 | 73 | writeln!(stderr, "caused by: {}", e.as_fail()).unwrap(); 74 | error!("error: {}", e); 75 | 76 | writeln!(stderr, "backtrace: {:?}", e.backtrace()).unwrap(); 77 | error!("error: {}", e); 78 | 79 | ::std::process::exit(1); 80 | } 81 | } 82 | 83 | fn run() -> Result<(), Error> { 84 | let xi = clap_app!( 85 | xi => 86 | (about: "The Xi Editor") 87 | (@arg core: -c --core +takes_value "Specify binary to use for the backend") 88 | (@arg logfile: -l --logfile +takes_value "Log file location") 89 | (@arg file: +required "File to edit")); 90 | 91 | let matches = xi.get_matches(); 92 | if let Some(logfile) = matches.value_of("logfile") { 93 | configure_logs(logfile); 94 | } 95 | 96 | tokio::run(future::lazy(move || { 97 | info!("starting xi-core"); 98 | let (tui_service_builder, core_events_rx) = TuiServiceBuilder::new(); 99 | let (client, core_stderr) = spawn( 100 | matches.value_of("core").unwrap_or("xi-core"), 101 | tui_service_builder, 102 | ).unwrap(); 103 | 104 | info!("starting logging xi-core errors"); 105 | tokio::spawn( 106 | core_stderr 107 | .for_each(|msg| { 108 | error!("core: {}", msg); 109 | Ok(()) 110 | }) 111 | .map_err(|_| ()), 112 | ); 113 | 114 | tokio::spawn(future::lazy(move || { 115 | let conf_dir = BaseDirectories::with_prefix("xi") 116 | .ok() 117 | .and_then(|dirs| Some(dirs.get_config_home().to_string_lossy().into_owned())); 118 | 119 | let client_clone = client.clone(); 120 | client 121 | .client_started(conf_dir.as_ref().map(|dir| &**dir), None) 122 | .map_err(|e| error!("failed to send \"client_started\" {:?}", e)) 123 | .and_then(move |_| { 124 | info!("initializing the TUI"); 125 | let mut tui = Tui::new(client_clone, core_events_rx) 126 | .expect("failed to initialize the TUI"); 127 | tui.run_command(Command::Open( 128 | matches.value_of("file").map(ToString::to_string), 129 | )); 130 | tui.run_command(Command::SetTheme("base16-eighties.dark".into())); 131 | tui.map_err(|e| error!("TUI exited with an error: {:?}", e)) 132 | }) 133 | })); 134 | Ok(()) 135 | })); 136 | Ok(()) 137 | } 138 | -------------------------------------------------------------------------------- /src/core/terminal.rs: -------------------------------------------------------------------------------- 1 | use std::io::{self, Stdout}; 2 | use std::thread::{sleep, spawn}; 3 | use std::time::Duration; 4 | 5 | use futures::sync::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; 6 | use futures::{Async, Poll, Sink, Stream}; 7 | 8 | use failure::{Error, ResultExt}; 9 | 10 | use termion::event::Event; 11 | use termion::input::MouseTerminal; 12 | use termion::input::TermRead; 13 | use termion::raw::{IntoRawMode, RawTerminal}; 14 | use termion::screen::AlternateScreen; 15 | use termion::terminal_size; 16 | 17 | /// Simple type alias for the Write implementer we render to. 18 | pub type RenderTarget = MouseTerminal>>; 19 | 20 | pub struct Terminal { 21 | size: UnboundedReceiver<(u16, u16)>, 22 | stdin: UnboundedReceiver, 23 | stdout: RenderTarget, 24 | } 25 | 26 | impl Terminal { 27 | pub fn new() -> Result { 28 | let (stdin_tx, stdin_rx) = unbounded(); 29 | let (size_tx, size_rx) = unbounded(); 30 | let stdout = MouseTerminal::from(AlternateScreen::from( 31 | io::stdout() 32 | .into_raw_mode() 33 | .context("Failed to put terminal into raw mode")?, 34 | )); 35 | 36 | let term = Terminal { 37 | stdin: stdin_rx, 38 | size: size_rx, 39 | stdout, 40 | }; 41 | 42 | Terminal::start_stdin_listening(stdin_tx); 43 | Terminal::start_size_listening(size_tx); 44 | Ok(term) 45 | } 46 | 47 | fn start_stdin_listening(tx: UnboundedSender) { 48 | let mut tx = tx; 49 | spawn(move || { 50 | info!("waiting for input events"); 51 | for event_res in io::stdin().events() { 52 | match event_res { 53 | // TODO: at least log the errors 54 | Ok(event) => { 55 | let _ = tx.start_send(event).unwrap(); 56 | let _ = tx.poll_complete().unwrap(); 57 | } 58 | Err(e) => error!("{}", e), 59 | } 60 | } 61 | info!("stop waiting for input events"); 62 | }); 63 | } 64 | 65 | fn start_size_listening(tx: UnboundedSender<(u16, u16)>) { 66 | let mut tx = tx; 67 | spawn(move || { 68 | let mut current_size = (0, 0); 69 | info!("waiting for resize events"); 70 | loop { 71 | match terminal_size() { 72 | Ok(new_size) => { 73 | if new_size != current_size { 74 | info!( 75 | "terminal resized (from {:?} to {:?})", 76 | current_size, new_size 77 | ); 78 | current_size = new_size; 79 | let _ = tx.start_send(current_size).unwrap(); 80 | let _ = tx.poll_complete().unwrap(); 81 | } 82 | } 83 | Err(e) => { 84 | error!("failed to get terminal size: {}", e); 85 | } 86 | } 87 | sleep(Duration::from_millis(10)); 88 | } 89 | }); 90 | } 91 | 92 | pub fn stdout(&mut self) -> &mut RenderTarget { 93 | &mut self.stdout 94 | } 95 | } 96 | 97 | pub enum TerminalEvent { 98 | Resize((u16, u16)), 99 | Input(Event), 100 | } 101 | 102 | impl Stream for Terminal { 103 | type Item = TerminalEvent; 104 | type Error = (); 105 | 106 | fn poll(&mut self) -> Poll, Self::Error> { 107 | debug!("polling for terminal size events"); 108 | match self.size.poll() { 109 | Ok(Async::Ready(Some(size))) => { 110 | debug!("size event: {:?}", size); 111 | let event = TerminalEvent::Resize(size); 112 | return Ok(Async::Ready(Some(event))); 113 | } 114 | Ok(Async::Ready(None)) => { 115 | warn!("terminal size sender closed the channel"); 116 | return Ok(Async::Ready(None)); 117 | } 118 | Ok(Async::NotReady) => { 119 | debug!("done polling for terminal size events"); 120 | } 121 | Err(()) => return Err(()), 122 | } 123 | 124 | debug!("polling for stdin events"); 125 | match self.stdin.poll() { 126 | Ok(Async::Ready(Some(event))) => { 127 | debug!("stdin event: {:?}", event); 128 | let event = TerminalEvent::Input(event); 129 | return Ok(Async::Ready(Some(event))); 130 | } 131 | Ok(Async::Ready(None)) => { 132 | warn!("terminal input sender closed the channel"); 133 | return Ok(Async::Ready(None)); 134 | } 135 | Ok(Async::NotReady) => { 136 | debug!("done polling for stdin events"); 137 | } 138 | Err(()) => return Err(()), 139 | } 140 | debug!("done polling the terminal"); 141 | Ok(Async::NotReady) 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/core/tui.rs: -------------------------------------------------------------------------------- 1 | use std::io::{self, Write}; 2 | 3 | use futures::sync::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}; 4 | use futures::sync::oneshot::{self, Receiver, Sender}; 5 | use futures::{Async, Future, Poll, Sink, Stream}; 6 | 7 | use termion::event::{Event, Key}; 8 | use xrl::{Client, Frontend, FrontendBuilder, MeasureWidth, XiNotification}; 9 | 10 | use failure::Error; 11 | 12 | use core::{Command, Terminal, TerminalEvent}; 13 | use widgets::{CommandPrompt, Editor}; 14 | 15 | pub struct Tui { 16 | /// The editor holds the text buffers (named "views" in xi 17 | /// terminology). 18 | editor: Editor, 19 | 20 | /// The command prompt is where users can type commands. 21 | prompt: Option, 22 | 23 | /// The terminal is used to draw on the screen a get inputs from 24 | /// the user. 25 | terminal: Terminal, 26 | 27 | /// The size of the terminal. 28 | term_size: (u16, u16), 29 | 30 | /// Whether the editor is shutting down. 31 | exit: bool, 32 | 33 | /// Stream of messages from Xi core. 34 | core_events: UnboundedReceiver, 35 | } 36 | 37 | impl Tui { 38 | /// Create a new Tui instance. 39 | pub fn new(client: Client, events: UnboundedReceiver) -> Result { 40 | Ok(Tui { 41 | terminal: Terminal::new()?, 42 | exit: false, 43 | term_size: (0, 0), 44 | editor: Editor::new(client), 45 | prompt: None, 46 | core_events: events, 47 | }) 48 | } 49 | 50 | fn handle_resize(&mut self, size: (u16, u16)) { 51 | self.term_size = size; 52 | self.editor.handle_resize(size); 53 | } 54 | 55 | pub fn run_command(&mut self, cmd: Command) { 56 | match cmd { 57 | Command::Cancel => { 58 | self.prompt = None; 59 | } 60 | Command::Quit => self.exit = true, 61 | Command::Save(view) => self.editor.save(view), 62 | Command::Back => self.editor.back(), 63 | Command::Delete => self.editor.delete(), 64 | Command::Open(file) => self.editor.new_view(file), 65 | Command::SetTheme(theme) => self.editor.set_theme(&theme), 66 | Command::NextBuffer => self.editor.next_buffer(), 67 | Command::PrevBuffer => self.editor.prev_buffer(), 68 | Command::MoveLeft => self.editor.move_left(), 69 | Command::MoveRight => self.editor.move_right(), 70 | Command::MoveUp => self.editor.move_up(), 71 | Command::MoveDown => self.editor.move_down(), 72 | Command::PageDown => self.editor.page_down(), 73 | Command::PageUp => self.editor.page_up(), 74 | Command::ToggleLineNumbers => self.editor.toggle_line_numbers(), 75 | } 76 | } 77 | 78 | /// Global keybindings can be parsed here 79 | fn handle_input(&mut self, event: Event) { 80 | debug!("handling input {:?}", event); 81 | match event { 82 | Event::Key(Key::Ctrl('c')) => self.exit = true, 83 | Event::Key(Key::Alt('x')) => { 84 | if let Some(ref mut prompt) = self.prompt { 85 | match prompt.handle_input(&event) { 86 | Ok(None) => {} 87 | Ok(Some(_)) => unreachable!(), 88 | Err(_) => unreachable!(), 89 | } 90 | } else { 91 | self.prompt = Some(CommandPrompt::default()); 92 | } 93 | } 94 | event => { 95 | // No command prompt is active, process the event normally. 96 | if self.prompt.is_none() { 97 | self.editor.handle_input(event); 98 | return; 99 | } 100 | 101 | // A command prompt is active. 102 | let mut prompt = self.prompt.take().unwrap(); 103 | match prompt.handle_input(&event) { 104 | Ok(None) => { 105 | self.prompt = Some(prompt); 106 | } 107 | Ok(Some(cmd)) => self.run_command(cmd), 108 | Err(err) => { 109 | error!("Failed to parse command: {:?}", err); 110 | } 111 | } 112 | } 113 | } 114 | } 115 | 116 | fn render(&mut self) -> Result<(), Error> { 117 | if let Some(ref mut prompt) = self.prompt { 118 | prompt.render(self.terminal.stdout(), self.term_size.1)?; 119 | } else { 120 | self.editor.render(self.terminal.stdout())?; 121 | } 122 | if let Err(e) = self.terminal.stdout().flush() { 123 | error!("failed to flush stdout: {}", e); 124 | } 125 | Ok(()) 126 | } 127 | 128 | fn handle_core_event(&mut self, event: CoreEvent) { 129 | self.editor.handle_core_event(event) 130 | } 131 | 132 | fn poll_editor(&mut self) { 133 | debug!("polling the editor"); 134 | match self.editor.poll() { 135 | Ok(Async::NotReady) => { 136 | debug!("no more editor event, done polling"); 137 | return; 138 | } 139 | Ok(Async::Ready(_)) => { 140 | info!("The editor exited normally. Shutting down the TUI"); 141 | self.exit = true; 142 | return; 143 | } 144 | Err(e) => { 145 | error!("The editor exited with an error: {:?}", e); 146 | error!("Shutting down the TUI."); 147 | self.exit = true; 148 | return; 149 | } 150 | } 151 | } 152 | 153 | fn poll_terminal(&mut self) { 154 | debug!("polling the terminal"); 155 | loop { 156 | match self.terminal.poll() { 157 | Ok(Async::Ready(Some(event))) => match event { 158 | TerminalEvent::Input(event) => self.handle_input(event), 159 | TerminalEvent::Resize(event) => self.handle_resize(event), 160 | }, 161 | Ok(Async::Ready(None)) => { 162 | info!("The terminal exited normally. Shutting down the TUI"); 163 | self.exit = true; 164 | return; 165 | } 166 | Ok(Async::NotReady) => { 167 | debug!("no more terminal event, done polling"); 168 | return; 169 | } 170 | Err(e) => { 171 | error!("The terminal exited with an error: {:?}", e); 172 | error!("Shutting down the TUI"); 173 | self.exit = true; 174 | return; 175 | } 176 | } 177 | } 178 | } 179 | 180 | fn poll_rpc(&mut self) { 181 | debug!("polling for RPC messages"); 182 | loop { 183 | match self.core_events.poll() { 184 | Ok(Async::Ready(Some(event))) => self.handle_core_event(event), 185 | Ok(Async::Ready(None)) => { 186 | info!("The RPC endpoint exited normally. Shutting down the TUI"); 187 | self.exit = true; 188 | return; 189 | } 190 | Ok(Async::NotReady) => { 191 | debug!("no more RPC event, done polling"); 192 | return; 193 | } 194 | Err(e) => { 195 | error!("The RPC endpoint exited with an error: {:?}", e); 196 | error!("Shutting down the TUI"); 197 | self.exit = true; 198 | return; 199 | } 200 | } 201 | } 202 | } 203 | } 204 | 205 | impl Future for Tui { 206 | type Item = (); 207 | type Error = io::Error; 208 | 209 | fn poll(&mut self) -> Poll { 210 | debug!("polling the TUI"); 211 | self.poll_terminal(); 212 | if self.exit { 213 | info!("exiting the TUI"); 214 | return Ok(Async::Ready(())); 215 | } 216 | 217 | self.poll_editor(); 218 | if self.exit { 219 | info!("exiting the TUI"); 220 | return Ok(Async::Ready(())); 221 | } 222 | 223 | self.poll_rpc(); 224 | if self.exit { 225 | info!("exiting the TUI"); 226 | return Ok(Async::Ready(())); 227 | } 228 | 229 | debug!("done polling the TUI components"); 230 | debug!("rendering"); 231 | self.render().expect("failed to render the TUI"); 232 | debug!("done rendering, end of polling"); 233 | Ok(Async::NotReady) 234 | } 235 | } 236 | 237 | pub enum CoreEvent { 238 | Notify(XiNotification), 239 | MeasureWidth((MeasureWidth, Sender>>)), 240 | } 241 | 242 | pub struct TuiService(UnboundedSender); 243 | 244 | impl Frontend for TuiService { 245 | type NotificationResult = Result<(), ()>; 246 | fn handle_notification(&mut self, notification: XiNotification) -> Self::NotificationResult { 247 | self.0.start_send(CoreEvent::Notify(notification)).unwrap(); 248 | self.0.poll_complete().unwrap(); 249 | Ok(()) 250 | } 251 | 252 | type MeasureWidthResult = NoErrorReceiver>>; 253 | fn handle_measure_width(&mut self, request: MeasureWidth) -> Self::MeasureWidthResult { 254 | let (tx, rx) = oneshot::channel::>>(); 255 | self.0 256 | .start_send(CoreEvent::MeasureWidth((request, tx))) 257 | .unwrap(); 258 | self.0.poll_complete().unwrap(); 259 | NoErrorReceiver(rx) 260 | } 261 | } 262 | 263 | /// A dummy type from wrap a `oneshot::Receiver`. 264 | /// 265 | /// The only difference with the `oneshot::Receiver` is that 266 | /// `NoErrorReceiver`'s future implementation uses the empty type `()` 267 | /// for its error. 268 | pub struct NoErrorReceiver(Receiver); 269 | 270 | impl Future for NoErrorReceiver { 271 | type Item = T; 272 | type Error = (); 273 | fn poll(&mut self) -> Poll { 274 | self.0.poll().map_err(|_cancelled| ()) 275 | } 276 | } 277 | 278 | pub struct TuiServiceBuilder(UnboundedSender); 279 | 280 | impl TuiServiceBuilder { 281 | pub fn new() -> (Self, UnboundedReceiver) { 282 | let (tx, rx) = unbounded(); 283 | (TuiServiceBuilder(tx), rx) 284 | } 285 | } 286 | 287 | impl FrontendBuilder for TuiServiceBuilder { 288 | type Frontend = TuiService; 289 | fn build(self, _client: Client) -> Self::Frontend { 290 | TuiService(self.0) 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /src/widgets/editor.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::io::Write; 3 | 4 | use futures::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; 5 | use futures::{Async, Future, Poll, Stream}; 6 | 7 | use failure::Error; 8 | use indexmap::IndexMap; 9 | use termion::event::Event as TermionEvent; 10 | use xrl::{Client, ConfigChanged, ScrollTo, Style, Update, ViewId, XiNotification}; 11 | 12 | use core::CoreEvent; 13 | use widgets::{View, ViewClient}; 14 | 15 | /// The main interface to xi-core 16 | pub struct Editor { 17 | /// Channel from which the responses to "new_view" requests are 18 | /// received. Upon receiving a `ViewId`, the `Editdor` creates a 19 | /// new view. 20 | pub new_view_rx: UnboundedReceiver<(ViewId, Option)>, 21 | 22 | /// Channel into which the responses to "new_view" requests are 23 | /// sent, when they are received from the core. 24 | pub new_view_tx: UnboundedSender<(ViewId, Option)>, 25 | 26 | /// Store the events that we cannot process right away. 27 | /// 28 | /// Due to the asynchronous nature of the communication with the 29 | /// core, we may receive events we cannot process on the 30 | /// moment. For instance, when opening a new view, we may receive 31 | /// notifications for it whereas we are not even done processing 32 | /// the response to the "open" request, and hence, the view might 33 | /// not even be created on our side yet. 34 | pub delayed_events: Vec, 35 | 36 | /// The views that are opened. 37 | pub views: IndexMap, 38 | 39 | /// Id of the view that is currently displayed on screen. 40 | pub current_view: ViewId, 41 | 42 | /// A client to send notifications or request to `xi-core`. 43 | pub client: Client, 44 | 45 | pub size: (u16, u16), 46 | pub styles: HashMap, 47 | } 48 | 49 | /// Methods for general use. 50 | impl Editor { 51 | pub fn new(client: Client) -> Editor { 52 | let mut styles = HashMap::new(); 53 | styles.insert(0, Default::default()); 54 | let (new_view_tx, new_view_rx) = mpsc::unbounded::<(ViewId, Option)>(); 55 | 56 | Editor { 57 | new_view_rx, 58 | new_view_tx, 59 | delayed_events: Vec::new(), 60 | views: IndexMap::new(), 61 | current_view: ViewId(0), 62 | client, 63 | size: (0, 0), 64 | styles, 65 | } 66 | } 67 | } 68 | 69 | // Strictly speaking we don't have to implement Future for the editor, 70 | // because we don't spawn it on the tokio runtime. But I'm still 71 | // somewhat undecided whether we should or not, and having the editor 72 | // implemented as a Future will make things easier if we decide to go 73 | // that way. 74 | impl Future for Editor { 75 | type Item = (); 76 | type Error = (); 77 | 78 | fn poll(&mut self) -> Poll { 79 | debug!("polling the editor"); 80 | 81 | debug!("handling delayed events"); 82 | if !self.delayed_events.is_empty() { 83 | let delayed_events: Vec = self.delayed_events.drain(..).collect(); 84 | for event in delayed_events { 85 | self.handle_core_event(event); 86 | } 87 | } 88 | 89 | debug!("polling 'new_view' responses"); 90 | loop { 91 | match self.new_view_rx.poll() { 92 | Ok(Async::Ready(Some((view_id, file_path)))) => { 93 | info!("creating new view {:?}", view_id); 94 | let client = ViewClient::new(self.client.clone(), view_id); 95 | let mut view = View::new(client, file_path); 96 | view.resize(self.size.1); 97 | self.views.insert(view_id, view); 98 | info!("switching to view {:?}", view_id); 99 | self.current_view = view_id; 100 | } 101 | // We own one of the senders so this cannot happen 102 | Ok(Async::Ready(None)) => unreachable!(), 103 | Ok(Async::NotReady) => { 104 | debug!("no more 'new_view' response"); 105 | break; 106 | } 107 | Err(e) => { 108 | error!("Uknown channel error: {:?}", e); 109 | return Err(()); 110 | } 111 | } 112 | } 113 | Ok(Async::NotReady) 114 | } 115 | } 116 | 117 | impl Editor { 118 | /// Handle keyboard and mouse events 119 | pub fn handle_input(&mut self, event: TermionEvent) { 120 | if let Some(view) = self.views.get_mut(&self.current_view) { 121 | view.handle_input(event) 122 | } 123 | } 124 | 125 | /// Handle terminal size changes 126 | pub fn handle_resize(&mut self, size: (u16, u16)) { 127 | info!("setting new terminal size"); 128 | self.size = size; 129 | if let Some(view) = self.views.get_mut(&self.current_view) { 130 | view.resize(size.1); 131 | } else { 132 | warn!("view {} not found", self.current_view); 133 | } 134 | } 135 | 136 | /// Handle message from xi-core, that the TUI forwarded us. 137 | pub fn handle_core_event(&mut self, event: CoreEvent) { 138 | match event { 139 | CoreEvent::Notify(notification) => match notification { 140 | XiNotification::Update(update) => self.update(update), 141 | XiNotification::DefStyle(style) => self.def_style(style), 142 | XiNotification::ScrollTo(scroll_to) => self.scroll_to(scroll_to), 143 | XiNotification::ConfigChanged(config) => self.config_changed(config), 144 | _ => info!("ignoring Xi core notification: {:?}", notification), 145 | }, 146 | CoreEvent::MeasureWidth((_request, _result_tx)) => unimplemented!(), 147 | } 148 | } 149 | 150 | /// Handle an "update" notification from Xi core. 151 | fn update(&mut self, update: Update) { 152 | match self.views.get_mut(&update.view_id) { 153 | Some(view) => view.update_cache(update), 154 | None => self 155 | .delayed_events 156 | .push(CoreEvent::Notify(XiNotification::Update(update))), 157 | } 158 | } 159 | 160 | /// Handle a "scroll_to" notification from Xi core. 161 | fn scroll_to(&mut self, scroll_to: ScrollTo) { 162 | match self.views.get_mut(&scroll_to.view_id) { 163 | Some(view) => view.set_cursor(scroll_to.line, scroll_to.column), 164 | None => self 165 | .delayed_events 166 | .push(CoreEvent::Notify(XiNotification::ScrollTo(scroll_to))), 167 | } 168 | } 169 | 170 | /// Handle a "def_style" notification from Xi core. 171 | fn def_style(&mut self, style: Style) { 172 | self.styles.insert(style.id, style); 173 | } 174 | 175 | /// Handle a "config_changed" notification from Xi core. 176 | fn config_changed(&mut self, config: ConfigChanged) { 177 | match self.views.get_mut(&config.view_id) { 178 | Some(view) => view.config_changed(config.changes), 179 | None => self 180 | .delayed_events 181 | .push(CoreEvent::Notify(XiNotification::ConfigChanged(config))), 182 | } 183 | } 184 | 185 | /// Spawn a future that sends a "new_view" request to the core, 186 | /// and forwards the response back to the `Editor`. 187 | pub fn new_view(&mut self, file_path: Option) { 188 | let response_tx = self.new_view_tx.clone(); 189 | let future = self 190 | .client 191 | .new_view(file_path.clone()) 192 | .and_then(move |id| { 193 | // when we get the response from the core, forward the new 194 | // view id to the editor so that the view can be created 195 | response_tx 196 | .unbounded_send((id, file_path)) 197 | .unwrap_or_else(|e| error!("failed to send \"new_view\" response: {:?}", e)); 198 | Ok(()) 199 | }) 200 | .or_else(|client_error| { 201 | error!("failed to send \"new_view\" response: {:?}", client_error); 202 | Ok(()) 203 | }); 204 | tokio::spawn(future); 205 | } 206 | 207 | /// Spawn a future that sends a "set_theme" notification to the 208 | /// core for the current view. 209 | pub fn set_theme(&mut self, theme: &str) { 210 | tokio::spawn(self.client.set_theme(theme).map_err(|_| ())); 211 | } 212 | 213 | /// Spawn a future that sends a "save" notification to the core. 214 | pub fn save(&mut self, view_id: Option) { 215 | match self.views.get_mut(&view_id.unwrap_or(self.current_view)) { 216 | Some(view) => view.save(), 217 | None => warn!("cannot save view {:?}: not found", &view_id), 218 | } 219 | } 220 | 221 | pub fn back(&mut self) { 222 | if let Some(view) = self.views.get_mut(&self.current_view) { 223 | view.back(); 224 | } 225 | } 226 | 227 | pub fn delete(&mut self) { 228 | if let Some(view) = self.views.get_mut(&self.current_view) { 229 | view.delete(); 230 | } 231 | } 232 | 233 | pub fn next_buffer(&mut self) { 234 | if let Some((dex, _, _)) = self.views.get_full(&self.current_view) { 235 | if dex + 1 == self.views.len() { 236 | if let Some((view, _)) = self.views.get_index(0) { 237 | self.current_view = *view; 238 | } 239 | } else if let Some((view, _)) = self.views.get_index(dex + 1) { 240 | self.current_view = *view; 241 | } 242 | } 243 | } 244 | 245 | pub fn prev_buffer(&mut self) { 246 | if let Some((dex, _, _)) = self.views.get_full(&self.current_view) { 247 | if dex == 0 { 248 | if let Some((view, _)) = self.views.get_index(self.views.len() - 1) { 249 | self.current_view = *view; 250 | } 251 | } else if let Some((view, _)) = self.views.get_index(dex - 1) { 252 | self.current_view = *view; 253 | } 254 | } 255 | } 256 | 257 | pub fn move_left(&mut self) { 258 | if let Some(view) = self.views.get_mut(&self.current_view) { 259 | view.move_left(); 260 | } 261 | } 262 | 263 | pub fn move_right(&mut self) { 264 | if let Some(view) = self.views.get_mut(&self.current_view) { 265 | view.move_right(); 266 | } 267 | } 268 | 269 | pub fn move_up(&mut self) { 270 | if let Some(view) = self.views.get_mut(&self.current_view) { 271 | view.move_up(); 272 | } 273 | } 274 | 275 | pub fn move_down(&mut self) { 276 | if let Some(view) = self.views.get_mut(&self.current_view) { 277 | view.move_down(); 278 | } 279 | } 280 | 281 | pub fn page_down(&mut self) { 282 | if let Some(view) = self.views.get_mut(&self.current_view) { 283 | view.page_down(); 284 | } 285 | } 286 | 287 | pub fn page_up(&mut self) { 288 | if let Some(view) = self.views.get_mut(&self.current_view) { 289 | view.page_up(); 290 | } 291 | } 292 | 293 | pub fn toggle_line_numbers(&mut self) { 294 | if let Some(view) = self.views.get_mut(&self.current_view) { 295 | view.toggle_line_numbers(); 296 | } 297 | } 298 | } 299 | 300 | /// Methods ment to be called by the tui struct 301 | impl Editor { 302 | // We render if: 303 | // - the current view is dirty 304 | // - we switched views 305 | // - the style changed 306 | // - the terminal size changed 307 | pub fn render(&mut self, term: &mut W) -> Result<(), Error> { 308 | if let Some(view) = self.views.get_mut(&self.current_view) { 309 | debug!("rendering the current view"); 310 | view.render(term, &self.styles)?; 311 | } else { 312 | warn!("no view to render"); 313 | } 314 | Ok(()) 315 | } 316 | } 317 | -------------------------------------------------------------------------------- /src/widgets/view/view.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::max; 2 | use std::collections::HashMap; 3 | use std::io::Write; 4 | 5 | use failure::Error; 6 | use termion::clear::CurrentLine as ClearLine; 7 | use termion::cursor::Goto; 8 | use termion::event::{Event, Key, MouseButton, MouseEvent}; 9 | use xrl::{ConfigChanges, Line, LineCache, Style, Update}; 10 | 11 | use super::cfg::ViewConfig; 12 | use super::client::Client; 13 | use super::style::{reset_style, set_style}; 14 | use super::window::Window; 15 | 16 | #[derive(Debug, Default)] 17 | pub struct Cursor { 18 | pub line: u64, 19 | pub column: u64, 20 | } 21 | 22 | pub struct View { 23 | cache: LineCache, 24 | cursor: Cursor, 25 | window: Window, 26 | file: Option, 27 | client: Client, 28 | cfg: ViewConfig, 29 | } 30 | 31 | impl View { 32 | pub fn new(client: Client, file: Option) -> View { 33 | View { 34 | cache: LineCache::default(), 35 | cursor: Default::default(), 36 | window: Window::new(), 37 | cfg: ViewConfig::default(), 38 | client, 39 | file, 40 | } 41 | } 42 | 43 | pub fn update_cache(&mut self, update: Update) { 44 | info!("updating cache"); 45 | self.cache.update(update) 46 | } 47 | 48 | pub fn set_cursor(&mut self, line: u64, column: u64) { 49 | self.cursor = Cursor { line, column }; 50 | self.window.set_cursor(&self.cursor); 51 | } 52 | 53 | pub fn config_changed(&mut self, changes: ConfigChanges) { 54 | if let Some(tab_size) = changes.tab_size { 55 | self.cfg.tab_size = tab_size as u16; 56 | } 57 | } 58 | 59 | pub fn render( 60 | &mut self, 61 | w: &mut W, 62 | styles: &HashMap, 63 | ) -> Result<(), Error> { 64 | self.update_window(); 65 | self.render_lines(w, styles)?; 66 | self.render_cursor(w); 67 | Ok(()) 68 | } 69 | 70 | pub fn resize(&mut self, height: u16) { 71 | self.window.resize(height); 72 | self.update_window(); 73 | let top = self.cache.before() + self.window.start(); 74 | let bottom = self.cache.after() + self.window.end(); 75 | self.client.scroll(top, bottom); 76 | } 77 | 78 | pub fn insert(&mut self, c: char) { 79 | self.client.insert(c) 80 | } 81 | 82 | pub fn insert_newline(&mut self) { 83 | self.client.insert_newline() 84 | } 85 | 86 | pub fn insert_tab(&mut self) { 87 | self.client.insert_tab() 88 | } 89 | 90 | pub fn save(&mut self) { 91 | self.client.save(self.file.as_ref().unwrap()) 92 | } 93 | 94 | pub fn back(&mut self) { 95 | self.client.backspace() 96 | } 97 | 98 | pub fn delete(&mut self) { 99 | self.client.delete() 100 | } 101 | 102 | pub fn page_down(&mut self) { 103 | self.client.page_down() 104 | } 105 | 106 | pub fn page_up(&mut self) { 107 | self.client.page_up() 108 | } 109 | 110 | pub fn move_left(&mut self) { 111 | self.client.left() 112 | } 113 | 114 | pub fn move_right(&mut self) { 115 | self.client.right() 116 | } 117 | 118 | pub fn move_up(&mut self) { 119 | self.client.up() 120 | } 121 | 122 | pub fn move_down(&mut self) { 123 | self.client.down() 124 | } 125 | 126 | pub fn toggle_line_numbers(&mut self) { 127 | self.cfg.display_gutter = !self.cfg.display_gutter; 128 | } 129 | 130 | fn update_window(&mut self) { 131 | if self.cursor.line < self.cache.before() { 132 | error!( 133 | "cursor is on line {} but there are {} invalid lines in cache.", 134 | self.cursor.line, 135 | self.cache.before() 136 | ); 137 | return; 138 | } 139 | let cursor_line = self.cursor.line - self.cache.before(); 140 | let nb_lines = self.cache.lines().len() as u64; 141 | let gutter_size = (self.cache.before() + nb_lines + self.cache.after()) 142 | .to_string() 143 | .len() as u16; 144 | let gutter_size = gutter_size + 1; // Space between line number and content 145 | self.cfg.gutter_size = max(gutter_size, 4); // min gutter width 4 146 | self.window.update(cursor_line, nb_lines); 147 | } 148 | 149 | fn get_click_location(&self, x: u64, y: u64) -> (u64, u64) { 150 | let lineno = x + self.cache.before() + self.window.start(); 151 | if let Some(line) = self.cache.lines().get(x as usize) { 152 | if y < u64::from(self.cfg.gutter_size) { 153 | return (lineno, 0); 154 | } 155 | let mut text_len: u16 = 0; 156 | for (idx, c) in line.text.chars().enumerate() { 157 | let char_width = self.translate_char_width(text_len, c); 158 | text_len += char_width; 159 | if u64::from(text_len) >= y { 160 | // If the character at idx is wider than one column, 161 | // the click occurred within the character. Otherwise, 162 | // the click occurred on the character at idx + 1 163 | if char_width > 1 { 164 | return (lineno as u64, (idx - self.cfg.gutter_size as usize) as u64); 165 | } else { 166 | return ( 167 | lineno as u64, 168 | (idx - self.cfg.gutter_size as usize) as u64 + 1, 169 | ); 170 | } 171 | } 172 | } 173 | return (lineno, line.text.len() as u64 + 1); 174 | } else { 175 | warn!("no line at index {} found in cache", x); 176 | return (x, y); 177 | } 178 | } 179 | 180 | fn click(&mut self, x: u64, y: u64) { 181 | let (line, column) = self.get_click_location(x, y); 182 | self.client.click(line, column); 183 | } 184 | 185 | fn drag(&mut self, x: u64, y: u64) { 186 | let (line, column) = self.get_click_location(x, y); 187 | self.client.drag(line, column); 188 | } 189 | 190 | pub fn handle_input(&mut self, event: Event) { 191 | match event { 192 | Event::Key(key) => match key { 193 | Key::Char(c) => match c { 194 | '\n' => self.insert_newline(), 195 | '\t' => self.insert_tab(), 196 | _ => self.insert(c), 197 | }, 198 | Key::Ctrl(c) => match c { 199 | 'w' => self.save(), 200 | 'h' => self.back(), 201 | _ => error!("un-handled input ctrl+{}", c), 202 | }, 203 | Key::Backspace => self.back(), 204 | Key::Delete => self.delete(), 205 | Key::Left => self.client.left(), 206 | Key::Right => self.client.right(), 207 | Key::Up => self.client.up(), 208 | Key::Down => self.client.down(), 209 | Key::Home => self.client.home(), 210 | Key::End => self.client.end(), 211 | Key::PageUp => self.page_up(), 212 | Key::PageDown => self.page_down(), 213 | k => error!("un-handled key {:?}", k), 214 | }, 215 | Event::Mouse(mouse_event) => match mouse_event { 216 | MouseEvent::Press(press_event, y, x) => match press_event { 217 | MouseButton::Left => self.click(u64::from(x) - 1, u64::from(y) - 1), 218 | MouseButton::WheelUp => self.client.up(), 219 | MouseButton::WheelDown => self.client.down(), 220 | button => error!("un-handled button {:?}", button), 221 | }, 222 | MouseEvent::Release(..) => {} 223 | MouseEvent::Hold(y, x) => self.drag(u64::from(x) - 1, u64::from(y) - 1), 224 | }, 225 | ev => error!("un-handled event {:?}", ev), 226 | } 227 | } 228 | 229 | fn render_lines(&self, w: &mut W, styles: &HashMap) -> Result<(), Error> { 230 | debug!("rendering lines"); 231 | trace!("current cache\n{:?}", self.cache); 232 | 233 | // Get the lines that are within the displayed window 234 | let lines = self 235 | .cache 236 | .lines() 237 | .iter() 238 | .skip(self.window.start() as usize) 239 | .take(self.window.size() as usize); 240 | 241 | // Draw the valid lines within this range 242 | let mut line_strings = String::new(); 243 | let mut line_no = self.cache.before() + self.window.start(); 244 | for (line_index, line) in lines.enumerate() { 245 | line_strings.push_str(&self.render_line_str(line, Some(line_no), line_index, styles)); 246 | line_no += 1; 247 | } 248 | 249 | // If the number of lines is less than window height 250 | // render empty lines to fill the view window. 251 | let line_count = self.cache.lines().len() as u16; 252 | let win_size = self.window.size(); 253 | if win_size > line_count { 254 | for num in line_count..win_size { 255 | line_strings.push_str(&self.render_line_str( 256 | &Line::default(), 257 | None, 258 | num as usize, 259 | styles, 260 | )); 261 | } 262 | } 263 | w.write_all(line_strings.as_bytes())?; 264 | 265 | Ok(()) 266 | } 267 | 268 | // Next tab stop, assuming 0-based indexing 269 | fn tab_width_at_position(&self, position: u16) -> u16 { 270 | self.cfg.tab_size - (position % self.cfg.tab_size) 271 | } 272 | 273 | fn render_line_str( 274 | &self, 275 | line: &Line, 276 | lineno: Option, 277 | line_index: usize, 278 | styles: &HashMap, 279 | ) -> String { 280 | let text = self.escape_control_and_add_styles(styles, line); 281 | if let Some(line_no) = lineno { 282 | if self.cfg.display_gutter { 283 | let line_no = (line_no + 1).to_string(); 284 | let line_no_offset = self.cfg.gutter_size - line_no.len() as u16; 285 | format!( 286 | "{}{}{}{}{}", 287 | Goto(line_no_offset, line_index as u16 + 1), 288 | ClearLine, 289 | line_no, 290 | Goto(self.cfg.gutter_size + 1, line_index as u16 + 1), 291 | &text 292 | ) 293 | } else { 294 | format!("{}{}{}", Goto(0, line_index as u16 + 1), ClearLine, &text) 295 | } 296 | } else { 297 | format!( 298 | "{}{}{}", 299 | Goto(self.cfg.gutter_size + 1, line_index as u16 + 1), 300 | ClearLine, 301 | &text 302 | ) 303 | } 304 | } 305 | 306 | fn escape_control_and_add_styles(&self, styles: &HashMap, line: &Line) -> String { 307 | let mut position: u16 = 0; 308 | let mut text = String::with_capacity(line.text.capacity()); 309 | for c in line.text.chars() { 310 | match c { 311 | '\x00'..='\x08' | '\x0a'..='\x1f' | '\x7f' => { 312 | // Render in caret notation, i.e. '\x02' is rendered as '^B' 313 | text.push('^'); 314 | text.push((c as u8 ^ 0x40u8) as char); 315 | position += 2; 316 | } 317 | '\t' => { 318 | let tab_width = self.tab_width_at_position(position); 319 | text.push_str(&" ".repeat(tab_width as usize)); 320 | position += tab_width; 321 | } 322 | _ => { 323 | text.push(c); 324 | position += 1; 325 | } 326 | } 327 | } 328 | if line.styles.is_empty() { 329 | return text; 330 | } 331 | let mut style_sequences = self.get_style_sequences(styles, line); 332 | for style in style_sequences.drain(..) { 333 | trace!("inserting style: {:?}", style); 334 | if style.0 >= text.len() { 335 | text.push_str(&style.1); 336 | } else { 337 | text.insert_str(style.0, &style.1); 338 | } 339 | } 340 | trace!("styled line: {:?}", text); 341 | text 342 | } 343 | 344 | fn get_style_sequences( 345 | &self, 346 | styles: &HashMap, 347 | line: &Line, 348 | ) -> Vec<(usize, String)> { 349 | let mut style_sequences: Vec<(usize, String)> = Vec::new(); 350 | let mut prev_style_end: usize = 0; 351 | for style_def in &line.styles { 352 | let start_idx = if style_def.offset >= 0 { 353 | (prev_style_end + style_def.offset as usize) 354 | } else { 355 | // FIXME: does that actually work? 356 | (prev_style_end - ((-style_def.offset) as usize)) 357 | }; 358 | let end_idx = start_idx + style_def.length as usize; 359 | prev_style_end = end_idx; 360 | 361 | if let Some(style) = styles.get(&style_def.style_id) { 362 | let start_sequence = match set_style(style) { 363 | Ok(s) => s, 364 | Err(e) => { 365 | error!("could not get CSI sequence to set style {:?}: {}", style, e); 366 | continue; 367 | } 368 | }; 369 | let end_sequence = match reset_style(style) { 370 | Ok(s) => s, 371 | Err(e) => { 372 | error!( 373 | "could not get CSI sequence to reset style {:?}: {}", 374 | style, e 375 | ); 376 | continue; 377 | } 378 | }; 379 | style_sequences.push((start_idx, start_sequence)); 380 | style_sequences.push((end_idx, end_sequence)); 381 | } else { 382 | error!( 383 | "no style ID {} found. Not applying style.", 384 | style_def.style_id 385 | ); 386 | }; 387 | } 388 | // Note that we sort the vector in *reverse* order, so that we apply style starting from 389 | // the end of the line, and we don't have to worry about the indices changing. 390 | style_sequences.sort_by(|a, b| a.0.cmp(&b.0)); 391 | style_sequences.reverse(); 392 | trace!("{:?}", style_sequences); 393 | style_sequences 394 | } 395 | 396 | fn render_cursor(&self, w: &mut W) { 397 | info!("rendering cursor"); 398 | if self.cache.is_empty() { 399 | info!("cache is empty, rendering cursor at the top left corner"); 400 | if let Err(e) = write!(w, "{}", Goto(1, 1)) { 401 | error!("failed to render cursor: {}", e); 402 | } 403 | return; 404 | } 405 | 406 | if self.cursor.line < self.cache.before() { 407 | error!( 408 | "the cursor is on line {} which is marked invalid in the cache", 409 | self.cursor.line 410 | ); 411 | return; 412 | } 413 | // Get the line that has the cursor 414 | let line_idx = self.cursor.line - self.cache.before(); 415 | let line = match self.cache.lines().get(line_idx as usize) { 416 | Some(line) => line, 417 | None => { 418 | error!("no valid line at cursor index {}", self.cursor.line); 419 | return; 420 | } 421 | }; 422 | 423 | if line_idx < self.window.start() { 424 | error!( 425 | "the line that has the cursor (nb={}, cache_idx={}) not within the displayed window ({:?})", 426 | self.cursor.line, 427 | line_idx, 428 | self.window 429 | ); 430 | return; 431 | } 432 | // Get the line vertical offset so that we know where to draw it. 433 | let line_pos = line_idx - self.window.start(); 434 | 435 | // Calculate the cursor position on the line. The trick is that we know the position within 436 | // the string, but characters may have various lengths. For the moment, we only handle 437 | // control characters and tabs. We assume control characters (0x00-0x1f, excluding 0x09 == 438 | // tab) are rendered in caret notation and are thus two columns wide. Tabs are 439 | // variable-width, rounding up to the next tab stop. All other characters are assumed to be 440 | // one column wide. 441 | let column: u16 = line 442 | .text 443 | .chars() 444 | .take(self.cursor.column as usize) 445 | .fold(0, |acc, c| acc + self.translate_char_width(acc, c)); 446 | 447 | // Draw the cursor 448 | let cursor_pos = Goto(self.cfg.gutter_size + column + 1, line_pos as u16 + 1); 449 | if let Err(e) = write!(w, "{}", cursor_pos) { 450 | error!("failed to render cursor: {}", e); 451 | } 452 | info!("Cursor rendered at ({}, {})", line_pos, column); 453 | } 454 | 455 | fn translate_char_width(&self, position: u16, c: char) -> u16 { 456 | match c { 457 | // Caret notation means non-tab control characters are two columns wide 458 | '\x00'..='\x08' | '\x0a'..='\x1f' | '\x7f' => 2, 459 | '\t' => self.tab_width_at_position(position), 460 | _ => 1, 461 | } 462 | } 463 | } 464 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "adler32" 5 | version = "1.0.3" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | [[package]] 9 | name = "ansi_term" 10 | version = "0.11.0" 11 | source = "registry+https://github.com/rust-lang/crates.io-index" 12 | dependencies = [ 13 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 14 | ] 15 | 16 | [[package]] 17 | name = "antidote" 18 | version = "1.0.0" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | 21 | [[package]] 22 | name = "arc-swap" 23 | version = "0.3.11" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | 26 | [[package]] 27 | name = "arrayvec" 28 | version = "0.4.10" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | dependencies = [ 31 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 32 | ] 33 | 34 | [[package]] 35 | name = "atty" 36 | version = "0.2.11" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | dependencies = [ 39 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 40 | "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", 41 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 42 | ] 43 | 44 | [[package]] 45 | name = "autocfg" 46 | version = "0.1.4" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | 49 | [[package]] 50 | name = "backtrace" 51 | version = "0.3.30" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | dependencies = [ 54 | "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 55 | "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", 56 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 57 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 58 | "rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", 59 | ] 60 | 61 | [[package]] 62 | name = "backtrace-sys" 63 | version = "0.1.28" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | dependencies = [ 66 | "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", 67 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 68 | ] 69 | 70 | [[package]] 71 | name = "base64" 72 | version = "0.10.1" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | dependencies = [ 75 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 76 | ] 77 | 78 | [[package]] 79 | name = "bitflags" 80 | version = "1.1.0" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | 83 | [[package]] 84 | name = "build_const" 85 | version = "0.2.1" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | 88 | [[package]] 89 | name = "byteorder" 90 | version = "1.3.2" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | 93 | [[package]] 94 | name = "bytes" 95 | version = "0.4.12" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | dependencies = [ 98 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 99 | "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 100 | ] 101 | 102 | [[package]] 103 | name = "cc" 104 | version = "1.0.37" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | 107 | [[package]] 108 | name = "cfg-if" 109 | version = "0.1.9" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | 112 | [[package]] 113 | name = "chrono" 114 | version = "0.4.6" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | dependencies = [ 117 | "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", 118 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 119 | "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", 120 | ] 121 | 122 | [[package]] 123 | name = "clap" 124 | version = "2.33.0" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | dependencies = [ 127 | "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 128 | "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 129 | "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 130 | "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 131 | "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 132 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 133 | "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 134 | ] 135 | 136 | [[package]] 137 | name = "cloudabi" 138 | version = "0.0.3" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | dependencies = [ 141 | "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 142 | ] 143 | 144 | [[package]] 145 | name = "crc" 146 | version = "1.8.1" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | dependencies = [ 149 | "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 150 | ] 151 | 152 | [[package]] 153 | name = "crc32fast" 154 | version = "1.2.0" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | dependencies = [ 157 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 158 | ] 159 | 160 | [[package]] 161 | name = "crossbeam-deque" 162 | version = "0.7.1" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | dependencies = [ 165 | "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 166 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 167 | ] 168 | 169 | [[package]] 170 | name = "crossbeam-epoch" 171 | version = "0.7.1" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | dependencies = [ 174 | "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", 175 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 176 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 177 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 178 | "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 179 | "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 180 | ] 181 | 182 | [[package]] 183 | name = "crossbeam-queue" 184 | version = "0.1.2" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | dependencies = [ 187 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 188 | ] 189 | 190 | [[package]] 191 | name = "crossbeam-utils" 192 | version = "0.6.5" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | dependencies = [ 195 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 196 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 197 | ] 198 | 199 | [[package]] 200 | name = "dtoa" 201 | version = "0.4.4" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | 204 | [[package]] 205 | name = "failure" 206 | version = "0.1.5" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | dependencies = [ 209 | "backtrace 0.3.30 (registry+https://github.com/rust-lang/crates.io-index)", 210 | "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 211 | ] 212 | 213 | [[package]] 214 | name = "failure_derive" 215 | version = "0.1.5" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | dependencies = [ 218 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 219 | "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 220 | "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", 221 | "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", 222 | ] 223 | 224 | [[package]] 225 | name = "flate2" 226 | version = "1.0.7" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | dependencies = [ 229 | "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 230 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 231 | "miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 232 | "miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 233 | ] 234 | 235 | [[package]] 236 | name = "fnv" 237 | version = "1.0.6" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | 240 | [[package]] 241 | name = "fuchsia-cprng" 242 | version = "0.1.1" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | 245 | [[package]] 246 | name = "fuchsia-zircon" 247 | version = "0.3.3" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | dependencies = [ 250 | "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 251 | "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 252 | ] 253 | 254 | [[package]] 255 | name = "fuchsia-zircon-sys" 256 | version = "0.3.3" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | 259 | [[package]] 260 | name = "futures" 261 | version = "0.1.27" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | 264 | [[package]] 265 | name = "humantime" 266 | version = "1.2.0" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | dependencies = [ 269 | "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 270 | ] 271 | 272 | [[package]] 273 | name = "indexmap" 274 | version = "1.0.2" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | 277 | [[package]] 278 | name = "iovec" 279 | version = "0.1.2" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | dependencies = [ 282 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 283 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 284 | ] 285 | 286 | [[package]] 287 | name = "itoa" 288 | version = "0.4.4" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | 291 | [[package]] 292 | name = "kernel32-sys" 293 | version = "0.2.2" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | dependencies = [ 296 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 297 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 298 | ] 299 | 300 | [[package]] 301 | name = "lazy_static" 302 | version = "1.3.0" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | 305 | [[package]] 306 | name = "lazycell" 307 | version = "1.2.1" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | 310 | [[package]] 311 | name = "libc" 312 | version = "0.2.58" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | 315 | [[package]] 316 | name = "line-wrap" 317 | version = "0.1.1" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | dependencies = [ 320 | "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 321 | ] 322 | 323 | [[package]] 324 | name = "linked-hash-map" 325 | version = "0.5.2" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | 328 | [[package]] 329 | name = "lock_api" 330 | version = "0.1.5" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | dependencies = [ 333 | "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 334 | "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 335 | ] 336 | 337 | [[package]] 338 | name = "log" 339 | version = "0.4.6" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | dependencies = [ 342 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 343 | "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", 344 | ] 345 | 346 | [[package]] 347 | name = "log-mdc" 348 | version = "0.1.0" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | 351 | [[package]] 352 | name = "log4rs" 353 | version = "0.8.3" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | dependencies = [ 356 | "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 357 | "arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", 358 | "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 359 | "flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", 360 | "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 361 | "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 362 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 363 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 364 | "log-mdc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 365 | "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", 366 | "serde-value 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", 367 | "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", 368 | "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", 369 | "serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)", 370 | "thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 371 | "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 372 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 373 | ] 374 | 375 | [[package]] 376 | name = "memoffset" 377 | version = "0.2.1" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | 380 | [[package]] 381 | name = "miniz-sys" 382 | version = "0.1.12" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | dependencies = [ 385 | "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", 386 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 387 | ] 388 | 389 | [[package]] 390 | name = "miniz_oxide" 391 | version = "0.2.1" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | dependencies = [ 394 | "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 395 | ] 396 | 397 | [[package]] 398 | name = "miniz_oxide_c_api" 399 | version = "0.2.1" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | dependencies = [ 402 | "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", 403 | "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 404 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 405 | "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 406 | ] 407 | 408 | [[package]] 409 | name = "mio" 410 | version = "0.6.19" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | dependencies = [ 413 | "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 414 | "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 415 | "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 416 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 417 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 418 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 419 | "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 420 | "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", 421 | "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 422 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 423 | ] 424 | 425 | [[package]] 426 | name = "mio-named-pipes" 427 | version = "0.1.6" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | dependencies = [ 430 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 431 | "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", 432 | "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 433 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 434 | ] 435 | 436 | [[package]] 437 | name = "mio-uds" 438 | version = "0.6.7" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | dependencies = [ 441 | "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 442 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 443 | "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", 444 | ] 445 | 446 | [[package]] 447 | name = "miow" 448 | version = "0.2.1" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | dependencies = [ 451 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 452 | "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", 453 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 454 | "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 455 | ] 456 | 457 | [[package]] 458 | name = "miow" 459 | version = "0.3.3" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | dependencies = [ 462 | "socket2 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", 463 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 464 | ] 465 | 466 | [[package]] 467 | name = "net2" 468 | version = "0.2.33" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | dependencies = [ 471 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 472 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 473 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 474 | ] 475 | 476 | [[package]] 477 | name = "nodrop" 478 | version = "0.1.13" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | 481 | [[package]] 482 | name = "num-integer" 483 | version = "0.1.41" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | dependencies = [ 486 | "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 487 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 488 | ] 489 | 490 | [[package]] 491 | name = "num-traits" 492 | version = "0.2.8" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | dependencies = [ 495 | "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 496 | ] 497 | 498 | [[package]] 499 | name = "num_cpus" 500 | version = "1.10.1" 501 | source = "registry+https://github.com/rust-lang/crates.io-index" 502 | dependencies = [ 503 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 504 | ] 505 | 506 | [[package]] 507 | name = "numtoa" 508 | version = "0.1.0" 509 | source = "registry+https://github.com/rust-lang/crates.io-index" 510 | 511 | [[package]] 512 | name = "ordered-float" 513 | version = "1.0.2" 514 | source = "registry+https://github.com/rust-lang/crates.io-index" 515 | dependencies = [ 516 | "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 517 | ] 518 | 519 | [[package]] 520 | name = "owning_ref" 521 | version = "0.4.0" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | dependencies = [ 524 | "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 525 | ] 526 | 527 | [[package]] 528 | name = "parking_lot" 529 | version = "0.7.1" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | dependencies = [ 532 | "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 533 | "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 534 | ] 535 | 536 | [[package]] 537 | name = "parking_lot_core" 538 | version = "0.4.0" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | dependencies = [ 541 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 542 | "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 543 | "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 544 | "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 545 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 546 | ] 547 | 548 | [[package]] 549 | name = "plist" 550 | version = "0.4.2" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | dependencies = [ 553 | "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 554 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 555 | "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 556 | "line-wrap 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 557 | "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", 558 | "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 559 | ] 560 | 561 | [[package]] 562 | name = "proc-macro2" 563 | version = "0.4.30" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | dependencies = [ 566 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 567 | ] 568 | 569 | [[package]] 570 | name = "quick-error" 571 | version = "1.2.2" 572 | source = "registry+https://github.com/rust-lang/crates.io-index" 573 | 574 | [[package]] 575 | name = "quote" 576 | version = "0.6.12" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | dependencies = [ 579 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 580 | ] 581 | 582 | [[package]] 583 | name = "rand" 584 | version = "0.6.5" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | dependencies = [ 587 | "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 588 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 589 | "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 590 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 591 | "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 592 | "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 593 | "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 594 | "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 595 | "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 596 | "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 597 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 598 | ] 599 | 600 | [[package]] 601 | name = "rand_chacha" 602 | version = "0.1.1" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | dependencies = [ 605 | "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 606 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 607 | ] 608 | 609 | [[package]] 610 | name = "rand_core" 611 | version = "0.3.1" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | dependencies = [ 614 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 615 | ] 616 | 617 | [[package]] 618 | name = "rand_core" 619 | version = "0.4.0" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | 622 | [[package]] 623 | name = "rand_hc" 624 | version = "0.1.0" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | dependencies = [ 627 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 628 | ] 629 | 630 | [[package]] 631 | name = "rand_isaac" 632 | version = "0.1.1" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | dependencies = [ 635 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 636 | ] 637 | 638 | [[package]] 639 | name = "rand_jitter" 640 | version = "0.1.4" 641 | source = "registry+https://github.com/rust-lang/crates.io-index" 642 | dependencies = [ 643 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 644 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 645 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 646 | ] 647 | 648 | [[package]] 649 | name = "rand_os" 650 | version = "0.1.3" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | dependencies = [ 653 | "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 654 | "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 655 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 656 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 657 | "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 658 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 659 | ] 660 | 661 | [[package]] 662 | name = "rand_pcg" 663 | version = "0.1.2" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | dependencies = [ 666 | "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 667 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 668 | ] 669 | 670 | [[package]] 671 | name = "rand_xorshift" 672 | version = "0.1.1" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | dependencies = [ 675 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 676 | ] 677 | 678 | [[package]] 679 | name = "rdrand" 680 | version = "0.4.0" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | dependencies = [ 683 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 684 | ] 685 | 686 | [[package]] 687 | name = "redox_syscall" 688 | version = "0.1.54" 689 | source = "registry+https://github.com/rust-lang/crates.io-index" 690 | 691 | [[package]] 692 | name = "redox_termios" 693 | version = "0.1.1" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | dependencies = [ 696 | "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", 697 | ] 698 | 699 | [[package]] 700 | name = "rustc-demangle" 701 | version = "0.1.15" 702 | source = "registry+https://github.com/rust-lang/crates.io-index" 703 | 704 | [[package]] 705 | name = "rustc_version" 706 | version = "0.2.3" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | dependencies = [ 709 | "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 710 | ] 711 | 712 | [[package]] 713 | name = "ryu" 714 | version = "0.2.8" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | 717 | [[package]] 718 | name = "safemem" 719 | version = "0.3.0" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | 722 | [[package]] 723 | name = "same-file" 724 | version = "1.0.4" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | dependencies = [ 727 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 728 | ] 729 | 730 | [[package]] 731 | name = "scopeguard" 732 | version = "0.3.3" 733 | source = "registry+https://github.com/rust-lang/crates.io-index" 734 | 735 | [[package]] 736 | name = "semver" 737 | version = "0.9.0" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | dependencies = [ 740 | "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 741 | ] 742 | 743 | [[package]] 744 | name = "semver-parser" 745 | version = "0.7.0" 746 | source = "registry+https://github.com/rust-lang/crates.io-index" 747 | 748 | [[package]] 749 | name = "serde" 750 | version = "1.0.92" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | 753 | [[package]] 754 | name = "serde-value" 755 | version = "0.5.3" 756 | source = "registry+https://github.com/rust-lang/crates.io-index" 757 | dependencies = [ 758 | "ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 759 | "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", 760 | ] 761 | 762 | [[package]] 763 | name = "serde_derive" 764 | version = "1.0.92" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | dependencies = [ 767 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 768 | "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 769 | "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", 770 | ] 771 | 772 | [[package]] 773 | name = "serde_json" 774 | version = "1.0.39" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | dependencies = [ 777 | "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 778 | "ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 779 | "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", 780 | ] 781 | 782 | [[package]] 783 | name = "serde_yaml" 784 | version = "0.8.9" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | dependencies = [ 787 | "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 788 | "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 789 | "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", 790 | "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 791 | ] 792 | 793 | [[package]] 794 | name = "signal-hook" 795 | version = "0.1.9" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | dependencies = [ 798 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 799 | "signal-hook-registry 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 800 | ] 801 | 802 | [[package]] 803 | name = "signal-hook-registry" 804 | version = "1.0.1" 805 | source = "registry+https://github.com/rust-lang/crates.io-index" 806 | dependencies = [ 807 | "arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", 808 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 809 | ] 810 | 811 | [[package]] 812 | name = "slab" 813 | version = "0.4.2" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | 816 | [[package]] 817 | name = "smallvec" 818 | version = "0.6.10" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | 821 | [[package]] 822 | name = "socket2" 823 | version = "0.3.9" 824 | source = "registry+https://github.com/rust-lang/crates.io-index" 825 | dependencies = [ 826 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 827 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 828 | "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", 829 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 830 | ] 831 | 832 | [[package]] 833 | name = "stable_deref_trait" 834 | version = "1.1.1" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | 837 | [[package]] 838 | name = "strsim" 839 | version = "0.8.0" 840 | source = "registry+https://github.com/rust-lang/crates.io-index" 841 | 842 | [[package]] 843 | name = "syn" 844 | version = "0.15.36" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | dependencies = [ 847 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 848 | "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 849 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 850 | ] 851 | 852 | [[package]] 853 | name = "synstructure" 854 | version = "0.10.2" 855 | source = "registry+https://github.com/rust-lang/crates.io-index" 856 | dependencies = [ 857 | "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", 858 | "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 859 | "syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)", 860 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 861 | ] 862 | 863 | [[package]] 864 | name = "syntect" 865 | version = "3.2.0" 866 | source = "registry+https://github.com/rust-lang/crates.io-index" 867 | dependencies = [ 868 | "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 869 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 870 | "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 871 | "plist 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 872 | "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", 873 | "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", 874 | "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", 875 | "walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 876 | ] 877 | 878 | [[package]] 879 | name = "termion" 880 | version = "1.5.3" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | dependencies = [ 883 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 884 | "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 885 | "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", 886 | "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 887 | ] 888 | 889 | [[package]] 890 | name = "textwrap" 891 | version = "0.11.0" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | dependencies = [ 894 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 895 | ] 896 | 897 | [[package]] 898 | name = "thread-id" 899 | version = "3.3.0" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | dependencies = [ 902 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 903 | "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", 904 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 905 | ] 906 | 907 | [[package]] 908 | name = "time" 909 | version = "0.1.42" 910 | source = "registry+https://github.com/rust-lang/crates.io-index" 911 | dependencies = [ 912 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 913 | "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", 914 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 915 | ] 916 | 917 | [[package]] 918 | name = "tokio" 919 | version = "0.1.21" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | dependencies = [ 922 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 923 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 924 | "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", 925 | "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 926 | "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 927 | "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 928 | "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 929 | "tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 930 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 931 | "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 932 | "tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 933 | "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 934 | "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", 935 | "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 936 | "tokio-trace-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 937 | "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 938 | "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", 939 | ] 940 | 941 | [[package]] 942 | name = "tokio-codec" 943 | version = "0.1.1" 944 | source = "registry+https://github.com/rust-lang/crates.io-index" 945 | dependencies = [ 946 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 947 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 948 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 949 | ] 950 | 951 | [[package]] 952 | name = "tokio-current-thread" 953 | version = "0.1.6" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | dependencies = [ 956 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 957 | "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 958 | ] 959 | 960 | [[package]] 961 | name = "tokio-executor" 962 | version = "0.1.7" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | dependencies = [ 965 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 966 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 967 | ] 968 | 969 | [[package]] 970 | name = "tokio-fs" 971 | version = "0.1.6" 972 | source = "registry+https://github.com/rust-lang/crates.io-index" 973 | dependencies = [ 974 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 975 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 976 | "tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", 977 | ] 978 | 979 | [[package]] 980 | name = "tokio-io" 981 | version = "0.1.12" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | dependencies = [ 984 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 985 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 986 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 987 | ] 988 | 989 | [[package]] 990 | name = "tokio-process" 991 | version = "0.2.3" 992 | source = "registry+https://github.com/rust-lang/crates.io-index" 993 | dependencies = [ 994 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 995 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 996 | "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", 997 | "mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 998 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 999 | "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1000 | "tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 1001 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 1002 | ] 1003 | 1004 | [[package]] 1005 | name = "tokio-reactor" 1006 | version = "0.1.9" 1007 | source = "registry+https://github.com/rust-lang/crates.io-index" 1008 | dependencies = [ 1009 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 1010 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 1011 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1012 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1013 | "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", 1014 | "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 1015 | "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1016 | "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1017 | "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 1018 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1019 | "tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1020 | ] 1021 | 1022 | [[package]] 1023 | name = "tokio-signal" 1024 | version = "0.2.7" 1025 | source = "registry+https://github.com/rust-lang/crates.io-index" 1026 | dependencies = [ 1027 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 1028 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 1029 | "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", 1030 | "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", 1031 | "signal-hook 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1032 | "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 1033 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1034 | "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1035 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 1036 | ] 1037 | 1038 | [[package]] 1039 | name = "tokio-sync" 1040 | version = "0.1.6" 1041 | source = "registry+https://github.com/rust-lang/crates.io-index" 1042 | dependencies = [ 1043 | "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 1044 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 1045 | ] 1046 | 1047 | [[package]] 1048 | name = "tokio-tcp" 1049 | version = "0.1.3" 1050 | source = "registry+https://github.com/rust-lang/crates.io-index" 1051 | dependencies = [ 1052 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 1053 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 1054 | "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 1055 | "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", 1056 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1057 | "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1058 | ] 1059 | 1060 | [[package]] 1061 | name = "tokio-threadpool" 1062 | version = "0.1.14" 1063 | source = "registry+https://github.com/rust-lang/crates.io-index" 1064 | dependencies = [ 1065 | "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1066 | "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 1067 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 1068 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 1069 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1070 | "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 1071 | "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 1072 | "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1073 | "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 1074 | ] 1075 | 1076 | [[package]] 1077 | name = "tokio-timer" 1078 | version = "0.2.11" 1079 | source = "registry+https://github.com/rust-lang/crates.io-index" 1080 | dependencies = [ 1081 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 1082 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 1083 | "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1084 | "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 1085 | ] 1086 | 1087 | [[package]] 1088 | name = "tokio-trace-core" 1089 | version = "0.2.0" 1090 | source = "registry+https://github.com/rust-lang/crates.io-index" 1091 | dependencies = [ 1092 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1093 | ] 1094 | 1095 | [[package]] 1096 | name = "tokio-udp" 1097 | version = "0.1.3" 1098 | source = "registry+https://github.com/rust-lang/crates.io-index" 1099 | dependencies = [ 1100 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 1101 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 1102 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1103 | "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", 1104 | "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 1105 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1106 | "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1107 | ] 1108 | 1109 | [[package]] 1110 | name = "tokio-uds" 1111 | version = "0.2.5" 1112 | source = "registry+https://github.com/rust-lang/crates.io-index" 1113 | dependencies = [ 1114 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 1115 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 1116 | "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 1117 | "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", 1118 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1119 | "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", 1120 | "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", 1121 | "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 1122 | "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1123 | "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "traitobject" 1128 | version = "0.1.0" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | 1131 | [[package]] 1132 | name = "typemap" 1133 | version = "0.3.3" 1134 | source = "registry+https://github.com/rust-lang/crates.io-index" 1135 | dependencies = [ 1136 | "unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1137 | ] 1138 | 1139 | [[package]] 1140 | name = "unicode-width" 1141 | version = "0.1.5" 1142 | source = "registry+https://github.com/rust-lang/crates.io-index" 1143 | 1144 | [[package]] 1145 | name = "unicode-xid" 1146 | version = "0.1.0" 1147 | source = "registry+https://github.com/rust-lang/crates.io-index" 1148 | 1149 | [[package]] 1150 | name = "unsafe-any" 1151 | version = "0.4.2" 1152 | source = "registry+https://github.com/rust-lang/crates.io-index" 1153 | dependencies = [ 1154 | "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1155 | ] 1156 | 1157 | [[package]] 1158 | name = "vec_map" 1159 | version = "0.8.1" 1160 | source = "registry+https://github.com/rust-lang/crates.io-index" 1161 | 1162 | [[package]] 1163 | name = "walkdir" 1164 | version = "2.2.8" 1165 | source = "registry+https://github.com/rust-lang/crates.io-index" 1166 | dependencies = [ 1167 | "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 1168 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 1169 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 1170 | ] 1171 | 1172 | [[package]] 1173 | name = "winapi" 1174 | version = "0.2.8" 1175 | source = "registry+https://github.com/rust-lang/crates.io-index" 1176 | 1177 | [[package]] 1178 | name = "winapi" 1179 | version = "0.3.7" 1180 | source = "registry+https://github.com/rust-lang/crates.io-index" 1181 | dependencies = [ 1182 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1183 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1184 | ] 1185 | 1186 | [[package]] 1187 | name = "winapi-build" 1188 | version = "0.1.1" 1189 | source = "registry+https://github.com/rust-lang/crates.io-index" 1190 | 1191 | [[package]] 1192 | name = "winapi-i686-pc-windows-gnu" 1193 | version = "0.4.0" 1194 | source = "registry+https://github.com/rust-lang/crates.io-index" 1195 | 1196 | [[package]] 1197 | name = "winapi-util" 1198 | version = "0.1.2" 1199 | source = "registry+https://github.com/rust-lang/crates.io-index" 1200 | dependencies = [ 1201 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 1202 | ] 1203 | 1204 | [[package]] 1205 | name = "winapi-x86_64-pc-windows-gnu" 1206 | version = "0.4.0" 1207 | source = "registry+https://github.com/rust-lang/crates.io-index" 1208 | 1209 | [[package]] 1210 | name = "ws2_32-sys" 1211 | version = "0.2.1" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | dependencies = [ 1214 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 1215 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 1216 | ] 1217 | 1218 | [[package]] 1219 | name = "xdg" 1220 | version = "2.2.0" 1221 | source = "registry+https://github.com/rust-lang/crates.io-index" 1222 | 1223 | [[package]] 1224 | name = "xi-term" 1225 | version = "0.1.0" 1226 | dependencies = [ 1227 | "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", 1228 | "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1229 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 1230 | "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1231 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1232 | "log4rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", 1233 | "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", 1234 | "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", 1235 | "xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1236 | "xrl 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 1237 | ] 1238 | 1239 | [[package]] 1240 | name = "xml-rs" 1241 | version = "0.8.0" 1242 | source = "registry+https://github.com/rust-lang/crates.io-index" 1243 | 1244 | [[package]] 1245 | name = "xrl" 1246 | version = "0.0.8" 1247 | source = "registry+https://github.com/rust-lang/crates.io-index" 1248 | dependencies = [ 1249 | "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", 1250 | "futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", 1251 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", 1252 | "serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", 1253 | "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", 1254 | "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", 1255 | "syntect 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1256 | "tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", 1257 | "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 1258 | "tokio-process 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 1259 | ] 1260 | 1261 | [[package]] 1262 | name = "yaml-rust" 1263 | version = "0.4.3" 1264 | source = "registry+https://github.com/rust-lang/crates.io-index" 1265 | dependencies = [ 1266 | "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 1267 | ] 1268 | 1269 | [metadata] 1270 | "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" 1271 | "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 1272 | "checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" 1273 | "checksum arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "bc4662175ead9cd84451d5c35070517777949a2ed84551764129cedb88384841" 1274 | "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" 1275 | "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" 1276 | "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" 1277 | "checksum backtrace 0.3.30 (registry+https://github.com/rust-lang/crates.io-index)" = "ada4c783bb7e7443c14e0480f429ae2cc99da95065aeab7ee1b81ada0419404f" 1278 | "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" 1279 | "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" 1280 | "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" 1281 | "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" 1282 | "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" 1283 | "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" 1284 | "checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" 1285 | "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" 1286 | "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" 1287 | "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" 1288 | "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 1289 | "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" 1290 | "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" 1291 | "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" 1292 | "checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" 1293 | "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" 1294 | "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" 1295 | "checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" 1296 | "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" 1297 | "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" 1298 | "checksum flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f87e68aa82b2de08a6e037f1385455759df6e445a8df5e005b4297191dbf18aa" 1299 | "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" 1300 | "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 1301 | "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 1302 | "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 1303 | "checksum futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "a2037ec1c6c1c4f79557762eab1f7eae1f64f6cb418ace90fae88f0942b60139" 1304 | "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" 1305 | "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" 1306 | "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" 1307 | "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" 1308 | "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 1309 | "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" 1310 | "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" 1311 | "checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" 1312 | "checksum line-wrap 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" 1313 | "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" 1314 | "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" 1315 | "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" 1316 | "checksum log-mdc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" 1317 | "checksum log4rs 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "100052474df98158c0738a7d3f4249c99978490178b5f9f68cd835ac57adbd1b" 1318 | "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" 1319 | "checksum miniz-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9e3ae51cea1576ceba0dde3d484d30e6e5b86dee0b2d412fe3a16a15c98202" 1320 | "checksum miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c468f2369f07d651a5d0bb2c9079f8488a66d5466efe42d0c5c6466edcb7f71e" 1321 | "checksum miniz_oxide_c_api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7fe927a42e3807ef71defb191dc87d4e24479b221e67015fe38ae2b7b447bab" 1322 | "checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" 1323 | "checksum mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f5e374eff525ce1c5b7687c4cef63943e7686524a387933ad27ca7ec43779cb3" 1324 | "checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" 1325 | "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" 1326 | "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" 1327 | "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" 1328 | "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" 1329 | "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" 1330 | "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" 1331 | "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" 1332 | "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" 1333 | "checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518" 1334 | "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" 1335 | "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" 1336 | "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" 1337 | "checksum plist 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a9f075f6394100e7c105ed1af73fb1859d6fd14e49d4290d578120beb167f" 1338 | "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 1339 | "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" 1340 | "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" 1341 | "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" 1342 | "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" 1343 | "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 1344 | "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" 1345 | "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" 1346 | "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" 1347 | "checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" 1348 | "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" 1349 | "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" 1350 | "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" 1351 | "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 1352 | "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" 1353 | "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" 1354 | "checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" 1355 | "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1356 | "checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f" 1357 | "checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" 1358 | "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" 1359 | "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" 1360 | "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1361 | "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1362 | "checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be" 1363 | "checksum serde-value 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7a663f873dedc4eac1a559d4c6bc0d0b2c34dc5ac4702e105014b8281489e44f" 1364 | "checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e" 1365 | "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" 1366 | "checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582" 1367 | "checksum signal-hook 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "72ab58f1fda436857e6337dcb6a5aaa34f16c5ddc87b3a8b6ef7a212f90b9c5a" 1368 | "checksum signal-hook-registry 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cded4ffa32146722ec54ab1f16320568465aa922aa9ab4708129599740da85d7" 1369 | "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1370 | "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" 1371 | "checksum socket2 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "4e626972d3593207547f14bf5fc9efa4d0e7283deb73fef1dff313dae9ab8878" 1372 | "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" 1373 | "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 1374 | "checksum syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)" = "8b4f551a91e2e3848aeef8751d0d4eec9489b6474c720fd4c55958d8d31a430c" 1375 | "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" 1376 | "checksum syntect 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e80b8831c5a543192ffc3727f01cf0e57579c6ac15558e3048bfb5708892167b" 1377 | "checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" 1378 | "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 1379 | "checksum thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" 1380 | "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" 1381 | "checksum tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "ec2ffcf4bcfc641413fa0f1427bf8f91dfc78f56a6559cbf50e04837ae442a87" 1382 | "checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" 1383 | "checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443" 1384 | "checksum tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "83ea44c6c0773cc034771693711c35c677b4b5a4b21b9e7071704c54de7d555e" 1385 | "checksum tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe6dc22b08d6993916647d108a1a7d15b9cd29c4f4496c62b92c45b5041b7af" 1386 | "checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" 1387 | "checksum tokio-process 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88e1281e412013f1ff5787def044a9577a0bed059f451e835f1643201f8b777d" 1388 | "checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce" 1389 | "checksum tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "dd6dc5276ea05ce379a16de90083ec80836440d5ef8a6a39545a3207373b8296" 1390 | "checksum tokio-sync 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2162248ff317e2bc713b261f242b69dbb838b85248ed20bb21df56d60ea4cae7" 1391 | "checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" 1392 | "checksum tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72558af20be886ea124595ea0f806dd5703b8958e4705429dd58b3d8231f72f2" 1393 | "checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e" 1394 | "checksum tokio-trace-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9c8a256d6956f7cb5e2bdfe8b1e8022f1a09206c6c2b1ba00f3b746b260c613" 1395 | "checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" 1396 | "checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" 1397 | "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" 1398 | "checksum typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "653be63c80a3296da5551e1bfd2cca35227e13cdd08c6668903ae2f4f77aa1f6" 1399 | "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" 1400 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 1401 | "checksum unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f" 1402 | "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" 1403 | "checksum walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c7904a7e2bb3cdf0cf5e783f44204a85a37a93151738fa349f06680f59a98b45" 1404 | "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 1405 | "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" 1406 | "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 1407 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1408 | "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" 1409 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1410 | "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 1411 | "checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" 1412 | "checksum xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5" 1413 | "checksum xrl 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92cbe4c2a4df52b07f17ae37e64936772a696ca78bb6489e2ba72a70ccbf81d0" 1414 | "checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" 1415 | --------------------------------------------------------------------------------