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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
// Copyright 2017 Lyndon Brown
//
// Licensed under the MIT license or the Apache license (version 2.0), at your option. You may not
// copy, modify, or distribute this file except in compliance with said license. You can find copies
// of these licenses either in the LICENSE-MIT and LICENSE-APACHE files, or alternatively at
// <http://opensource.org/licenses/MIT> and <http://www.apache.org/licenses/LICENSE-2.0>
// respectively.

//! ANSI terminal text formatting assistant
//!
//! Some virtual-terminals (ANSI ones being the focus here) have a feature of allowing command-line
//! programs executed in them to request that certain limited formatting effects such as colour or
//! boldness be applied to portions of the text the program outputs for them to display. This is
//! achieved through the program embedding special “ANSI control” byte sequences into that text
//! output. This can prove very useful for instance in highlighting error notices.
//!
//! The purpose of this crate is to offer functionality to assist in generating and using such
//! control sequences.
//!
//! Note that such formatting should only be used when the `stdout` stream (or `stderr` as
//! applicable) is connected to an actual terminal that will process and use them (you wouldn't want
//! these control sequences to exist in output that the user is having the terminal redirect into a
//! text file or another program as then it would just be treated as a part of the text and lead to
//! garbled output and confusion). Some utility functions are provided within the [support mod] to
//! assist you with determining appropriateness of using formatted output.
//!
//! # Predefined sequences
//!
//! There is no strict need to actually understand how to construct such control sequences to make
//! use of the formatting they offer; many predefined sequences are available for your use in the
//! [predefined mod].
//!
//! To make use of these simply inject them into the right points of a to-be-printed string via
//! format arguments, as demonstrated below. Remember not to forget to make use of a reset after the
//! text to be formatted. For instance:
//!
//! ```rust
//! use term_ctrl::predefined::{RESET, colours::fg::RED};
//! println!("{}Error:{} You made an error!", RED, RESET);
//! ```
//!
//! In the example just given, the text “<span style="color:#c00">Error:</span>” will be highlighted
//! in red. Of course as mentioned earlier, you should only use the colour sequences if output is
//! actually connected to a terminal (and that the terminal has not redirected it, so do not assume
//! output to stdout is okay). Here the example is modified to use a helper to check suitability and
//! a filter to control use:
//!
//! ```rust
//! use term_ctrl::predefined::{RESET, colours::fg::RED};
//! let format = term_ctrl::support::fmt_supported_stdout();
//! let filter = |seq| { match format { true => seq, false => "" } };
//! println!("{}Error:{} You made an error!", filter(RED), filter(RESET));
//! ```
//!
//! Note, when resetting to normal, be sure to always use the proper reset sequence. Do not make the
//! mistake of setting text colour to black and presuming that this achieves the same thing; it does
//! not. (Consider that some people have black text on a white background in their terminal, whilst
//! others use the opposite! Black text on a black background does not work very well!).
//!
//! # Constructing sequences
//!
//! Although understanding the sequences is not required, there are however benefits to be gained
//! from it, since for instance not every possible combination can reasonably be provided in
//! predefined form, and you may be able to achieve greater efficiency by constructing a custom one
//! rather than using multiple predefines in sequence.
//!
//! Let’s take a quick look at the sequence itself, then we can move on to discuss a macro which
//! helps make custom construction very easy.
//!
//! ## The sequence pattern
//!
//! The sequence pattern consists of four component parts:
//!
//! <table style="width:auto">
//!     <tr><td>1</td><td>ESC ('\u{1B}')</td><td>The escape (␛) char, Unicode 0x1B</td></tr>
//!     <tr><td>2</td><td>'['</td><td>An opening bracket char</td></tr>
//!     <tr><td>3</td><td colspan="2">One or more numbers using a semi-colon (';') as a separator</td></tr>
//!     <tr><td>4</td><td>'m'</td><td>A lower-case letter m</td></tr>
//! </table>
//!
//! In other words a pattern of: `"\u{1B}[` <em><codes\></em> `m"`
//!
//! Every control sequence fits this template, and it is the set of numbers included in it which
//! determine the precise formatting nature of the request. As a quick example, the sequence of
//! `"\u{1B}[31;1m"` specifies two numbers, `31` which corresponds to red text, and `1` which
//! corresponds to bold text (the set of available number codes are discussed shortly).
//!
//! Typically each of the individual numbers given corresponds to a particular effect, however as we
//! will see shortly there are a couple of exceptions where multiple numbers are used.
//!
//! Before we continue, understand that the effects specified are applied in sequence and remain in
//! effect until changed or reset by a subsequent code in the sequence or by such a code in a later
//! sequence. Hence in the example given earlier, a sequence is used to enable red text, this is
//! followed by some text to which this formatting applies, then a new sequence is given that issues
//! the reset-all code. There are codes available for removing specific effects or resetting just
//! foreground or background-highlight colours. There is also the catch-all code `0` for resetting
//! everything to normal.
//!
//! ## Macro construction
//!
//! As just mentioned, a macro (called [`seq`]) is provided to assist with constructing sequences.
//! All you have to do is provide it with a list of decimal numbers and it will construct a string
//! of the above pattern that contains them. An example:
//!
//! ```rust
//! use term_ctrl::seq;
//! assert_eq!("\u{1B}[1;2;3m", seq!(1, 2, 3));
//! ```
//!
//! Note that you are not restricted to pure numeric literals, string literals work also:
//!
//! ```rust
//! use term_ctrl::seq;
//! assert_eq!("\u{1B}[1;2;3m", seq!("1", "2", "3"));
//! assert_eq!("\u{1B}[1;2;3m", seq!("1;2", 3));
//! ```
//!
//! Convenience macros are also provided for constructing 256-colour and RGB colour code sets for
//! use in a sequence (they do not generate the full sequence, just a multi-code set of numbers to
//! use in a sequence).
//!
//! ## Number code chart
//!
//! The following is a guide to the available number codes and what they correspond to. In most
//! cases a single number code corresponds to a single effect, however there are also those that
//! require a sequence of multiple numbers (with the normal semi-colon separator).
//!
//! ### Effects
//!
//! <table>
//!     <thead>
//!         <tr><th>Code</th><th>Effect</th><th>Code</th><th>Effect</th></tr>
//!     </thead>
//!     <tbody>
//!         <tr><td>0</td><td>Normal (reset)</td><td>20</td><td><a href="https://en.wikipedia.org/wiki/Fraktur_(script)">Fraktur</a> on</td></tr>
//!         <tr><td>1</td><td>Bold on (increase intensity)</td><td>21</td><td>Double-underline on</td></tr>
//!         <tr><td>2</td><td>Dim on (faint, or decrease intensity)</td><td>22</td><td>Bold and dim off</td></tr>
//!         <tr><td>3</td><td>Italic on</td><td>23</td><td>Italic and Fraktur off</td></tr>
//!         <tr><td>4</td><td>Underline on</td><td>24</td><td>Underline (and double-underline) off</td></tr>
//!         <tr><td>5</td><td>Blink on</td><td>25</td><td>Blink off (aka “steady”)</td></tr>
//!         <tr><td>6</td><td>Rapid-blink on</td><td>26</td><td><em>unused?</em></td></tr>
//!         <tr><td>7</td><td>“Inverse” on (swap fg/bg colours)</td><td>27</td><td>Inverse off (aka “positive”)</td></tr>
//!         <tr><td>8</td><td>Invisible (hidden) on</td><td>28</td><td>Invisible off (aka “visible”)</td></tr>
//!         <tr><td>9</td><td>Strike-through on</td><td>29</td><td>Strike-through off</td></tr>
//!     </tbody>
//! </table>
//!
//! Code zero (`0`) resets all effects and colour selections to defaults.
//!
//! Note that codes `22`-`25` and `27`-`29` provide for removing specific effects.
//!
//! Codes `10-19` (unlisted above) are used for font selection. Code `10` selects the primary
//! (default) font. Codes `11`-`19` select alternate fonts 1-9.
//!
//! ### Basic colours
//!
//! The basic colour palettes consist of a simple set of eight colours for each of foreground and
//! background-highlight uses. There are also “bright” variants.
//!
//! <table>
//!     <thead>
//!         <tr><th>Colour</th><th>Foreground</th><th>Background</th><th>Bright foreground</th><th>Bright background</th></tr>
//!     </thead>
//!     <tbody>
//!         <tr><td>Black</td><td>30</td><td>40</td><td>90</td><td>100</td></tr>
//!         <tr><td>Red</td><td>31</td><td>41</td><td>91</td><td>101</td></tr>
//!         <tr><td>Green</td><td>32</td><td>42</td><td>92</td><td>102</td></tr>
//!         <tr><td>Yellow</td><td>33</td><td>43</td><td>93</td><td>103</td></tr>
//!         <tr><td>Blue</td><td>34</td><td>44</td><td>94</td><td>104</td></tr>
//!         <tr><td>Magenta</td><td>35</td><td>45</td><td>95</td><td>105</td></tr>
//!         <tr><td>Cyan</td><td>36</td><td>46</td><td>96</td><td>106</td></tr>
//!         <tr><td>White</td><td>37</td><td>47</td><td>97</td><td>107</td></tr>
//!         <tr><td><em>Extended</em></td><td>38</td><td>48</td><td><em>n/a</em></td><td><em>n/a</em></td></tr>
//!         <tr><td><em>Default</em> (reset)</td><td>39</td><td>49</td><td><em>n/a</em></td><td><em>n/a</em></td></tr>
//!     </tbody>
//! </table>
//!
//! The “extended” codes `38` and `48` are used to start multi-code “extended” colour palette
//! selections, as discussed shortly.
//!
//! The “default” codes `39` and `49` are used to reset foreground and background-highlight colours
//! respectively to defaults, and apply to bright and extended colouring also.
//!
//! Note that the “bright” codes are not actually a part of the official ANSI standard, apparently.
//!
//! ### Extended range colours
//!
//! Wider choice of colours than above is made available as *extended* colours through use of a
//! sequence of codes (using the normal semi-colon separator).
//!
//! There are two ranges available, an 8-bit (256 colour) range, and a 24-bit RGB range. Both begin
//! with either `38` to choose text (foreground colouring) or `48` for background-highlight
//! colouring. This is followed by `5` for specifying 256-colour or `2` for specifying RGB colour.
//! With 256-colour a final third number with a value in the range of 0-255 selects the specific
//! colour. With RGB, three numbers must be given, each corresponding to red, green and blue
//! respectively, and each also being of a value in the range 0-255.
//!
//! [See here][Xterm_256color_chart.svg] for a 256-colour chart.
//!
//! As an example, `seq!(38,5,238)` changes the colour of text (not background) since it starts with
//! `38`, it is providing a 256-colour palette selection (the `5`), and is specifically selecting
//! colour `238` from that palette.
//!
//! As another example, `seq!(48,2,180,15,70)` changes the colour of the text background since it
//! starts with `48`, it is providing an RGB colour (the `2`), and is then followed with RGB values
//! of `180` for red, `15` for green and `70` for blue.
//!
//! # Resources
//!
//! A collection of useful or informative related resources:
//!
//!  - [Wikipedia: ANSI_escape_code][wikipedia_ANSI_escape_code_SGR] (Specifically the CSI-SGR stuff)
//!  - [Wikipedia: Xterm][wikipedia_Xterm]
//!  - [Xterm control sequence documentation][xterm_ctlseqs]
//!  - [256-color chart][Xterm_256color_chart.svg]
//!
//! [support mod]: mod@crate::support
//! [predefined mod]: mod@crate::predefined
//! [`seq`]: macro@seq
//! [Xterm_256color_chart.svg]: https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg
//! [wikipedia_ANSI_escape_code_SGR]: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR
//! [wikipedia_Xterm]: https://en.wikipedia.org/wiki/Xterm
//! [xterm_ctlseqs]: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html

#![no_std]

extern crate atty;
#[cfg(windows)]
extern crate winapi;

pub mod codes;
mod macros;
pub mod predefined;
pub mod support;