user-error 1.0.3

Simple error type that display in a clear and beautiful manner to the user of a CLI application.
Documentation
# UserError
UserError is an error type that helps you format and print good looking error messages for users of your CLI application. These errors are intended for consumption by a human, not your program. They are divided into 3 parts: summary, reasons and subtleties.

**Summary:** A String representing a one-line description of your error. A summary is mandatory and is printed boldly in red.

**Reasons:** A vector of Strings explaining in more detail _why_ this error occured. Reasons are optional and if the terminal supports color, the bullet point ('-') will be colored yellow. Each reason will be printed on its own line.

**Sublteties:** A vector of Strings explaining additional information, including what the user can do about the error, or where to file a bug. Sublteties are optionals and if the terminal supports color, subtleties will be printed _dimly_. Each subtly will be printed on its own line

### Coercion
std::io::Error, Err(String) and Err(&str) can all be coerced into a UserError. See the docs for examples.

### Docs
The docs are _really_ good for this crate. In addition to reading this README you can find tons of examples in the documentation generated by Cargo.

# Quickstart
Add the following to your Cargo.toml:
```yaml
[dependencies]
user-error = "1.0.2"
```

Add the following to your main.rs/lib.rs:
```rust
use user_error::UserError;

fn main() {
    let e = UserError::hardcoded("Failed to build project", 
                                    &[  "Database could not be parsed", 
                                        "File \"main.db\" not found"], 
                                    &[  "Try: touch main.db", 
                                        "This command will create and empty database file the program can use"]);
    eprintln!("{}", e);
}
```
This prints:
```text
Error: Failed to build project
- Database could not be parsed
- File "main.db" not found
Try: touch main.db
This command will create and empty database file the program can use 
```
If the user has colors enabled on their terminal, it may look something like this:
![Quickstart example of user-error library for Rust](https://xvrqt.sfo2.digitaloceanspaces.com/image-cache/user-error-output.png)

# Examples

## Creating Errors
If you're a flawless being like me, you are probably wondering how one makes a UserError, here are examples of the different ways:

### Simple Error
Creates an error with only a summary.
```rust
use user_error::UserError;

fn main() {
    let e = UserError::simple("Failed to build project");
    eprintln!("{}", e);
}
```

This prints:
```text
Error: Failed to build project
```

### Static Error
Creates an error from hardcoded &str's
```rust
use user_error::UserError;

fn main() {
    let e = UserError::hardcoded("Failed to build project", 
                                    &[  "Database could not be parsed", 
                                        "File \"main.db\" not found"], 
                                    &[  "Try: touch main.db", 
                                        "This command will create and empty database file the program can use"]);
    eprintln!("{}", e);
}
```
This prints:
```text
Error: Failed to build project
- Database could not be parsed
- File "main.db" not found
Try: touch main.db
This command will create and empty database file the program can use 
```

### Dynamic Error
Creates an error using heap allocated structures.
```rust
use user_error::UserError;

fn main() {
    let error_summary    = String::from("Failed to build project");
    let error_reasons    = vec![String::from("Database could not be parsed"), 
                                String::from("File \"main.db\" not found")];
    let error_subtleties = vec![String::from("Try: touch main.db"), 
                                String::from("This command will create and empty database file the program can use ")];
    let e = UserError::new(error_summary, error_reasons, error_subtleties);
    eprintln!("{}", e);
}
```
This prints:
```text
Error: Failed to build project
- Database could not be parsed
- File "main.db" not found
Try: touch main.db
This command will create and empty database file the program can use 
```

### From Other Errors
Certain types of errors will be automagically coerced into a UserError - and will preserve a pointer to the original error (should you need it)
Creates an error using heap allocated structures.
```rust
use std::fs::File;
use user_error::UserError;

// A really redundant way to open a file
fn open_file(path: &str) -> Result<File, UserError> {
    let f = File::open(path)?; // std::io::Error is coerced into a UserError here
    Ok(f)
}

fn main() {
    match open_file("does_not_exist.txt") {
        Err(e) => eprintln!("{}", e),
        Ok(_) => ()
    }
}
```
This prints:
```text
Error: No such file or directory (os error 2)
```

## Convenience Methods
These methods could save you some boilerplate in the same way unwrap() does.

### Print
If for some reason you don't want to follow the format!() convention, you can call print() on a UserError and it will pretty print itself to stderr
```rust
use user_error::UserError;

fn main() {
    let e = UserError::simple("Critical Failure!");
    e.print();
}
```
This prints:
```text
Error: Critical Failure!
```

### Print and Exit
Since this error is likely the last thing your program will run you can use this shortcut to print the error and exit the process in an immediate, albeit ungraceful manner. Returns error code 1 to the OS.
```rust
use user_error::UserError;

fn main() {
    let e = UserError::simple("Critical Failure!");
    e.print_and_exit();
    eprintln("I am never printed!");
}
```
This prints:
```text
Error: Critical Failure!
```

## Modifying the Error
There are a few methods for modifying the UserError after it has been made:

- clear_reasons(): empties the reasons array
- clear_subtleties(): empties the subtleties array
- add_reason(): add another reason to the reasons array
- add_subtly(): add another subtly to the subtleties array

Additional information can be found in the documentation.

# Future Work

 - Adding more types that a UserError can be coerced from
 - Figuring out how to implement source() for an arbitrary type that implements Error
 - Printing out a link to the issue tracker