Code Monkey home page Code Monkey logo

man's People

Contributors

badboy avatar codesections avatar dylan-dpc avatar killercup avatar kixunil avatar spacekookie avatar yoshuawuyts avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

man's Issues

API design

The current API is more of a sketch of what this could look like. On chat there seems to be a sentiment that the current API might not suffice for more complex man pages.

I'm opening this issue to gather examples of complex man pages, and to help shape the design of the crate. This should hopefully allow us to get a deeper understanding of which API we can, and should expose.

The README example does not compile

The usage example in the README does not currently compile. Even if the issues that prevent compilation are fixed, it does not result in any output.

Expected

Running the usage example should result in the output described in the README

Current

Running the usage example results in compiler errors or no output.

Possible Solution

I plan to submit a PR with a fix to this issue.

Design: how should we display subcommands?

I'm not sure how we should be handling subcommands. Should we create separate man pages? Should we create a single man page? It'd be super useful to gather prior art so we can figure out some of the options we have!

Ideally we could find a default that works for most people, and start by implementing that.

Let's start by looking at how git(1) does it.

Example: Git

Git create separate man pages for its subcommands. The git man page has GIT COMMANDS and HIGH LEVEL COMMANDS sections listing these commands.

Each subcommand has its own page, like you'd expect from any other man page.

Screenshots

git(1) commands section

2018-07-19-202102_1920x1080

git-add(1) man page

2018-07-19-202457_1920x1080

update to roff 0.2?

🐛 bug report

The man crate depends on roff 0.1, but roff has been at 0.2 since the end of last year, which is an API break.

It would be useful to bring man up to date with the latest version of roff, so that other build processes that depend on modern roff could use the same roff crate as man uses.

Have method for file path

Applies to #10. Per https://github.com/killercup/clap-man-demo/blob/master/build.rs#L17-L19, we should have a method to generate a file name.

API

Current

for man in gen_manuals(&app) {
    let name = "clap-man-demo.1"; // FIXME: Extract this from man!
    let path = PathBuf::from(&outdir).join(name);
    let mut out = fs::File::create(&path).unwrap();
    out.write_all(man.render().as_bytes()).unwrap();
}

Proposed

for man in gen_manuals(&app) {
    let path = PathBuf::from(env!("CARGO_PKG_NAME")).push(man.path());
    fs::write(path, man.render())?;
}

Document full use-case (e.g., `build.rs` script)

In discussing #31, @yoshuawuyts mentioned that we might be calling man differently. That made me realize that we don't have any documentation about the typical way to call man (e.g., at run time, in a build.rs script, or using an external tool. I propose adding something to the README that outlines calling man from a build.rs file, saving the generated file to the OUT_DIR and then (separately) installing the generated man page with make. I'm suggesting something like this be added to the README:

Example

First, generate a man page and save it to disk as part of your compilation using a build.rs file.

// build.rs
use man::prelude::*;
use std::env;
use std::fs::File;
use std::io::prelude::*;

include!("src/cli.rs");

fn main() {
    let mut out_dir = env::var("OUT_DIR").unwrap();
    let page = Manual::new("basic")
        .about("A basic example")
        .author(Author::new("Alice Person").email("[email protected]"))
        .author(Author::new("Bob Human").email("[email protected]"))
        .flag(
            Flag::new()
                .short("-d")
                .long("--debug")
                .help("Enable debug mode"),
        )
        .flag(
            Flag::new()
                .short("-v")
                .long("--verbose")
                .help("Enable verbose mode"),
        )
        .option(
            Opt::new("output")
                .short("-o")
                .long("--output")
                .help("The file path to write output to"),
        )
        .example(
            Example::new()
                .text("run basic in debug mode")
                .command("basic -d")
                .output("Debug Mode: basic will print errors to the console")
            )
        .custom(
            Section::new("usage note")
                .paragraph("This program will overwrite any file currently stored at the output path")
        )
        .render();
    out_dir.push_str("/MY_APP.1");
    let mut file = File::create(out_dir).expect("Should be able to open file in project directory");
    file.write_all(page.as_bytes()).expect("Should be able to write to file in project directory");
}

And then add a makefile to install the generated man page

# makefile
OUT_DIR := $(shell find -type d -name out | grep MY_APP)

