use crate::api::OverlayColorSpec;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use ts_rs::TS;
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[serde(deny_unknown_fields)]
#[ts(export)]
pub struct FileExplorerDecoration {
#[ts(type = "string")]
pub path: PathBuf,
pub symbol: String,
pub color: OverlayColorSpec,
#[serde(default)]
pub priority: i32,
}
fn default_leading_slot_min_width() -> usize {
2
}
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[ts(export)]
pub struct FileExplorerTooltip {
pub title: String,
pub lines: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[ts(export)]
pub struct FileExplorerLeadingSlot {
pub text: String,
pub color: OverlayColorSpec,
#[serde(default = "default_leading_slot_min_width")]
pub min_width: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[ts(export)]
pub struct FileExplorerTrailingSlot {
pub text: String,
pub color: OverlayColorSpec,
#[serde(default)]
pub tooltip: Option<FileExplorerTooltip>,
}
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[ts(export)]
pub struct FileExplorerSlotEntry {
#[ts(type = "string")]
pub path: PathBuf,
#[serde(default)]
pub leading: Option<FileExplorerLeadingSlot>,
#[serde(default)]
pub suppress_leading: bool,
#[serde(default)]
pub trailing: Option<FileExplorerTrailingSlot>,
#[serde(default)]
pub suppress_trailing: bool,
#[serde(default)]
pub name_color: Option<OverlayColorSpec>,
#[serde(default)]
pub suppress_name_color: bool,
#[serde(default)]
pub priority: i32,
}
#[cfg(feature = "plugins")]
impl<'js> rquickjs::FromJs<'js> for FileExplorerDecoration {
fn from_js(_ctx: &rquickjs::Ctx<'js>, value: rquickjs::Value<'js>) -> rquickjs::Result<Self> {
rquickjs_serde::from_value(value).map_err(|e| rquickjs::Error::FromJs {
from: "object",
to: "FileExplorerDecoration",
message: Some(e.to_string()),
})
}
}
#[cfg(feature = "plugins")]
impl<'js> rquickjs::FromJs<'js> for FileExplorerSlotEntry {
fn from_js(_ctx: &rquickjs::Ctx<'js>, value: rquickjs::Value<'js>) -> rquickjs::Result<Self> {
rquickjs_serde::from_value(value).map_err(|e| rquickjs::Error::FromJs {
from: "object",
to: "FileExplorerSlotEntry",
message: Some(e.to_string()),
})
}
}
#[cfg(all(test, feature = "plugins"))]
mod tests {
use super::*;
use rquickjs::{Context, FromJs, Runtime, Value};
#[test]
fn from_js_decodes_all_visible_fields() {
let rt = Runtime::new().unwrap();
let ctx = Context::full(&rt).unwrap();
ctx.with(|ctx| {
let v: Value = ctx
.eval::<Value, _>(
b"({path: '/tmp/a.rs', symbol: 'M', \
color: 'ui.file_status_added_fg', priority: 7})"
.as_slice(),
)
.unwrap();
let got = FileExplorerDecoration::from_js(&ctx, v).unwrap();
assert_eq!(got.path, PathBuf::from("/tmp/a.rs"));
assert_eq!(got.symbol, "M");
assert_eq!(got.priority, 7);
assert_eq!(got.color.as_theme_key(), Some("ui.file_status_added_fg"));
});
}
#[test]
fn slot_entry_from_js_decodes_suppression_flags() {
let rt = Runtime::new().unwrap();
let ctx = Context::full(&rt).unwrap();
ctx.with(|ctx| {
let v: Value = ctx
.eval::<Value, _>(
br#"({
path: '/tmp/a.rs',
suppressLeading: true,
suppressTrailing: true,
suppressNameColor: true,
priority: 5
})"#,
)
.unwrap();
let got = FileExplorerSlotEntry::from_js(&ctx, v).unwrap();
assert_eq!(got.path, PathBuf::from("/tmp/a.rs"));
assert!(got.suppress_leading);
assert!(got.suppress_trailing);
assert!(got.suppress_name_color);
assert_eq!(got.priority, 5);
});
}
}