use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(from = "ItemJson")]
pub struct AutocompleteItem {
pub value: String,
pub label: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
impl AutocompleteItem {
pub fn new(value: impl Into<String>) -> AutocompleteItem {
let value = value.into();
AutocompleteItem {
label: value.clone(),
value,
description: None,
}
}
}
#[derive(Deserialize)]
struct ItemJson {
value: String,
label: Option<String>,
description: Option<String>,
}
impl From<ItemJson> for AutocompleteItem {
fn from(item: ItemJson) -> AutocompleteItem {
AutocompleteItem {
label: item.label.unwrap_or_else(|| item.value.clone()),
value: item.value,
description: item.description,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ArgumentCompletions {
Ready(Option<Vec<AutocompleteItem>>),
Pending,
}
impl From<Option<Vec<AutocompleteItem>>> for ArgumentCompletions {
fn from(items: Option<Vec<AutocompleteItem>>) -> ArgumentCompletions {
ArgumentCompletions::Ready(items)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AutocompleteSuggestions {
pub items: Vec<AutocompleteItem>,
pub prefix: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EditorState {
pub lines: Vec<String>,
pub cursor_line: usize,
pub cursor_col: usize,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn an_item_without_a_label_shows_its_value() {
let item: AutocompleteItem = serde_json::from_str(r#"{"value": "a"}"#).unwrap();
assert_eq!(item.label, "a");
assert_eq!(
crate::json::to_string(&item).unwrap(),
r#"{"value":"a","label":"a"}"#
);
}
}