<commit_before>use std::io::{self, Write};

use futures::{future, Async, Future, Poll, Sink, Stream};
use futures::sync::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};

use termion::event::{Event, Key};
use tokio::run;
use xrl::{AvailablePlugins, Client, ConfigChanged, Frontend, FrontendBuilder,
          PluginStarted, PluginStoped, ScrollTo, ServerResult, Style, ThemeChanged, Update,
          UpdateCmds};

use xdg::BaseDirectories;
use failure::Error;

use core::{Terminal, TerminalEvent, Command};
use widgets::{Editor, CommandPrompt};


pub struct Tui {
    pub editor: Editor,
    pub prompt: Option<CommandPrompt>,
    pub term: Terminal,
    pub term_size: (u16, u16),
    pub shutdown: bool,
}

impl Tui {
    pub fn new(
        mut client: Client,
        events: UnboundedReceiver<CoreEvent>,
    ) -> Result<Self, Error> {

        let conf_dir = BaseDirectories::with_prefix("xi")
            .ok()
            .and_then(|dirs| Some(dirs.get_config_home().to_string_lossy().into_owned()));
        run(
            client
                .client_started(conf_dir.as_ref().map(|dir| &**dir), None)
                .map_err(|_| ()),
        );

        Ok(Tui {
            term: Terminal::new()?,
            shutdown: false,
            term_size: (0, 0),
            editor: Editor::new(client, events),
            prompt: None,
        })
    }

    fn handle_resize(&mut self, size: (u16, u16)) {
        self.term_size = size;
        self.editor.handle_resize(size);
    }

    fn exit(&mut self) {
        self.shutdown = true;
    }

    pub fn handle_cmd(&mut self, cmd: Command) {
        match cmd {
            Command::Cancel => {
                self.prompt = None;
            },
            Command::Quit => self.exit(),
            Command::Save(view) => self.editor.save(view),
            Command::Invalid(cmd) => {
                error!("Received invalid editor command: {}", cmd);
            }
        }
    }

    /// Global keybindings can be parsed here
    fn handle_input(&mut self, event: Event) {
        match event {
            Event::Key(Key::Ctrl('c')) => self.exit(),
            Event::Key(Key::Char(':')) => {
                if let Some(ref mut prompt) = self.prompt {
                    prompt.handle_input(event);
                } else {
                    self.prompt = Some(CommandPrompt::default());
                }
            },
            event => {
                let mut out = None;
                if let Some(ref mut prompt) = self.prompt {
                    if let Some(cmd) = prompt.handle_input(event) {
                        out = Some(cmd);
                    }
                } else {
                    self.editor.handle_input(event);
                }
                if let Some(out) = out {<commit_msg>change open prompt command to ^:<commit_after>use std::io::{self, Write};

use futures::{future, Async, Future, Poll, Sink, Stream};
use futures::sync::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};

use termion::event::{Event, Key};
use tokio::run;
use xrl::{AvailablePlugins, Client, ConfigChanged, Frontend, FrontendBuilder,
          PluginStarted, PluginStoped, ScrollTo, ServerResult, Style, ThemeChanged, Update,
          UpdateCmds};

use xdg::BaseDirectories;
use failure::Error;

use core::{Terminal, TerminalEvent, Command};
use widgets::{Editor, CommandPrompt};


pub struct Tui {
    pub editor: Editor,
    pub prompt: Option<CommandPrompt>,
    pub term: Terminal,
    pub term_size: (u16, u16),
    pub shutdown: bool,
}

impl Tui {
    pub fn new(
        mut client: Client,
        events: UnboundedReceiver<CoreEvent>,
    ) -> Result<Self, Error> {

        let conf_dir = BaseDirectories::with_prefix("xi")
            .ok()
            .and_then(|dirs| Some(dirs.get_config_home().to_string_lossy().into_owned()));
        run(
            client
                .client_started(conf_dir.as_ref().map(|dir| &**dir), None)
                .map_err(|_| ()),
        );

        Ok(Tui {
            term: Terminal::new()?,
            shutdown: false,
            term_size: (0, 0),
            editor: Editor::new(client, events),
            prompt: None,
        })
    }

    fn handle_resize(&mut self, size: (u16, u16)) {
        self.term_size = size;
        self.editor.handle_resize(size);
    }

    fn exit(&mut self) {
        self.shutdown = true;
    }

    pub fn handle_cmd(&mut self, cmd: Command) {
        match cmd {
            Command::Cancel => {
                self.prompt = None;
            },
            Command::Quit => self.exit(),
            Command::Save(view) => self.editor.save(view),
            Command::Invalid(cmd) => {
                error!("Received invalid editor command: {}", cmd);
            }
        }
    }

    /// Global keybindings can be parsed here
    fn handle_input(&mut self, event: Event) {
        match event {
            Event::Key(Key::Ctrl('c')) => self.exit(),
            Event::Key(Key::Ctrl(':')) => {
                if let Some(ref mut prompt) = self.prompt {
                    prompt.handle_input(event);
                } else {
                    self.prompt = Some(CommandPrompt::default());
                }
            },
            event => {
                let mut out = None;
                if let Some(ref mut prompt) = self.prompt {
                    if let Some(cmd) = prompt.handle_input(event) {
                        out = Some(cmd);
                    }
                } else {
                    self.editor.handle_input(event);
                }
                if let Some(out) = out {
{'fraction_non_alphanumeric': 0.1322196552336947, 'fraction_numerical': 0.003554291807357384, 'mean_word_length': 1.794438927507448, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5063095', 'n_tokens_mistral': 1671, 'n_tokens_neox': 1592, 'n_words': 373}