diff --git a/src/args.rs b/src/args.rs new file mode 100644 index 0000000..ac07e1f --- /dev/null +++ b/src/args.rs @@ -0,0 +1,82 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: MIT + +use structopt::StructOpt; + +use crate::doc; +use crate::viewer; + +/// Command-line viewer for rustdoc documentation +/// +/// rusty-man reads the HTML documentation generated by rustdoc and displays a documentation item. +/// Make sure to run `cargo doc` before using rusty-man. Per default, rusty-man looks up +/// documentation in the ./target/doc directory relative to the current working directory and in +/// the system documentation directories (share/doc/rust{,-doc}/html relative to the Rust sysroot, +/// see `rustc --print sysroot`, or /usr). Use the -s/--source option if you want to read the +/// documentation from a different directory. +/// +/// rusty-man tries to find an item that exactly matches the given keyword. If it doesn’t find an +/// exact match, it reads the search indexes of all available sources and tries to find a partial +/// match. +#[derive(Debug, StructOpt)] +pub struct Args { + /// The keyword to open the documentation for, e. g. `rand_core::RngCore` + pub keyword: doc::Name, + + /// The sources to check for documentation generated by rustdoc + /// + /// Typically, this is the path of a directory containing the documentation for one or more + /// crates in subdirectories. + #[structopt(name = "source", short, long, number_of_values = 1)] + pub source_paths: Vec, + + /// The viewer for the rustdoc documentation (one of: plain, rich) + #[structopt(long, parse(try_from_str = viewer::get_viewer))] + pub viewer: Option>, + + /// Do not search the default documentation sources + /// + /// If this option is not set, rusty-man appends `$sysroot/share/doc/rust{,-doc}/html` and + /// `target/doc` to the list of sources if they exist. `$sysroot` is the output of `rustc + /// --print sysroot` or `/usr` if that command does not output a valid path. + #[structopt(long)] + pub no_default_sources: bool, + + /// Do not read the search index if there is no exact match + /// + /// Per default, rusty-man reads the search indexes of all sources and tries to find matching + /// items if there is no exact match for the keyword. If this option is set, the search + /// indexes are not read. + #[structopt(long)] + pub no_search: bool, + + /// Show all examples for the item instead of opening the full documentation. + #[structopt(short, long)] + pub examples: bool, + + #[structopt(flatten)] + pub viewer_args: ViewerArgs, +} + +#[derive(Debug, StructOpt)] +pub struct ViewerArgs { + /// Disable syntax highlighting. + /// + /// Per default, rusty-man tries to highlight Rust code snippets in its output if the rich text + /// viewer is selected. If this option is set, it renders the HTML representation instead. + #[structopt(long)] + pub no_syntax_highlight: bool, + + /// The color theme for syntax highlighting + /// + /// rusty-man includes these color themes: base16-ocean.dark, base16-eighties.dark, + /// base16-mocha.dark, base16-ocean.light, InspiredGitHub, Solarized (dark), Solarized (light). + #[structopt(long, default_value = "base16-eighties.dark")] + pub theme: String, +} + +impl Args { + pub fn load() -> Args { + Args::from_args() + } +} diff --git a/src/main.rs b/src/main.rs index 2e53edf..dbb4fe3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,6 +35,7 @@ //! We don’t support the old index format. As the format of the HTML files is not specified, //! rusty-man might not work with new Rust versions that change the documentation format. +mod args; mod doc; mod index; mod parser; @@ -44,102 +45,31 @@ mod viewer; use std::io; use std::path; -use structopt::StructOpt; - -/// Command-line viewer for rustdoc documentation -/// -/// rusty-man reads the HTML documentation generated by rustdoc and displays a documentation item. -/// Make sure to run `cargo doc` before using rusty-man. Per default, rusty-man looks up -/// documentation in the ./target/doc directory relative to the current working directory and in -/// the system documentation directories (share/doc/rust{,-doc}/html relative to the Rust sysroot, -/// see `rustc --print sysroot`, or /usr). Use the -s/--source option if you want to read the -/// documentation from a different directory. -/// -/// rusty-man tries to find an item that exactly matches the given keyword. If it doesn’t find an -/// exact match, it reads the search indexes of all available sources and tries to find a partial -/// match. -#[derive(Debug, StructOpt)] -struct Opt { - /// The keyword to open the documentation for, e. g. `rand_core::RngCore` - keyword: doc::Name, - - /// The sources to check for documentation generated by rustdoc - /// - /// Typically, this is the path of a directory containing the documentation for one or more - /// crates in subdirectories. - #[structopt(name = "source", short, long, number_of_values = 1)] - source_paths: Vec, - - /// The viewer for the rustdoc documentation (one of: plain, rich) - #[structopt(long, parse(try_from_str = viewer::get_viewer))] - viewer: Option>, - - /// Do not search the default documentation sources - /// - /// If this option is not set, rusty-man appends `$sysroot/share/doc/rust{,-doc}/html` and - /// `target/doc` to the list of sources if they exist. `$sysroot` is the output of `rustc - /// --print sysroot` or `/usr` if that command does not output a valid path. - #[structopt(long)] - no_default_sources: bool, - - /// Do not read the search index if there is no exact match - /// - /// Per default, rusty-man reads the search indexes of all sources and tries to find matching - /// items if there is no exact match for the keyword. If this option is set, the search - /// indexes are not read. - #[structopt(long)] - no_search: bool, - - /// Show all examples for the item instead of opening the full documentation. - #[structopt(short, long)] - examples: bool, - - #[structopt(flatten)] - viewer_args: ViewerArgs, -} - -#[derive(Debug, StructOpt)] -pub struct ViewerArgs { - /// Disable syntax highlighting. - /// - /// Per default, rusty-man tries to highlight Rust code snippets in its output if the rich text - /// viewer is selected. If this option is set, it renders the HTML representation instead. - #[structopt(long)] - no_syntax_highlight: bool, - - /// The color theme for syntax highlighting - /// - /// rusty-man includes these color themes: base16-ocean.dark, base16-eighties.dark, - /// base16-mocha.dark, base16-ocean.light, InspiredGitHub, Solarized (dark), Solarized (light). - #[structopt(long, default_value = "base16-eighties.dark")] - theme: String, -} - fn main() -> anyhow::Result<()> { env_logger::init(); - let opt = Opt::from_args(); - let sources = load_sources(&opt.source_paths, !opt.no_default_sources)?; - let doc = if let Some(doc) = find_doc(&sources, &opt.keyword)? { + let args = args::Args::load(); + let sources = load_sources(&args.source_paths, !args.no_default_sources)?; + let doc = if let Some(doc) = find_doc(&sources, &args.keyword)? { Some(doc) - } else if !opt.no_search { - search_doc(&sources, &opt.keyword)? + } else if !args.no_search { + search_doc(&sources, &args.keyword)? } else { - anyhow::bail!("Could not find documentation for {}", &opt.keyword); + anyhow::bail!("Could not find documentation for {}", &args.keyword); }; if let Some(doc) = doc { - let viewer = opt.viewer.unwrap_or_else(viewer::get_default); - if opt.examples { + let viewer = args.viewer.unwrap_or_else(viewer::get_default); + if args.examples { let examples = doc.find_examples()?; anyhow::ensure!( !examples.is_empty(), "Could not find examples for {}", - &opt.keyword + &args.keyword ); - viewer.open_examples(opt.viewer_args, &doc, examples) + viewer.open_examples(args.viewer_args, &doc, examples) } else { - viewer.open(opt.viewer_args, &doc) + viewer.open(args.viewer_args, &doc) } } else { // item selection cancelled by user diff --git a/src/viewer/mod.rs b/src/viewer/mod.rs index 8787106..fdf4faa 100644 --- a/src/viewer/mod.rs +++ b/src/viewer/mod.rs @@ -7,14 +7,15 @@ use std::cmp; use std::fmt; use std::io; +use crate::args; use crate::doc; pub trait Viewer: fmt::Debug { - fn open(&self, args: crate::ViewerArgs, doc: &doc::Doc) -> anyhow::Result<()>; + fn open(&self, args: args::ViewerArgs, doc: &doc::Doc) -> anyhow::Result<()>; fn open_examples( &self, - args: crate::ViewerArgs, + args: args::ViewerArgs, doc: &doc::Doc, examples: Vec, ) -> anyhow::Result<()>; diff --git a/src/viewer/text/mod.rs b/src/viewer/text/mod.rs index 187b9b9..85ff742 100644 --- a/src/viewer/text/mod.rs +++ b/src/viewer/text/mod.rs @@ -8,11 +8,12 @@ use std::fmt; use std::io; use std::marker; +use crate::args; use crate::doc; use crate::viewer; pub trait Printer: fmt::Debug + marker::Sized { - fn new(args: crate::ViewerArgs) -> anyhow::Result; + fn new(args: args::ViewerArgs) -> anyhow::Result; fn print_title(&self, left: &str, middle: &str, right: &str) -> io::Result<()>; @@ -42,7 +43,7 @@ impl TextViewer

