1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use session::Session;
use rpc::*;
use rpc::value::{Value, Integer};
use neovim_api::NeovimApi;
use std::fmt;
use std::error::Error;

pub struct Neovim {
    pub session: Session,
}

pub struct UiAttachOptions {
    rgb: bool,
    popupmenu_external: bool,
}

impl UiAttachOptions {
    pub fn new() -> UiAttachOptions {
        UiAttachOptions { 
            rgb: true,
            popupmenu_external: false,
        }
    }

    pub fn set_rgb(&mut self, rgb: bool) {
        self.rgb = rgb;
    }

    pub fn set_popupmenu_external(&mut self, popupmenu_external: bool) {
        self.popupmenu_external = popupmenu_external;
    }

    fn to_value_map(&self) -> Value {
        Value::Map(vec![(Value::String("rgb".to_owned()), Value::Boolean(self.rgb)), (Value::String("popupmenu_external".to_owned()), Value::Boolean(self.popupmenu_external))])
    }
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum CallError {
    GenericError(String),
    NeovimError(u64, String),
}

impl fmt::Display for CallError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CallError::GenericError(ref s) => write!(f, "Unknown error type: {}", s),
            CallError::NeovimError(id, ref s) => write!(f, "{} - {}", id, s),
        }
    }
}

impl Error for CallError {
    fn description(&self) -> &str {
        match *self {
            CallError::GenericError(ref s) => s,
            CallError::NeovimError(_, ref s) => s,
        }
    }
}


#[doc(hidden)]
pub fn map_generic_error(err: Value) -> CallError {
    match err {
        Value::String(val) => CallError::GenericError(val),
        Value::Array(arr) => {
            if arr.len() == 2 {
                match (&arr[0], &arr[1]) {
                    (&Value::Integer(Integer::U64(id)), &Value::String(ref val)) => {
                        CallError::NeovimError(id, val.to_owned())
                    }
                    _ => CallError::GenericError(format!("{:?}", arr)),
                }
            } else {
                CallError::GenericError(format!("{:?}", arr))
            }
        }
        val => CallError::GenericError(format!("{:?}", val)),
    }
}

#[doc(hidden)]
pub fn map_result<T: FromVal<Value>>(val: Value) -> T {
    T::from_val(val)
}

impl Neovim {
    pub fn new(session: Session) -> Neovim {
        Neovim { session: session }
    }

    /// Register as a remote UI.
    ///
    /// After this method is called, the client will receive redraw notifications.
    pub fn ui_attach(&mut self, width: u64, height: u64, opts: UiAttachOptions) -> Result<(), CallError>  {
        self.session
            .call("nvim_ui_attach", &call_args!(width, height, opts.to_value_map()))
            .map_err(map_generic_error)
            .map(|_| ())
    }

    /// Unregister as a remote UI.
    pub fn ui_detach(&mut self) -> Result<(), CallError> {
        self.session.call("ui_detach", &vec![]).map_err(map_generic_error).map(|_| ())
    }

    /// Notify nvim that the client window has resized.
    ///
    /// If possible, nvim will send a redraw request to resize.
    pub fn ui_try_resize(&mut self, width: u64, height: u64) -> Result<(), CallError> {
        self.session
            .call("ui_try_resize", &call_args!(width, height))
            .map_err(map_generic_error)
            .map(|_| ())
    }

    /// Send a quit command to Nvim.
    /// The quit command is 'qa!' which will make Nvim quit without
    /// saving anything.
    pub fn quit_no_save(&mut self) -> Result<(), CallError> {
        self.command("qa!")
    }
}