extern crate serde; extern crate clap; extern crate cursive; extern crate tokio; extern crate reqwest; use std::{fs, env}; use std::path::PathBuf; use clap::{Arg, App}; use cursive::Cursive; use cursive::menu::MenuTree; use cursive::event::Key; use serde_json; mod types; mod http; #[tokio::main] async fn main() { let args = App::new("Freechat TUI") .version("69.420") .author("godrah") .about("oh you know") .arg(Arg::with_name("config") .short("c") .long("config") .value_name("CONFIG") .help("Specify path of config to use") .takes_value(true)) .arg(Arg::with_name("theme") .short("t") .long("theme") .value_name("THEME_FILE") .help("Specify theme file on startup") .takes_value(true)).get_matches(); let config: types::Config = if args.args.len() == 0 { let home = env::var("HOME").unwrap(); match fs::read_to_string(format!("{}/.config/freechat/config.json", home)) { Ok(data) => serde_json::from_str(&data).unwrap(), Err(e) => panic!("Bro: {}", e) } } else{ let path = args.value_of("config").unwrap(); match fs::read_to_string(path) { Ok(data) => serde_json::from_str(&data).unwrap(), Err(e) => panic!("Bro: {}", e) } }; // only load a theme if requested let theme = if let Some(theme) = args.value_of("theme") { Some(PathBuf::from(theme)) } else { None }; let mut app = cursive::default(); // optionally load optional theme if let Some(theme) = theme { let _ = app.load_theme_file(theme); } app.add_global_callback('q', Cursive::quit); app.add_global_callback(Key::Esc, |s| s.select_menubar()); app.set_autohide_menu(false); // don't hide the menubar all the time // menu bar at the top lets us pick between different servers in the config for server in config.servers.iter() { let name = match &server.name { Some(name) => name.to_string(), //None => String::from(&format!("{}", server.ip)) None => String::from("None") }; app.menubar().add_subtree(&name, MenuTree::new()); // add server name // on action: // open up search able list of channels // choose from that list of channels which one you want to see // NOTE: not passing the domain as the IP is resolved on server join if let Some(channels) = http::fetch_channels(&server.ip, server.port).await { // add a bunch of actionable leafs to our sub tree for channel in channels { app.menubar().find_subtree(name.as_ref()).unwrap().add_leaf(channel.name.clone(), move |s| { let (ip, name) = channel.parts(); http::sync::open_channel(ip, name, s); }); } } } app.run(); }