{ } } - fn exec(&self, args: crate::ViewerArgs, op: F) -> anyhow::Result<()> + fn exec(&self, args: args::ViewerArgs, op: F) -> anyhow::Result<()> where F: FnOnce(&TextRenderer

) -> io::Result<()>, { @@ -67,13 +68,13 @@ impl TextViewer { } impl viewer::Viewer for TextViewer

{ - fn open(&self, args: crate::ViewerArgs, doc: &doc::Doc) -> anyhow::Result<()> { + fn open(&self, args: args::ViewerArgs, doc: &doc::Doc) -> anyhow::Result<()> { self.exec(args, |r| r.print_doc(doc)) } fn open_examples( &self, - args: crate::ViewerArgs, + args: args::ViewerArgs, doc: &doc::Doc, examples: Vec, ) -> anyhow::Result<()> { diff --git a/src/viewer/text/plain.rs b/src/viewer/text/plain.rs index 79c232d..3807117 100644 --- a/src/viewer/text/plain.rs +++ b/src/viewer/text/plain.rs @@ -5,6 +5,7 @@ use std::io::{self, Write}; use html2text::render::text_renderer; +use crate::args; use crate::doc; use crate::viewer; @@ -20,7 +21,7 @@ struct Decorator { } impl super::Printer for PlainTextRenderer { - fn new(_args: crate::ViewerArgs) -> anyhow::Result { + fn new(_args: args::ViewerArgs) -> anyhow::Result { Ok(Self { line_length: viewer::get_line_length(), }) diff --git a/src/viewer/text/rich.rs b/src/viewer/text/rich.rs index a5de47f..8979d66 100644 --- a/src/viewer/text/rich.rs +++ b/src/viewer/text/rich.rs @@ -5,6 +5,7 @@ use std::io::{self, Write}; use html2text::render::text_renderer; +use crate::args; use crate::doc; use crate::viewer; @@ -54,7 +55,7 @@ impl RichTextRenderer { } impl super::Printer for RichTextRenderer { - fn new(args: crate::ViewerArgs) -> anyhow::Result { + fn new(args: args::ViewerArgs) -> anyhow::Result { use anyhow::Context; let mut theme_set = syntect::highlighting::ThemeSet::load_defaults();