Add o command for opening items to tui viewer

This patch adds the o command to the tui viewer that can be used to open
items.  The command uses the same lookup logic as the rusty-man program:
First, it tries to find a direct match.  If none is found, it uses the
search index to find partial matches.
This commit is contained in:
Robin Krahl 2020-10-12 01:08:00 +02:00
parent 44b1405595
commit 6232585d36
No known key found for this signature in database
GPG Key ID: 8E9B0870524F69D8
2 changed files with 78 additions and 6 deletions

View File

@ -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.

View File

@ -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<F>(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<index::IndexItem>) {
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)