diff --git a/CHANGELOG.md b/CHANGELOG.md index 42fda5b..ac3d7d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ SPDX-License-Identifier: MIT # Changelog for rusty-man +## Unreleased + +- Add `o` command for opening a documentation item to the tui viewer. + ## v0.4.1 (2020-10-11) This patch release fixes an issue with the pager configuration. diff --git a/src/viewer/tui/mod.rs b/src/viewer/tui/mod.rs index abc2a5c..c6920eb 100644 --- a/src/viewer/tui/mod.rs +++ b/src/viewer/tui/mod.rs @@ -7,12 +7,13 @@ use std::convert; use anyhow::Context as _; use cursive::view::{Resizable as _, Scrollable as _}; -use cursive::views::{Dialog, LinearLayout, PaddedView, Panel, TextView}; +use cursive::views::{Dialog, EditView, LinearLayout, PaddedView, Panel, SelectView, TextView}; use cursive::{event, theme, utils::markup}; use cursive_markup::MarkupView; use crate::args; use crate::doc; +use crate::index; use crate::source; use crate::viewer::{self, utils, utils::ManRenderer as _}; @@ -139,7 +140,6 @@ impl<'s> utils::ManRenderer for TuiManRenderer<'s> { ) -> Result<(), Self::Error> { let text = markup::StyledString::styled(text, theme::Effect::Bold); if let Some(link) = link { - // TODO: bold let heading = LinkView::new(text, move |s| { if let Err(err) = open_link(s, link.clone().into()) { report_error(s, err); @@ -221,6 +221,7 @@ fn create_cursive( screen.pop_layer(); } }); + cursive.add_global_callback('o', open_doc_dialog); let mut theme = theme::Theme::default(); theme.shadow = false; @@ -254,6 +255,76 @@ fn report_error(s: &mut cursive::Cursive, error: anyhow::Error) { s.add_layer(dialog); } +fn with_report_error(s: &mut cursive::Cursive, f: F) +where + F: Fn(&mut cursive::Cursive) -> anyhow::Result<()>, +{ + if let Err(err) = f(s) { + report_error(s, err); + } +} + +fn open_doc_dialog(s: &mut cursive::Cursive) { + let mut edit_view = EditView::new(); + edit_view.set_on_submit(|s, val| { + with_report_error(s, |s| { + s.pop_layer(); + let sources = &context(s).sources; + let name = doc::Name::from(val.to_owned()); + let mut doc = sources.find(&name, None)?; + if doc.is_none() { + let items = sources.search(&name)?; + if items.len() > 1 { + select_doc_dialog(s, items); + return Ok(()); + } else if !items.is_empty() { + doc = sources.find(&items[0].name, Some(items[0].ty))?; + } + } + if let Some(doc) = doc { + open_doc(s, &doc); + Ok(()) + } else { + Err(anyhow::anyhow!("Could not find documentation for {}", name)) + } + }); + }); + let dialog = Dialog::around(edit_view.min_width(40)).title("Open documentation"); + s.add_layer(dialog); +} + +fn select_doc_dialog(s: &mut cursive::Cursive, items: Vec) { + let mut select_view = SelectView::new(); + select_view.add_all( + items + .into_iter() + .map(|item| (item.name.as_ref().to_owned(), item)), + ); + select_view.set_on_submit(|s, item| { + with_report_error(s, |s| { + let doc = context(s).sources.find(&item.name, Some(item.ty))?; + if let Some(doc) = doc { + open_doc(s, &doc); + Ok(()) + } else { + Err(anyhow::anyhow!( + "Could not find documentation for {}", + item.name + )) + } + }); + }); + let dialog = Dialog::around(select_view.scrollable()).title("Select documentation item"); + s.add_layer(dialog); +} + +fn open_doc(s: &mut cursive::Cursive, doc: &doc::Doc) { + let mut renderer = context(s).create_renderer(&doc); + renderer.render_doc(&doc).unwrap(); + let view = renderer.into_view(); + s.add_fullscreen_layer(view); +} + fn handle_link(s: &mut cursive::Cursive, doc_name: &doc::Fqn, doc_ty: doc::ItemType, link: &str) { let result = resolve_link(doc_name, doc_ty, link).and_then(|link| open_link(s, link)); if let Err(err) = result { @@ -268,10 +339,7 @@ fn open_link(s: &mut cursive::Cursive, link: ResolvedLink) -> anyhow::Result<()> .sources .find(&name, ty)? .with_context(|| format!("Could not find documentation for item: {}", name))?; - let mut renderer = context(s).create_renderer(&doc); - renderer.render_doc(&doc).unwrap(); - let view = renderer.into_view(); - s.add_fullscreen_layer(view); + open_doc(s, &doc); Ok(()) } ResolvedLink::External(link) => webbrowser::open(&link)