.PHONY : install
install : 
	cp $(OUT_DIR)/MY_APP.1 /usr/local/share/man/man1/MY_APP.1
	# any other install commands for MY_APP (the bin, shell completions, etc.)

.PHONY : uninstall
uninstall :
	rm -f /usr/local/share/man/man1/MY_APP.1
	# any other uninstall commands for MY_APP

end example

Two questions on this:

  1. Is build.rs + makefile the procedure we want to recommend?
  2. If so, should an example like this go under the current example in the README (which prints to stdout) or replace that example?

Add DESCRIPTION section

🙋 feature request

Hi, I just started experimenting with this crate in my configure_me crate and I must say it's pretty neat.

However, I'm missing DESCRIPTION section. I tried to put my documentation into about, but it was long and the result was very ugly.

Add version/date API

I am including version and date in the same issue because I've checked several man(1) pages and noticed that the formatting of the two is related: specifically, the version will be displayed in the bottom center of the page if the man page doesn't have a date. If the man page has a date, the date is displayed in the bottom center of the page and the version is moved to the left.

I also note that we can use the env!("CARGO_PACKAGE_VERSION") macro to read the version from the Cargo.toml file and that version is a required field. Based on the above, I propose the following API:

Default (nothing specified; assume the Cargo.toml version is 0.2.0)

Manual::new("basic");

prints at the bottom:

                                       0.2.0                                    BASIC(1)

Date

Manual::new("basic")
  .date("August 2017");
0.2.0                                August 2017                              BASIC(1)

Date & Custom version

Manual::new("basic")
  .date("January 1, 2019")
  .version("0.1.0");
0.1.0                                January 1, 2017                          BASIC(1)

Custom date & no version

Manual::new("basic")
  .date("2015-05-23")
  .version("");
                                       2015-05-23                             BASIC(1)

Note: the API I suggest takes a str for the date and leaves the exact formatting to the user. It could, of course, take a date string or something (perhaps using Chrono) and format the date for the user. But, based on looking at a few man pages, there doesn't seem to be consensus on how to format dates and it seems better to leave that to the users.

Any thoughts on this API before I work on a PR?

Which sections should a man page have?

I'm thinking almost all sections should be optional, but we want to somewhat restrict which sections are possible. Which sections should we have?

From what I've seen, we should probably support the following sections:

Required

This should probably be part of the ::new() constructor?

  • Name: name of the project (to be displayed at the top)
  • Version: version (to be displayed at the bottom)

Optional

  • Synopsis: quite similar to the short output of -h in CLIs
  • Description: what does this CLI do?
  • Authors: who wrote this?
  • Flags: which CLI flags can be passed?
  • Options: which CLI flags that require arguments can be passed
  • See Also: related projects
  • Files: which files does this project use (e.g. ~/.ifconfig)
  • Exit Codes: what are the possible exit codes?
  • Environment Variables: which env vars are checked?

Improve `exit status` section

As noted in the comments, the exit_status section is currently hard-coded, but should be revised to accept arguments. Specifically, the exit status section will currently always be:

EXIT STATUS
        0      Successful program execution.

        1      Unsuccessful program execution.

        101    The program panicked.

Looking at a variety of man pages, I've noticed that not all of them have an "exit status" section (including some that I trust to be good, including git, bash, zsh, and rg. Thus, I think that we should make the exit status section optional.

Of course, as noted in the comment, we should make it possible to pass app-specific exit codes. However, it seems like the current implementation (0, 1, and 101) will be a very common default, so it would be nice if we keep that as fairly easy behavior.

Given all of the above, I propose the following API

.exit_status(ExitStatus::default())

produces current behavior

