pub mod error;
use crate::{macros::topics, userscript_api::ApiObject};
use error::Error;
use mlua::{ExternalError, UserData};
use std::collections::HashMap;
use topics::{about, scanmgr};
topics! {
use HelpTopic about for "Build, version, and license information.";
use HelpTopic queue for "Queue up files and other data for scanning.";
use HelpTopic scanmgr for "Start a scan of all queued data items.";
use HelpTopic user_engines for "Register custom scan engines from userscripts.";
}
pub trait HelpTopic
where
Self: Send + Sync + 'static,
{
fn name(&self) -> &'static str;
fn short_description(&self) -> &'static str;
fn content(&self) -> &'static str;
}
pub struct HelpSystem {
topics: HashMap<String, Box<dyn HelpTopic>>,
}
impl HelpSystem {
#[must_use]
pub fn new() -> Self {
Self {
topics: HashMap::with_capacity(50),
}
}
pub fn topic(&mut self, topic: Box<dyn HelpTopic>) -> &mut Self {
self.topics.insert(topic.name().to_owned(), topic);
self
}
}
impl Default for HelpSystem {
fn default() -> Self {
use topics::{queue, user_engines};
let mut help_system: HelpSystem = Self::new();
help_system
.topic(Box::new(about::Topic))
.topic(Box::new(queue::Topic))
.topic(Box::new(scanmgr::Topic))
.topic(Box::new(user_engines::Topic));
help_system
}
}
impl UserData for HelpSystem {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_meta_method("__call", |_, this: &HelpSystem, topic: Option<String>| {
if let Some(topic) = topic {
if let Some(topic) = this.topics.get(topic.trim()) {
let content: &str = topic.content();
println!("{content}");
if !content.ends_with('\n') {
println!();
}
Ok(())
} else {
Err(Error::topic_not_found(&topic).into_lua_err())
}
} else {
println!(include_str!("help_system/topics/__generic.txt"));
Ok(())
}
});
methods.add_method("topics", |_, this: &HelpSystem, ()| {
println!("The following help topics are available:\n");
for (name, topic) in &this.topics {
let name: &str = name.trim();
let description: &str = topic.short_description().trim();
println!("{name:<16} - {description:<50}");
}
println!("\nTo get help on a particular topic, use help 'topic'\n");
Ok(())
});
}
}
impl ApiObject for HelpSystem {
fn name(&self) -> &'static str {
"help"
}
}