-
Notifications
You must be signed in to change notification settings - Fork 28
Description
General thoughts
A lot of the API takes or returns a Value, and leaves it to the user to sort out what to put in or get out. Nvim-rs will try to improve upon this.
-
One tool will be using
TryFromon theValues sent from neovim and return an error containing the value if it failed. This will need an additional variant inCallError, so it's a breaking change. -
A second thing to do is to handwrite more if the API and manually do conversions that aren't done by the autogenerated API. Below is a list of functions which are affected, grouped by some ad-hoc thoughts, sometimes with comments. Those changes will of course be breaking, too.
-
Thirdly, provide common structs. This will come from rewriting the API mostly, but contain some more things (events, like
nvim_buf_line_events, fromValues... which are there? UI events for sure, which are quite an undertaking in themselves). -
A fourth, unreflected idea is to help people handle requests/notifications, which wrap arguments as
Values. There's no way to know the structure beforehand, so the way probably is having people define structs and usermp-serdefor deserialization. So we could write examples? Does that need new error variants? I.e. what does serde emit, and do we need to return that?
Plans
Changing CallError and using TryFrom should be a next step. Needs a new release of msgpack-rust, though, might need to ping the maintainers.
Changing the API is a major undertaking, and might be open-ended. Maybe we can do it in batches, grouped like below? Would like feedback :)
Providing event types can probably be made non-breaking (with the right use of generics, since Value implements TryFrom<Value>), so we could go slower.
The API functions
Nvim Options:
Those handle nvim options. Maybe make an NvimOption enum and work with that? Types are a closed set (String, Bool, Number - what is that exactly?), so it shouldn't be hard.
buffer.get_option(
&self, name: &str
) -> Result<Value, Box<CallError>>
buffer.set_option(
&self, name: &str, value: Value,
) -> Result<(), Box<CallError>>
window.get_option(
&self, name: &str
) -> Result<Value, Box<CallError>>
window.set_option(
&self, name: &str, value: Value,
) -> Result<(), Box<CallError>>
neovim.set_option(
&self, name: &str, value: Value,
) -> Result<(), Box<CallError>>
neovim.get_option(
&self, name: &str
) -> Result<Value, Box<CallError>>
// This is actually just a bool. Could also take a UiOption
neovim.ui_set_option(
&self, name: &str, value: Value,
) -> Result<(), Box<CallError>>Variables:
Those deal with variables in neovim. Can be more types than options. Partially solvable by just using generics nicely, but getting heterogenous things back might just be a case for point 4 above.
buffer.get_var(
&self,
name: &str
) -> Result<Value, Box<CallError>>
buffer.set_var(
&self, name: &str, value: Value,
) -> Result<(), Box<CallError>>
window.get_var(
&self,
name: &str
) -> Result<Value, Box<CallError>>
window.set_var(
&self, name: &str, value: Value,
) -> Result<(), Box<CallError>>
tabpage.get_var(
&self, name: &str
) -> Result<Value, Box<CallError>>
tabpage.set_var(
&self, name: &str, value: Value,
) -> Result<(), Box<CallError>>
neovim.get_var(
&self, name: &str
) -> Result<Value, Box<CallError>>
neovim.set_var(
&self, name: &str, value: Value,
) -> Result<(), Box<CallError>>
neovim.get_vvar(
&self, name: &str
) -> Result<Value, Box<CallError>>
neovim.set_vvar(
&self, name: &str, value: Value,
) -> Result<(), Box<CallError>>Fns with Values we're receiving
Receving Values means we need to parse them for the user. Sometimes easy, somtimes borderline impossible. Problems are heterogeneous Dictionaries, and deeply nested things. Might be solvable with custom types in several cases, but might be too hard or complex in others.
// Returns something very complex, we might just skip this fn
neovim.parse_expression(
&self, expr: &str, flags: &str, highlight: bool,
) -> Result<Vec<(Value, Value)>, Box<CallError>>
// List of Dicts, keys are strings, values are heterogenous
neovim.list_uis(
&self
) -> Result<Vec<Value>, Box<CallError>>
// List of i64
neovim.get_proc_children(
&self, pid: i64,
) -> Result<Vec<Value>, Box<CallError>>
// Map of process properties(??) or Nil
neovim.get_proc(
&self,
pid: i64
) -> Result<Value, Box<CallError>>
// Dict names -> ids
neovim.get_namespaces(
&self,
) -> Result<Vec<(Value, Value)>, Box<CallError>>
// Dicts names -> 24bit Values
neovim.get_color_map(
&self,
) -> Result<Vec<(Value, Value)>, Box<CallError>>
// Dictionary { "mode": String, "blocking": Boolean }
neovim.get_mode(
&self
) -> Result<Vec<(Value, Value)>, Box<CallError>>
// 2-tuple channelid, api map
neovim.get_api_info(
&self
) -> Result<Vec<Value>, Box<CallError>>
neovim.get_chan_info(
&self, chan: i64,
) -> Result<Vec<(Value, Value)>, Box<CallError>>
// Array of dictionaries from get_chan_info
neovim.list_chans(
&self
) -> Result<Vec<Value>, Box<CallError>>Fns with Values we're sending
Sending Values means we have to encode them for the user. Sounds easy, but unless we allow functions with a gazillion single arguments we probably needs predefined structures the user needs to pass in. Options are also often heterogenous dictionaries, and might change when neovim evolves.
neovim.set_client_info(
&self, name: &str, version: Vec<(Value, Value)>, typ: &str, methods: Vec<(Value, Value)>, attributes: Vec<(Value, Value)>,
) -> Result<(), Box<CallError>>
neovim.select_popupmenu_item(
&self, item: i64, insert: bool, finish: bool, opts: Vec<(Value, Value)>,
) -> Result<(), Box<CallError>>
neovim.open_win(
&self, buffer: &Buffer<W>, enter: bool, config: Vec<(Value, Value)>,
) -> Result<Window<W>, Box<CallError>>
buffer.attach(
&self, send_buffer: bool, opts: Vec<(Value, Value)>,
) -> Result<bool, Box<CallError>>Keymap, extmarks, virtualtext, window config, highlights
Those are kind of similar in that we might need to introduce structs to pass in or to return, but they exist in nice groups which could be tackled one by one.
neovim.get_keymap(
&self, mode: &str,
) -> Result<Vec<Vec<(Value, Value)>>, Box<CallError>>
neovim.set_keymap(
&self, mode: &str, lhs: &str, rhs: &str, opts: Vec<(Value, Value)>,
) -> Result<(), Box<CallError>>
buffer.get_keymap(
&self, mode: &str,
) -> Result<Vec<Vec<(Value, Value)>>, Box<CallError>>
buffer.set_keymap(
&self, mode: &str, lhs: &str, rhs: &str, opts: Vec<(Value, Value)>,
) -> Result<(), Box<CallError>>
buffer.get_extmarks(
&self, ns_id: i64, start: Value, end: Value, opts: Vec<(Value, Value)>,
) -> Result<Vec<Value>, Box<CallError>>
buffer.set_extmark(
&self, ns_id: i64, id: i64, line: i64, col: i64, opts: Vec<(Value, Value)>,
) -> Result<i64, Box<CallError>>
buffer.set_virtual_text(
&self, ns_id: i64, line: i64, chunks: Vec<Value>, opts: Vec<(Value, Value)>,
) -> Result<i64, Box<CallError>>
buffer.get_virtual_text(
&self, lnum: i64,
) -> Result<Vec<Value>, Box<CallError>>
window.set_config(
&self, config: Vec<(Value, Value)>,
) -> Result<(), Box<CallError>>
window.get_config(
&self,
) -> Result<Vec<(Value, Value)>, Box<CallError>>
neovim.get_hl_by_name(
&self, name: &str, rgb: bool,
) -> Result<Vec<(Value, Value)>, Box<CallError>>
neovim.get_hl_by_id(
&self, hl_id: i64, rgb: bool,
) -> Result<Vec<(Value, Value)>, Box<CallError>>Complex things that might return very different things
Basically, like variables. This time though, there's lua and viml to consider.
neovim.call_atomic(
&self, calls: Vec<Value>,
) -> Result<Vec<Value>, Box<CallError>>
neovim.eval(
&self, expr: &str
) -> Result<Value, Box<CallError>>
neovim.execute_lua(
&self, code: &str, args: Vec<Value>,
) -> Result<Value, Box<CallError>>
neovim.exec_lua(
&self, code: &str, args: Vec<Value>,
) -> Result<Value, Box<CallError>>
neovim.call_function(
&self, fname: &str, args: Vec<Value>,
) -> Result<Value, Box<CallError>>
neovim.call_dict_function(
&self, dict: Value, fname: &str, args: Vec<Value>,
) -> Result<Value, Box<CallError>>Fns that send & receive Values
Just because I couldn't find another category. Might just be we need to define the right structs?
neovim.get_context(
&self, opts: Vec<(Value, Value)>,
) -> Result<Vec<(Value, Value)>, Box<CallError>>
neovim.load_context(
&self, dict: Vec<(Value, Value)>,
) -> Result<Value, Box<CallError>>
neovim.get_commands(
&self, opts: Vec<(Value, Value)>,
) -> Result<Vec<(Value, Value)>, Box<CallError>>
buffer.get_commands(
&self, opts: Vec<(Value, Value)>,
) -> Result<Vec<(Value, Value)>, Box<CallError>>