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