1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ts_rs::TS)]
5#[ts(export)]
6pub enum CommandSource {
7 Builtin,
9 Plugin(String),
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS)]
16#[ts(export)]
17pub struct Command {
18 pub name: String,
20 pub description: String,
22 pub action_name: String,
24 pub plugin_name: String,
26 pub custom_contexts: Vec<String>,
28 #[serde(default)]
37 pub terminal_bypass: bool,
38}
39
40#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ts_rs::TS)]
42#[serde(deny_unknown_fields)]
43#[ts(export, rename = "PromptSuggestion")]
44pub struct Suggestion {
45 pub text: String,
47 #[serde(default)]
49 #[ts(optional)]
50 pub description: Option<String>,
51 #[serde(default)]
53 #[ts(optional)]
54 pub value: Option<String>,
55 #[serde(default)]
57 #[ts(optional)]
58 pub disabled: Option<bool>,
59 #[serde(default)]
64 #[ts(optional)]
65 pub description_spans: Option<Vec<crate::api::StyledText>>,
66 #[serde(default)]
68 #[ts(optional)]
69 pub keybinding: Option<String>,
70 #[serde(skip)]
72 #[ts(skip)]
73 pub source: Option<CommandSource>,
74}
75
76#[cfg(feature = "plugins")]
77impl<'js> rquickjs::FromJs<'js> for Suggestion {
78 fn from_js(_ctx: &rquickjs::Ctx<'js>, value: rquickjs::Value<'js>) -> rquickjs::Result<Self> {
79 rquickjs_serde::from_value(value).map_err(|e| rquickjs::Error::FromJs {
80 from: "object",
81 to: "Suggestion",
82 message: Some(e.to_string()),
83 })
84 }
85}
86
87impl Suggestion {
88 pub fn new(text: String) -> Self {
89 Self {
90 text,
91 description: None,
92 value: None,
93 disabled: None,
94 description_spans: None,
95 keybinding: None,
96 source: None,
97 }
98 }
99
100 pub fn is_disabled(&self) -> bool {
102 self.disabled.unwrap_or(false)
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
112 fn is_disabled_reflects_disabled_field() {
113 let mut s = Suggestion::new("foo".into());
114 assert!(!s.is_disabled(), "None defaults to enabled");
115
116 s.disabled = Some(false);
117 assert!(!s.is_disabled());
118
119 s.disabled = Some(true);
120 assert!(s.is_disabled());
121 }
122
123 #[cfg(feature = "plugins")]
127 #[test]
128 fn suggestion_from_js_decodes_distinguishing_fields() {
129 use rquickjs::{Context, FromJs, Runtime, Value};
130 let rt = Runtime::new().unwrap();
131 let ctx = Context::full(&rt).unwrap();
132 ctx.with(|ctx| {
133 let v: Value = ctx
134 .eval::<Value, _>(b"({text: 'hello', description: 'world'})".as_slice())
135 .unwrap();
136 let got = Suggestion::from_js(&ctx, v).unwrap();
137 assert_eq!(got.text, "hello");
138 assert_eq!(got.description.as_deref(), Some("world"));
139 });
140 }
141}