use oxi_types::{
conversion::{self, FromObject, ToObject},
serde::Deserializer,
Array,
Object,
};
#[cfg(feature = "neovim-nightly")]
use oxi_types::{Boolean, Dictionary, Integer, String as NvimString};
use serde::Deserialize;
use super::{CmdMagic, CmdRange, CommandAddr, CommandModifiers, CommandNArgs};
use crate::serde_utils as utils;
#[non_exhaustive]
#[derive(Clone, Debug, Default, Deserialize)]
pub struct CmdInfos {
#[serde(default, deserialize_with = "utils::none_literal_is_none")]
pub addr: Option<CommandAddr>,
#[serde(default)]
pub args: Vec<String>,
#[serde(default)]
pub bang: Option<bool>,
#[serde(default)]
pub cmd: Option<String>,
#[serde(default, deserialize_with = "utils::minus_one_is_none")]
pub count: Option<u32>,
#[serde(default)]
pub magic: Option<CmdMagic>,
#[serde(default)]
pub mods: Option<CommandModifiers>,
#[serde(default)]
pub nargs: Option<CommandNArgs>,
#[serde(default, deserialize_with = "utils::empty_string_is_none")]
pub nextcmd: Option<String>,
#[serde(default)]
pub range: Option<CmdRange>,
#[serde(default, deserialize_with = "utils::char_from_string")]
pub reg: Option<char>,
}
impl CmdInfos {
#[inline(always)]
pub fn builder() -> CmdInfosBuilder {
CmdInfosBuilder::default()
}
}
#[derive(Clone, Default)]
pub struct CmdInfosBuilder(CmdInfos);
impl CmdInfosBuilder {
#[inline]
pub fn args<S, I>(&mut self, iter: I) -> &mut Self
where
S: Into<String>,
I: IntoIterator<Item = S>,
{
self.0.args = iter.into_iter().map(Into::into).collect();
self
}
#[inline]
pub fn bang(&mut self, bang: bool) -> &mut Self {
self.0.bang = Some(bang);
self
}
#[inline]
pub fn cmd(&mut self, cmd: impl Into<String>) -> &mut Self {
self.0.cmd = Some(cmd.into());
self
}
#[inline]
pub fn count(&mut self, count: u32) -> &mut Self {
self.0.count = Some(count);
self
}
#[inline]
pub fn magic(&mut self, magic: CmdMagic) -> &mut Self {
self.0.magic = Some(magic);
self
}
#[inline]
pub fn mods(&mut self, mods: CommandModifiers) -> &mut Self {
self.0.mods = Some(mods);
self
}
#[inline]
pub fn nargs(&mut self, nargs: CommandNArgs) -> &mut Self {
self.0.nargs = Some(nargs);
self
}
#[inline]
pub fn nextcmd(&mut self, nextcmd: impl Into<String>) -> &mut Self {
self.0.nextcmd = Some(nextcmd.into());
self
}
#[inline]
pub fn range(&mut self, range: CmdRange) -> &mut Self {
self.0.range = Some(range);
self
}
#[inline]
pub fn reg(&mut self, reg: char) -> &mut Self {
self.0.reg = Some(reg);
self
}
#[inline]
pub fn build(&mut self) -> CmdInfos {
std::mem::take(&mut self.0)
}
}
impl FromObject for CmdInfos {
#[inline]
fn from_object(obj: Object) -> Result<Self, conversion::Error> {
Self::deserialize(Deserializer::new(obj)).map_err(Into::into)
}
}
#[cfg(not(feature = "neovim-nightly"))]
#[derive(Default, Debug)]
#[allow(non_camel_case_types)]
#[repr(C)]
pub(crate) struct KeyDict_cmd {
cmd: Object,
reg: Object,
bang: Object,
addr: Object,
mods: Object,
args: Object,
count: Object,
magic: Object,
nargs: Object,
range: Object,
nextcmd: Object,
}
#[cfg(feature = "neovim-nightly")]
#[derive(Default, Debug)]
#[allow(non_camel_case_types)]
#[repr(C)]
pub(crate) struct KeyDict_cmd {
mask: u64,
cmd: NvimString,
range: Array,
count: Integer,
reg: NvimString,
bang: Boolean,
args: Array,
magic: Dictionary,
mods: Dictionary,
nargs: Object,
addr: Object,
nextcmd: Object,
}
impl From<&CmdInfos> for KeyDict_cmd {
#[inline]
fn from(infos: &CmdInfos) -> Self {
#[cfg(not(feature = "neovim-nightly"))]
{
Self {
cmd: infos.cmd.clone().into(),
reg: infos.reg.into(),
bang: infos.bang.into(),
addr: infos
.addr
.map(|v| v.to_object().unwrap())
.unwrap_or_default(),
mods: infos
.mods
.map(|v| v.to_object().unwrap())
.unwrap_or_default(),
args: Array::from_iter(infos.args.clone()).into(),
count: infos.count.into(),
magic: infos
.magic
.map(|v| v.to_object().unwrap())
.unwrap_or_default(),
nargs: infos
.nargs
.map(|v| v.to_object().unwrap())
.unwrap_or_default(),
range: infos.range.into(),
nextcmd: infos.nextcmd.clone().into(),
}
}
#[cfg(feature = "neovim-nightly")]
{
let mut mask = 0;
let cmd = if let Some(cmd) = infos.cmd.as_deref() {
mask |= 0b11;
NvimString::from(cmd)
} else {
NvimString::default()
};
let range = if let Some(range) = infos.range {
mask |= 0b10000000001;
Array::from(range)
} else {
Array::default()
};
let count = if let Some(count) = infos.count {
mask |= 0b10000001;
count as Integer
} else {
Integer::default()
};
let reg = if let Some(reg) = infos.reg {
mask |= 0b101;
reg.into()
} else {
NvimString::default()
};
let bang = if let Some(bang) = infos.bang {
mask |= 0b1001;
bang
} else {
Boolean::default()
};
let args = if !infos.args.is_empty() {
mask |= 0b1000001;
Array::from_iter(infos.args.clone())
} else {
Array::default()
};
let magic = if let Some(magic) = infos.magic {
mask |= 0b100000001;
Dictionary::from(magic)
} else {
Dictionary::default()
};
let mods = if let Some(mods) = infos.mods {
mask |= 0b100001;
Dictionary::from(mods)
} else {
Dictionary::default()
};
let nargs = if let Some(nargs) = infos.nargs {
mask |= 0b1000000001;
nargs.to_object().unwrap()
} else {
Object::default()
};
let addr = if let Some(addr) = infos.addr {
mask |= 0b10001;
addr.to_object().unwrap()
} else {
Object::default()
};
let nextcmd = if let Some(nextcmd) = infos.nextcmd.as_deref() {
mask |= 0b100000000001;
NvimString::from(nextcmd).into()
} else {
Object::default()
};
Self {
mask,
cmd,
reg,
bang,
addr,
mods,
args,
count,
magic,
nargs,
range,
nextcmd,
}
}
}
}