{"id":2,"title":"Rust Cli File","content":"use clap::{Parser, Args};\n\nuse crate::network::Server;\nuse crate::tui::App;\nuse crate::queries::{SearchMenu, SearchResults};\nuse crate::posts::Post;\n// TODO: we need to import Url with Server all the time... shouldn't there be an additional string method?\n// Well, we eventually won't be creating servers willy-nilly on-demand.\nuse url::Url;\n\n// https://docs.rs/clap/latest/clap/_derive/\n\n#[derive(Parser)]\npub enum Cli {\n    #[command(name = \"--search\")]\n    Query(Query),\n    #[command(name = \"--stats\")]\n    Stats,\n    #[command(name = \"--pub\")]\n    // TODO: can this path be parsed as an actual Path type?\n    Pub {title: String, path: String},\n}\n\nimpl Cli {\n    pub fn from_args() -> Self {\n        if let Some(command) = std::env::args().nth(1) {\n            // Why does pythonexamples.org have rust tutorials?!\n            // https://pythonexamples.org/rust/how-to-get-first-n-characters-in-string\n            // https://www.dotnetperls.com/starts-with-rust\n            if !command.starts_with(\"-\") {\n                // search shortcut! Stick a --search in there and parse it!\n                let mut search_insert = std::env::args().into_iter().collect::<Vec<String>>();\n                search_insert.insert(1, \"--search\".to_string());\n                return Self::parse_from(search_insert);\n            }\n        }\n\n        return Self::parse()\n    }\n\n    pub fn process(self) {\n        match self {\n            Cli::Query(query) => Self::process_query(query.words),\n            Cli::Stats => Self::process_stats(),\n            Cli::Pub {title, path} => Self::process_pub(title, path)\n        }\n    }\n\n    fn process_query(words: Vec<String>) {\n        let server = Server::new(Url::parse(\"https://theterseverse.alwaysdata.net\").unwrap());\n        let results = server.search(words);\n\n        match results {\n            Ok(r) => {App::default().run(&mut SearchMenu::new(SearchResults::new(&server, r))).unwrap()}\n            Err(e) => {println!(\"Error: {e}\")}\n        }\n    }\n\n    fn process_stats() {\n        let server = Server::new(Url::parse(\"https://theterseverse.alwaysdata.net\").unwrap());\n        let results = server.get_stats();\n\n        match results {\n            Ok(stats) => {println!(\"{stats}\")}\n            Err(e) => {println!(\"Error in getting stats: {e}\")}\n        }\n    }\n\n    fn process_pub(title: String, path: String) {\n\n        let content = std::fs::read_to_string(&path);\n        \n        match content {\n            Err(_) => {println!(\"Path not readable\"); return}\n            _ => {}\n        }\n\n        // TODO: Is there a better way to manage content with the above match\n        // to avoid unwrapping?\n        let post = Post {title, content: content.unwrap()};\n\n        let server = Server::new(Url::parse(\"https://theterseverse.alwaysdata.net\").unwrap());\n        // TODO: if Post gets a user field, we'll need to create the post in-server;\n        // might not know what account you're in!\n        let results = server.publish(post);\n\n        match results {\n            Ok(_) => println!(\"Post published successfully!\"),\n            Err(e) => println!(\"Error in publishing post: {e}\")\n        }\n    }\n}\n\n#[derive(Args)]\npub struct Query {\n    pub words: Vec<String>,\n}\n// #[derive(Parser, Debug)]\n// pub struct QueryCli {\n//     #[clap(num_args = 1.., value_delimiter = ' ')]\n//     pub query: Vec<String>,\n// }\n\n// https://github.com/clap-rs/clap/discussions/5725\n\n// https://stackoverflow.com/questions/76315540/how-do-i-require-one-of-the-two-clap-options"}