.exit_status(ExitStatus::default_plus([(1, "invalid input"), (3, "could not read file")])

Produces an exit status section with 0 and 101 as defaults plus whatever custom codes and messages the user supplies in an vec of tuples.

.exit_status(ExitStatus::custom([(0, "success")]))

Produces a fully custom exit status section with only the user-supplied codes/messages.

I'm happy to implement this API; please let me know if you think we should go in a different direction.

Support for custom sections?

As discussed in #1, a man page traditionally has several different sections beyond the few that man currently supports. I agree that, long-term, it would be best for man to support a larger number of those sections. Supporting a list section directly would allow man to provide a higher abstraction over that section and would guide crate authors towards including relevant/helpful/traditional sections.

However, I believe man should also support custom sections. In the short term, this would allow users to include any of the sections listed in #1, even if they need to operate at a bit lower level of abstraction/don't have access to the same degree of prewritten formatting. Longer term, including custom sections would still be useful to users who want to include sections beyond those we chose to support.

As an example of the later, I have seen many man pages that include a copying section, which isn't one of the sections listed in #1. Many users might want to include that section, and a custom section command would let them do so.

If no one objects or has a different suggestion, I will work on a PR for custom sections.

Move clap v3 -> man glue code to clap_generate

As per clap-rs/clap#552 (comment), the clap team would be happy to add the man page generation code to their new clap_derive crate. That would mean we could move all clap-specific code there, and only keep the man page generation code in this repo.

cc/ @spacekookie how would you feel about moving code there? I also tagged you in the issue above about joining the clap org.

This furthers the https://github.com/rust-lang-nursery/cli-wg/issues/42 milestone issue.

Format example in README to show bold

The example in the README currently shows the output in plain text, when means it cannot show which text is bold. However, GitHub supports using the <pre> tag, which would alow us to use html markup inside the output. The result would look like this:

BASIC(1)                                             General Commands Manual                                             BASIC(1)

NAME
       basic - A basic example

SYNOPSIS
       basic [FLAGS] [OPTIONS]

FLAGS
       -d, --debug
              Enable debug mode

       -v, --verbose
              Enable verbose mode

OPTIONS
       -o, --output=output
              The file path to write output to

USAGE NOTE
       This file will overwrite any file currently stored at the output path.

EXIT STATUS
       0      Successful program execution.

       1      Unsuccessful program execution.

       101    The program panicked.

AUTHORS
         Alice Person <[email protected]>
         Bob Human <[email protected]>

I think this would be pretty helpful in letting users see the actual formatting that man is doing—much of what we're doing is adding bold, so showing the output without that makes the crate look a lot less useful.

My only hesitation about this is crates.io. Does anyone know if it respects the <pre> tag in the same way GitHub does?

Have "source" section

Found myself debugging a tool today, and turned out I had 2 tools installed with duplicate names.

The way I found out was thanks to the "source" section in the man page, providing a key differentiator between the tools.

I propose we add a "source" section to the man page, which ideally can be populated by consumers using the repository value from the Cargo.toml in upstream consumers of man.

Thanks!

Screenshot

2018-08-30-014058_1920x1080

Add examples API

I've taken a look at the examples provided in various man pages and they're pretty diverse (including many that don't have any, but I think we should make it easy for Rust CLIs to provide examples).

I've noticed that example sections seem to have multiple parts, which leads me to propose the following API.
.text_before() default, none
.prompt() default "$"
.command()
.output()
.text_after()`

Here's how this API would look with a simple example (taken from the watchexec man page

Manual::new("watchexec")
  .example(
    Example::new()
      .text_before("Watch all HTML, CSS, and JavaScript files for changes:")
      .command("watchexec -e html,css,js make")
  );

which would print

EXAMPLES
      Watch all HTML, CSS, and JavaScript files for changes:
           $  watchexec -e html,css,js make

And here's a more slightly complex example (from the pass man page)

Manual::new("pass")
  .example(
    Example::new()
      .text_before("Initialize password store")
      .prompt("zx2c4@laptop ~ $")
      .command(" pass init [email protected]")
      .output("mkdir: created directory ‘/home/zx2c4/.password-store’")
      .output("Password store initialized for [email protected].")
  );

Which would produce

EXAMPLES
     Initialize password store
          zx2c4@laptop ~ $ pass init [email protected]
          mkdir: created directory ‘/home/zx2c4/.password-store’
          Password store initialized for [email protected].

The .prompt() method could also take an empty string to produce examples without a leading prompt (the style used in the git man/help pages).

Any thoughts on that API?

Options with no "="

The Opt::new function forces items to labeled --long=NEW. Many programs man pages have display options as --long NEW or --long NEW1 NEW2. Would it be possible in the future to not force the user to have the =? Then the user could add the = to the begining whent they want to use it?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.