use cursive::{ event::Key, menu::MenuTree, traits::*, views::{Dialog, EditView, Panel, ResizedView, TextView}, Cursive, }; fn main() { cursive::logger::init(); let mut siv = cursive::default(); siv.add_global_callback('q', cursive::Cursive::quit); siv.add_global_callback('~', cursive::Cursive::toggle_debug_console); siv.add_global_callback('o', open_prompt); siv.add_global_callback('?', help); siv.menubar() .add_subtree( "majc", MenuTree::new() .leaf("About", move |s| { s.add_layer(Dialog::info(format!( "{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION") ))); }) .leaf("Help", move |s| { help(s); }), ) .add_leaf("Open", |s| open_prompt(s)); siv.add_global_callback(Key::Esc, |s| s.select_menubar()); help(&mut siv); siv.run(); } fn help(siv: &mut Cursive) { let content = include_str!("./help.gmi"); siv.add_layer( Dialog::around(Panel::new(TextView::new(content).scrollable())) .title("Help") .dismiss_button("Ok"), ); } fn open_prompt(siv: &mut Cursive) { siv.add_layer( Dialog::around( EditView::new() .on_submit(open) .with_name("url") .fixed_width(50), ) .title("Enter a Gemini URL") .button("Ok", |s| { let url = s .call_on_name("url", |view: &mut EditView| view.get_content()) .unwrap(); open(s, &url); }) .button("Cancel", |s| { s.pop_layer(); }), ); } fn open(siv: &mut Cursive, url: &str) { use maj::{get, StatusCode}; use std::str; siv.pop_layer(); log::debug!("got URL: {}", url); match get(url.to_string()) { Ok(resp) => { if resp.status != StatusCode::Success { siv.add_layer(Dialog::info(format!("{:?}: {}", resp.status, resp.meta))); return; } siv.add_fullscreen_layer(ResizedView::with_full_screen( Dialog::around(Panel::new( TextView::new(str::from_utf8(&resp.body).unwrap()).scrollable(), )) .title(format!("{}: {}", url, resp.meta)), )); } Err(why) => { log::error!("got response error: {:?}", why); siv.add_layer(Dialog::info(format!("Error fetching response: {:?}", why))); } } }