1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! glitter, a git repository status pretty-printer
//!
//! An expression based, ergonomic language for writing the status of your git repository into
//! your shell prompt.
//!
//! For example :`"\<\b\(\+\-)>\[\M\A\R\D':'\m\a\u\d]\{\h('@')}':'"` results in something that
//! might look like `<master(+1)>[M1:D3]{@5}:` where
//!
//! - `master` is the name of the current branch.
//! - `+1`: means we are 1 commit ahead of the remote branch
//! - `M1`: the number of staged modifications
//! - `D3`: is the number of unstaged deleted files
//! - `@5`: is the number of stashes
//!
//! `glit` expressions also support inline format expressions to do things like making text red,
//! or bold, or using ANSI terminal escape sequences, or setting RGB colors for your git
//! information.
//!
//! # Grammar
//!
//! `glit` expressions have four basic types of expressions:
//!
//! 1. Named expressions
//! 2. Format expressions
//! 3. Group expressions
//! 4. Literals
//!
//! ## Literals
//!
//! Any characters between single quotes literal, except for backslashes and single quotes.
//! Literals are left untouched.  For example, `'literal'` outputs `literal`.
//!
//! ## Named expressions
//!
//! Named expressions represent information about your git repository.
//!
//! | Name  | Meaning                        | Example         |
//! |:------|:-------------------------------|:----------------|
//! | `\b`  | branch name or head commit id  | `master`        |
//! | `\B`  | remote name                    | `origin/master` |
//! | `\+`  | # of commits ahead remote      | `+1`            |
//! | `\-`  | # of commits behind remote     | `-1`            |
//! | `\m`  | # of unstaged modified files   | `M1`            |
//! | `\a`  | # of untracked files           | `?1`            |
//! | `\d`  | # of unstaged deleted files    | `D1`            |
//! | `\u`  | # of merge conflicts           | `U1`            |
//! | `\M`  | # of staged modified files     | `M1`            |
//! | `\A`  | # of added files               | `A1`            |
//! | `\R`  | # of renamed files             | `R1`            |
//! | `\D`  | # of staged deleted files      | `D1`            |
//! | `\h`  | # of stashed files             | `H1`            |
//!
//! You can provide other expressions as arguments to expressions which replace the default prefix
//! which appears before the result or file count.  For example, `\h('@')` will output `@3`
//! instead of `H3` if your repository has 3 stashed files.  You can provide an arbitrary number
//! of valid expressions as a prefix to another named expression.
//!
//! ## Group Expressions
//!
//! Glitter will surround grouped expressions with parentheses or brackets, and will print nothing
//! if the group is empty.
//!
//! | Macro       | Result                           |
//! |:------------|:---------------------------------|
//! | `\[]`       | empty                            |
//! | `\()`       | empty                            |
//! | `\<>`       | empty                            |
//! | `\{}`       | empty                            |
//! | `\{\b}`     | `{master}`                       |
//! | `\<\+\->`   | `<+1-1>`                         |
//! | `\[\M\A\R]` | `[M1A3]` where `\R` is empty     |
//! | `\[\r\(\a)]`| empty, when `\r`, `\a` are empty |
//!
//! ## Format Expressions
//!
//! Glitter expressions support ANSI terminal formatting through the following styles:
//!
//! | Format               | Meaning                                       |
//! |:---------------------|:----------------------------------------------|
//! | `#~(`...`)`          | reset                                         |
//! | `#_(`...`)`          | underline                                     |
//! | `#i(`...`)`          | italic text                                   |
//! | `#*(`...`)`          | bold text                                     |
//! | `#r(`...`)`          | red text                                      |
//! | `#g(`...`)`          | green text                                    |
//! | `#b(`...`)`          | blue text                                     |
//! | `#m(`...`)`          | magenta/purple text                           |
//! | `#y(`...`)`          | yellow text                                   |
//! | `#w(`...`)`          | white text                                    |
//! | `#k(`...`)`          | bright black text                             |
//! | `#[01,02,03](`...`)` | 24 bit rgb text color                         |
//! | `#R(`...`)`          | red background                                |
//! | `#G(`...`)`          | green background                              |
//! | `#B(`...`)`          | blue background                               |
//! | `#M(`...`)`          | magenta/purple background                     |
//! | `#Y(`...`)`          | yellow background                             |
//! | `#W(`...`)`          | white background                              |
//! | `#K(`...`)`          | bright black background                       |
//! | `#{01,02,03}(`...`)` | 24 bit rgb background color                   |
//! | `#01(`...`)`         | Fixed terminal color                          |
//!
//! Format styles can be combined in a single expression by separating them with semicolons:
//!
//! | Format         | Meaning                        |
//! |:---------------|:-------------------------------|
//! | `#w;K(`...`)`  | white text, black background   |
//! | `#r;*(`...`)`  | red bold text                  |
//! | `#42(`...`)`   | a forest greenish color        |
//! | `#_;*(`...`)`  | underline bold text            |

extern crate git2;
#[macro_use]
extern crate nom;
#[cfg_attr(test, macro_use)]
#[cfg(test)]
extern crate proptest;

use std::io;

pub mod ast;
mod color;
pub mod git;
pub mod interpreter;
pub mod parser;

pub use git::Stats;

#[derive(Debug)]
pub enum Error {
    InterpreterError(interpreter::InterpreterErr),
    ParseError(parser::ParseError),
}

impl From<interpreter::InterpreterErr> for Error {
    fn from(e: interpreter::InterpreterErr) -> Self {
        Error::InterpreterError(e)
    }
}

impl From<parser::ParseError> for Error {
    fn from(e: parser::ParseError) -> Self {
        Error::ParseError(e)
    }
}

pub fn glitter<W: io::Write>(
    stats: Stats,
    format: String,
    allow_color: bool,
    bash_prompt: bool,
    w: &mut W,
) -> Result<(), Error> {
    let tree = parser::parse(format)?;
    interpreter::Interpreter::new(stats, allow_color, bash_prompt).evaluate(&tree, w)?;
    Ok(())
}