Add links to module items
This patch adds links to the items in the module member list. This only applies for the tui viewer, as the links wouldn’t provide any additional information for the plain and rich viewers.
This commit is contained in:
parent
8e8f7728e2
commit
4c5d5808aa
@ -56,7 +56,12 @@ impl utils::ManRenderer for PlainTextRenderer {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_heading(&mut self, indent: u8, s: &str) -> io::Result<()> {
|
||||
fn print_heading(
|
||||
&mut self,
|
||||
indent: u8,
|
||||
s: &str,
|
||||
_link: Option<utils::DocLink>,
|
||||
) -> io::Result<()> {
|
||||
writeln!(io::stdout(), "{}{}", " ".repeat(indent.into()), s)
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,12 @@ impl utils::ManRenderer for RichTextRenderer {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_heading(&mut self, indent: u8, s: &str) -> io::Result<()> {
|
||||
fn print_heading(
|
||||
&mut self,
|
||||
indent: u8,
|
||||
s: &str,
|
||||
_link: Option<utils::DocLink>,
|
||||
) -> io::Result<()> {
|
||||
write!(io::stdout(), "{}", " ".repeat(usize::from(indent)))?;
|
||||
render(text_style::StyledStr::plain(s).bold())?;
|
||||
writeln!(io::stdout())
|
||||
|
@ -8,14 +8,14 @@ use std::convert;
|
||||
use anyhow::Context as _;
|
||||
use cursive::view::{Resizable as _, Scrollable as _};
|
||||
use cursive::views::{Dialog, LinearLayout, PaddedView, Panel, TextView};
|
||||
use cursive::{event, theme};
|
||||
use cursive::{event, theme, utils::markup};
|
||||
|
||||
use crate::args;
|
||||
use crate::doc;
|
||||
use crate::source;
|
||||
use crate::viewer::{self, utils, utils::ManRenderer as _};
|
||||
|
||||
use views::{CodeView, HtmlView};
|
||||
use views::{CodeView, HtmlView, LinkView};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TuiViewer {}
|
||||
@ -133,9 +133,25 @@ impl<'s> utils::ManRenderer for TuiManRenderer<'s> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_heading(&mut self, indent: u8, text: &str) -> Result<(), Self::Error> {
|
||||
let heading = TextView::new(text).effect(theme::Effect::Bold);
|
||||
self.layout.add_child(indent_view(indent, heading));
|
||||
fn print_heading(
|
||||
&mut self,
|
||||
indent: u8,
|
||||
text: &str,
|
||||
link: Option<utils::DocLink>,
|
||||
) -> 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);
|
||||
}
|
||||
});
|
||||
self.layout.add_child(indent_view(indent, heading));
|
||||
} else {
|
||||
let heading = TextView::new(text);
|
||||
self.layout.add_child(indent_view(indent, heading));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -266,6 +282,12 @@ enum ResolvedLink {
|
||||
External(String),
|
||||
}
|
||||
|
||||
impl From<utils::DocLink> for ResolvedLink {
|
||||
fn from(link: utils::DocLink) -> ResolvedLink {
|
||||
ResolvedLink::Doc(link.ty, link.name)
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_link(
|
||||
doc_name: &doc::Fqn,
|
||||
doc_ty: doc::ItemType,
|
||||
|
@ -346,6 +346,54 @@ fn get_rich_style(annotation: &text_renderer::RichAnnotation) -> Option<theme::S
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LinkView {
|
||||
text: markup::StyledString,
|
||||
cb: event::Callback,
|
||||
is_focused: bool,
|
||||
}
|
||||
|
||||
impl LinkView {
|
||||
pub fn new<F>(text: impl Into<markup::StyledString>, cb: F) -> LinkView
|
||||
where
|
||||
F: Fn(&mut cursive::Cursive) + 'static,
|
||||
{
|
||||
LinkView {
|
||||
text: text.into(),
|
||||
cb: event::Callback::from_fn(cb),
|
||||
is_focused: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl cursive::View for LinkView {
|
||||
fn draw(&self, printer: &cursive::Printer) {
|
||||
let mut style = theme::Style::from(theme::Effect::Underline);
|
||||
if self.is_focused && printer.focused {
|
||||
style = style.combine(theme::PaletteColor::Highlight);
|
||||
};
|
||||
printer.with_style(style, |printer| {
|
||||
printer.print_styled((0, 0), (&self.text).into())
|
||||
});
|
||||
}
|
||||
|
||||
fn required_size(&mut self, _constraint: cursive::XY<usize>) -> cursive::XY<usize> {
|
||||
(self.text.width(), 1).into()
|
||||
}
|
||||
|
||||
fn take_focus(&mut self, _direction: cursive::direction::Direction) -> bool {
|
||||
self.is_focused = true;
|
||||
true
|
||||
}
|
||||
|
||||
fn on_event(&mut self, event: event::Event) -> event::EventResult {
|
||||
if event == event::Event::Key(event::Key::Enter) {
|
||||
event::EventResult::Consumed(Some(self.cb.clone()))
|
||||
} else {
|
||||
event::EventResult::Ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CodeView {
|
||||
lines: Vec<markup::StyledString>,
|
||||
width: usize,
|
||||
|
@ -183,12 +183,23 @@ fn is_pre(ts: &RichString) -> bool {
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct DocLink {
|
||||
pub name: doc::Fqn,
|
||||
pub ty: Option<doc::ItemType>,
|
||||
}
|
||||
|
||||
/// A trait for viewer implementations that display the documentation in a man-like style.
|
||||
pub trait ManRenderer {
|
||||
type Error: std::error::Error + Sized + Send;
|
||||
|
||||
fn print_title(&mut self, left: &str, center: &str, right: &str) -> Result<(), Self::Error>;
|
||||
fn print_heading(&mut self, indent: u8, text: &str) -> Result<(), Self::Error>;
|
||||
fn print_heading(
|
||||
&mut self,
|
||||
indent: u8,
|
||||
text: &str,
|
||||
link: Option<DocLink>,
|
||||
) -> Result<(), Self::Error>;
|
||||
fn print_code(&mut self, indent: u8, code: &doc::Code) -> Result<(), Self::Error>;
|
||||
fn print_text(&mut self, indent: u8, text: &doc::Text) -> Result<(), Self::Error>;
|
||||
fn println(&mut self) -> Result<(), Self::Error>;
|
||||
@ -197,28 +208,36 @@ pub trait ManRenderer {
|
||||
print_title(self, doc)?;
|
||||
|
||||
if let Some(text) = &doc.definition {
|
||||
print_heading(self, 1, "Synopsis")?;
|
||||
print_heading(self, 1, "Synopsis", None)?;
|
||||
self.print_code(6, text)?;
|
||||
self.println()?;
|
||||
}
|
||||
|
||||
if let Some(text) = &doc.description {
|
||||
print_heading(self, 1, "Description")?;
|
||||
print_heading(self, 1, "Description", None)?;
|
||||
self.print_text(6, text)?;
|
||||
self.println()?;
|
||||
}
|
||||
|
||||
for (ty, groups) in &doc.groups {
|
||||
print_heading(self, 1, ty.group_name())?;
|
||||
print_heading(self, 1, ty.group_name(), None)?;
|
||||
|
||||
for group in groups {
|
||||
if let Some(title) = &group.title {
|
||||
print_heading(self, 2, title)?;
|
||||
print_heading(self, 2, title, None)?;
|
||||
}
|
||||
|
||||
for member in &group.members {
|
||||
let link = if doc::ItemType::Module == doc.ty {
|
||||
Some(DocLink {
|
||||
name: member.name.clone(),
|
||||
ty: Some(*ty),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// TODO: use something link strip_prefix instead of last()
|
||||
print_heading(self, 3, member.name.last())?;
|
||||
print_heading(self, 3, member.name.last(), link)?;
|
||||
if let Some(definition) = &member.definition {
|
||||
self.print_code(12, definition)?;
|
||||
}
|
||||
@ -244,12 +263,12 @@ pub trait ManRenderer {
|
||||
examples: &[doc::Example],
|
||||
) -> Result<(), Self::Error> {
|
||||
print_title(self, doc)?;
|
||||
print_heading(self, 1, "Examples")?;
|
||||
print_heading(self, 1, "Examples", None)?;
|
||||
|
||||
let n = examples.len();
|
||||
for (i, example) in examples.iter().enumerate() {
|
||||
if n > 1 {
|
||||
print_heading(self, 2, &format!("Example {} of {}", i + 1, n))?;
|
||||
print_heading(self, 2, &format!("Example {} of {}", i + 1, n), None)?;
|
||||
}
|
||||
if let Some(description) = &example.description {
|
||||
self.print_text(6, description)?;
|
||||
@ -272,6 +291,7 @@ fn print_heading<M: ManRenderer + ?Sized>(
|
||||
viewer: &mut M,
|
||||
level: u8,
|
||||
text: &str,
|
||||
link: Option<DocLink>,
|
||||
) -> Result<(), M::Error> {
|
||||
let text = match level {
|
||||
1 => std::borrow::Cow::from(text.to_uppercase()),
|
||||
@ -282,7 +302,7 @@ fn print_heading<M: ManRenderer + ?Sized>(
|
||||
2 => 3,
|
||||
_ => 6,
|
||||
};
|
||||
viewer.print_heading(indent, text.as_ref())
|
||||
viewer.print_heading(indent, text.as_ref(), link)
|
||||
}
|
||||
|
||||
/// Link handling mode for the [`RichDecorator`].
|
||||
|
Loading…
Reference in New Issue
Block a user