cprintf 0.2.0

A tool to format with color and style
Documentation
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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# cprintf

`printf`-like with color and style support.

A sanitized `printf` alternative that also prints colors.

Actually works in `printf` style but with easy color and style specifiers.

## Examples

The quoting and escaping in these examples is assuming that you write these command in a `sh`-like shell.

For more examples, compile and check the `./demo.bash` examples.

At the time of writing these lines, Github doesn't support coloring.

You will need to either 
* checkout this repository, compile and run the [demo.sh]./demo.sh script
* check out the Asciinema showcase, but they also have issues with the brighter colors, some styles, ...
* get a better Markdown reader

Text examples are available in the [Examples.md](./Examples.md) file.

### Basics

[![asciicast](https://asciinema.org/a/gBf1QAkPN6GbWk0oJXOk2aU48.svg)](https://asciinema.org/a/gBf1QAkPN6GbWk0oJXOk2aU48)

### Colors

[![asciicast](https://asciinema.org/a/SbpwZ7bvBo5HZct9vd9X2Pgas.svg)](https://asciinema.org/a/SbpwZ7bvBo5HZct9vd9X2Pgas)

### More colors

[![asciicast](https://asciinema.org/a/N1XUudOsdjgupmBtVhQ6a20aa.svg)](https://asciinema.org/a/N1XUudOsdjgupmBtVhQ6a20aa)

### Styles

[![asciicast](https://asciinema.org/a/AuHNpDwKDalFHj5Z892GOSp38.svg)](https://asciinema.org/a/AuHNpDwKDalFHj5Z892GOSp38)

### C-style escapes

[![asciicast](https://asciinema.org/a/wR6h2fBIGcJO1xlquE5C5wG4C.svg)](https://asciinema.org/a/wR6h2fBIGcJO1xlquE5C5wG4C)

### Quality of life

[![asciicast](https://asciinema.org/a/ilpgpZb56mNNx1XT5M8DhLxuc.svg)](https://asciinema.org/a/ilpgpZb56mNNx1XT5M8DhLxuc)

# Specification

`cprintf` takes at least 1 argument: a format and as many arguments as necessary.

It works in the style of `printf`.

## Format

The format is a string of characters made of regular strings and placeholders.

Example: `Some text followed by a specifier {}`

## Specifiers

Specified in `{}`, rust/python style.

A specifier may contain whitespaces (` `, `\t`, ...) for an easier read.

A specifier's text and color parts may be in any order.

The specifier may contain the following information.

### A color

The color is indicated with `#`.

The color may be regular or bright.

The color is specified with different formats: code (number), single letter or word.

The color short names are based on the
RGB: `r`ed, `g`reen, `b`lue,
and CMYKW: `c`yan, `m`agenta, `y`ellow, blac`k` + `w`hite conventions.

Lower case is the normal variant, upper case is the bright variant.

#### Named colors reference table

| Name    | code | short |  long   | code bright | short bright | long bright |
|---------|:----:|:-----:|:-------:|:-----------:|:------------:|:-----------:|
| Black   |  0   |   k   |  black  |      8      |      K       |    BLACK    |
| Red     |  1   |   r   |   red   |      9      |      R       |     RED     |
| Green   |  2   |   g   |  green  |     10      |      G       |    GREEN    |
| Yellow  |  3   |   y   | yellow  |     11      |      Y       |   YELLOW    |
| Blue    |  4   |   b   |  blue   |     12      |      B       |    BLUE     |
| Magenta |  5   |   m   | magenta |     13      |      M       |   MAGENTA   |
| Cyan    |  6   |   c   |  cyan   |     14      |      C       |    CYAN     |
| White   |  7   |   w   |  white  |     15      |      W       |    WHITE    |

You can also use any hexadecimal color like brown: `#54370f`.

The usual notation applies: `#RRGGBB` in hexadecimal format.
The letters may be either lower or upper case.

The color can also be specified with the `rgb()` function.
It takes 3 parameters: red, green and blue ranging between 0 and 255 included.

#### Foreground/background

The color may be applied to either the foreground, the background or both.

Split with slash foreground over background.

`#foreground/background`

Either side is optional.

`#red` is a red font, regular background.
`#/green` is a regular font, green background.
`#red/green` is a red font, green background.
`#/` is no color, same as not specifying a color.

### A reference

Unlike `printf` where the order of arguments is forced,
`cprintf` may use arguments in any order with `%x` 
where `x` is an integer referring to the arguments passed to `cprintf`.

To use it like `printf`, do

```bash
cprintf '{} {} {}' a b c
``` 

`a b c`

To select an argument by its position, do

```bash
cprintf '{%3} {%2} {%1}' a b c
``` 

`c b a`

For clarity, it's not possible to mix index-based and positional arguments.

### A style

Supports all the styles that the ANSI escape codes allows.

A style can be specified with the long option or the short option 
`{style=bold}` or `{!bold}`.

A style can be specified with a single letter.

|  Long name  |               Alternatives               | Short name |
|:-----------:|:----------------------------------------:|:----------:|
|   strong    |                   bold                   |     s      |
|     dim     |                  faint                   |     d      |
|   italic    |                                          |     i      |
|  underline  |               underscored                |     u      |
|    blink    |                 blinking                 |     b      |
|  reversed   | inverse inversed invert inverted reverse |     r      |
|   hidden    |                invisible                 |     h      |
| crossed-out |           strike strikethrough           |     c      |

Some styles have several names.

It's possible to combine the styles.

For instance `cprintf 'foo {!italic!bold!dim!blink!strike!underline#red}' bar` for maximum visibility 🌟.

The options for the style specifiers are not case-sensitive.

The styles can be specified in many ways to help you save time. Here are a few examples of that:

```
!bold,hidden
!bold !hidden
style=bold,hidden
style=bold style=hidden
!bh
style=bh
!BH
```

#### Bold

`{!s}`
`{style=strong}`

Also accepted:

`{style=bold}`

#### Dim

`{!d}`
`{style=dim}`

Also accepted:

`{style=faint}`

#### Italic

`{!i}`
`{style=italic}`

#### Underline

`{!u}`
`{style=underline}`

Also accepted:

`{style=underscored}`

#### Blink

`{!b}`
`{style=blink}`

Also accepted:

`{style=blinking}`

#### Reversed

`{!r}`
`{style=reversed}`

Also accepted:

`{style=inverted}`
`{style=invert}`
`{style=inverse}`
`{style=inversed}`
`{style=reversed}`
`{style=reverse}`


#### Hidden

`{!h}`
`{style=hidden}`

Also accepted:

`{style=invisible}`

#### Crossed out

`{!c}`
`{style=crossed-out}`


Also accepted:

`{style=strikethrough}`
`{style=strike}`

## Multiple arguments

Use `{@}` to mean "all the args", bash-style.

`cprintf 'hello {%1} {@} {%1}' world foo`

`hello world world foo world`

The separator between the arguments defaults to space ` `.

It's also possible to specify the separator using pipes.

```bash
cprintf 'hello {%1} {@|, |} {%1}' 1 2 3 4
```

`1 1, 2, 3, 4 1`


```bash
cprintf 'hello {@|\||}' a b
```

`a|b`

It's possible to give a style to all the arguments at once using the previous specifiers.

`cprintf {all style=bold color=red}`

Will print all the arguments in red.


## Speed

```bash
hyperfine --shell=none 'target/release/cprintf "foo {!bold color=rgb(1,2,3)} bar {style=blink index=2 #k/R} baz" "Wagamama" "Sakura"'
```

```
Benchmark 1: target/release/cprintf "foo {!bold color=rgb(1,2,3)} bar {style=blink index=2 #k/R} baz" "Wagamama" "Sakura"
  Time (mean ± σ):       1.7 ms ±   0.2 ms    [User: 1.1 ms, System: 0.5 ms]
  Range (min … max):     1.1 ms …   3.3 ms    1155 runs
```

Is it fast? Is it slow? Surely fast enough to satisfy your eyes' bandwidth :)

## Size

A bit chubby.

```
ll target/release/cprintf
-rwxrwxr-x 2 uuh uuh 2,1M Okt 11 19:46 target/release/cprintf
```

## Goals

No `-` `--` `-n` `-e` etc. ambiguity as in `echo`

No `%x` and other random characters like in `printf`

No looking up for color code indexes nor figuring out which option is correct like in tput.

Useful english nouns but allow existing styles for easy migration form those tools.

Support color.

Fast! Native binary.

Format support à la printf but with modern format specifiers:

* selectors
    * positional `{}`
    * indexed `{%1}`
* styles
    * simple colors `{#red}`
    * reset to default after printing? `{#red!preserve}` or auto reset? 🤔
    * any color `{#A03472}`
    * background colors `{#white/red}`
* Styles: bold, italic, blink, reset, ... `{!bold}`
* Position on screen `{@5,10}`

## Motivation

Must be simple to start with and not trap people by default!

Must be powerful enough to not require extra tooling if it's easier, be it

* bash's number formatting trick `$(([##7]v))` for format the variable v in base 7 for instance
* printf's decimal formatting
* escape sequences or tput coloring

I'm tired of looking up color codes and have unreadable color escape sequences.

I don't want to play with `tput setaf 3` and have an unreadable echo statement.

I'm tired of looking up printf's formats, I didn't touch C for years. I use modern languages with friendlier formatting
options.

I don't want to build another layer of bash workarounds. It still contains all of echo's flaws regarding `-` `-n` `-e`
and escape sequences.

https://github.com/ununhexium/configfiles/blob/master/.local/scripts/cecho

https://github.com/ununhexium/configfiles/blob/master/.local/scripts/cecho2

https://github.com/ununhexium/configfiles/blob/master/.local/scripts/bases

I don't want to start a real scripting language, or even worse: the JVM, to highlight a few lines of output in a bash
script.

It may as well be comprehensive so there's 1 tool that gives access to all of the shell's printing capabilities if the
format string remains terse.
I'm likely engaging on a slippery slope but we'll see if it's possible.

I don't want to import and redeclare the colors each time I use them. This should be done once and for all.

https://stackoverflow.com/questions/5412761/using-colors-with-printf

### Limitation in current tools

Mix of bash's base formatting, sprintf's decimal formatting, echo workarounds, escape sequences or tput, alternative
tool that auto-color based on various criteria

### Alternatives?

Alternatives: [zuncito](https://codeberg.org/lukaslauterbach/zuncito)
a friendly C competing implementation.

TODO: is there anything that comes close to this?

If yes list here.

#### DIY

https://gist.github.com/WestleyK/dc71766b3ce28bb31be54b9ab7709082

https://github.com/mikesart/dotfiles/blob/master/.bash_colors

### Shell / Scripts

Fish has an easy way to set a color

https://github.com/fish-shell/fish-shell/issues/2343

https://github.com/ppo/bash-colors

https://gist.github.com/inexorabletash/9122583

## TODOs

% everything
%x single index
%x:y range
%: same as %

## Error message improvements: position hint

## Format specifiers brainstorming

All the format given below are assumed ot be enclosed in `{}`

It must be possible to easily combine the format specifiers.

Format types:

* Name 1st position
* Index `%`
* Color `#`
* Style `!`

## Documents and references

### ANSI escape codes gist

https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797