termimad/
lib.rs

1/*! This crate lets you display simple markdown snippets
2or scrollable wrapped markdown texts in the terminal.
3
4In order to use Termimad you typically need
5* some *markdown*: a string which you can have loaded or dynamically built
6* a *skin*: which defines the colors and style attributes of every parts
7
8Additionnaly, you might define an *area* of the screen in which to draw (and maybe scroll).
9
10# The skin
11
12It's an instance of [`MadSkin`](struct.MadSkin.html) whose fields you customize according
13to your tastes or (better) to your application's configuration.
14
15
16```rust
17use termimad::crossterm::style::{Color::*, Attribute::*};
18use termimad::*;
19
20// start with the default skin
21let mut skin = MadSkin::default();
22// let's decide bold is in light gray
23skin.bold.set_fg(gray(20));
24// let's make strikeout not striked out but red, with no specific background, and bold
25skin.strikeout = CompoundStyle::new(Some(Red), None, Bold.into());
26```
27
28**Beware:**
29* you may define colors in full [`rgb`](fn.rgb.html) but this will limit compatibility with old terminals. It's recommended to stick to [Ansi colors](fn.ansi.html), [gray levels](fn.gray.html), or [Crossterm predefined values](https://docs.rs/crossterm/0.9.6/crossterm/enum.Color.html).
30* styles are composed. For example a word may very well be italic, bold and striked out. It might not be wise to have them differ only by their background color for example.
31
32# Display a simple inline snippet
33
34
35```
36# use termimad::*;
37// with the default skin, nothing simpler:
38termimad::print_inline("value: **52**");
39```
40# Print a text
41
42A multi-line markdown string can be printed the same way than an *inline* snippet, but you usually want it to be wrapped according to the available terminal width.
43
44```rust,no_run
45# use termimad::*;
46# let skin = MadSkin::default();
47# let my_markdown = "#title\n* item 1\n* item 2";
48eprintln!("{}", skin.term_text(my_markdown));
49```
50
51[`MadSkin`](struct.MadSkin.html) contains other functions to prepare a text for no specific size or for one which isn't the terminal's width. It also offers several functions to print it either on `stdout` or on a given `Write`.
52
53# Display a text, maybe scroll it
54
55A terminal application often uses an *alternate* screen instead of just dumping its text to stdout, and you often want to display in a specific rect of that screen, with adequate wrapping and not writing outside that rect.
56
57You may also want to display a scrollbar if the text doesn't fit the area. A [`MadView`](struct.MadView.html) makes that simple:
58
59```
60# use termimad::*;
61# let markdown = String::from("#title\n* item 1\n* item 2");
62# let skin = MadSkin::default();
63let area = Area::new(0, 0, 10, 12);
64let mut view = MadView::from(markdown, area, skin);
65view.write().unwrap();
66```
67
68If you don't want to give ownership of the skin, markdown and area, you may prefer to use a [`TextView`](struct.TextView.html).
69
70You may see how to write a text viewer responding to key inputs to scroll a markdown text in [the scrollable example](https://github.com/Canop/termimad/blob/master/examples/scrollable/main.rs).
71
72# Templates
73
74In order to separate the rendering format from the content, the `format!` macro is not always a good solution because you may not be sure the content is free of characters which may mess the markdown.
75
76A solution is to use one of the templating functions or macros.
77
78Example:
79
80```
81# #[macro_use] extern crate minimad;
82# use termimad::*;
83# let skin = MadSkin::default();
84mad_print_inline!(
85    &skin,
86    "**$0 formula:** *$1*", // the markdown template, interpreted once
87    "Disk",  // fills $0
88    "2*π*r", // fills $1. Note that the stars don't mess the markdown
89);
90```
91
92Main difference with using `print!(format!( ... ))`:
93* the markdown parsing and template building are done only once (using `once_cell` internally)
94* the given values aren't interpreted as markdown fragments and don't impact the style
95* arguments can be omited, repeated, given in any order
96* no support for fmt parameters or arguments other than `&str` *(in the current version)*
97
98You'll find more examples and advice in the *templates* example.
99
100# Examples
101
102The repository contains several other examples, which hopefully cover the whole API while being simple enough. It's recommended you start by trying them or at least glance at their code.
103
104*/
105
106mod area;
107mod ask;
108mod code;
109mod color;
110mod composite;
111mod composite_kind;
112mod compound_style;
113mod displayable_line;
114mod errors;
115mod events;
116mod fit;
117mod inline;
118mod line;
119mod line_style;
120mod list_indentation;
121mod macros;
122mod parse;
123mod rect;
124mod scrollbar_style;
125mod serde;
126mod skin;
127mod spacing;
128mod styled_char;
129mod table_border_chars;
130mod tbl;
131mod text;
132mod tokens;
133mod views;
134
135pub use {
136    area::{
137        compute_scrollbar,
138        terminal_size,
139        Area,
140    },
141    ask::*,
142    color::*,
143    composite::FmtComposite,
144    composite_kind::*,
145    compound_style::*,
146    coolor,
147    crokey::crossterm,
148    crossbeam,
149    displayable_line::DisplayableLine,
150    errors::Error,
151    events::{
152        EventSource,
153        EventSourceOptions,
154        TickBeamId,
155        Ticker,
156        TimedEvent,
157    },
158    fit::*,
159    inline::FmtInline,
160    line::FmtLine,
161    line_style::LineStyle,
162    list_indentation::*,
163    minimad::{
164        self,
165        Alignment,
166    },
167    parse::*,
168    rect::*,
169    scrollbar_style::ScrollBarStyle,
170    skin::MadSkin,
171    spacing::Spacing,
172    styled_char::StyledChar,
173    table_border_chars::*,
174    text::FmtText,
175    tbl::*,
176    views::{
177        InputField,
178        ListView,
179        ListViewCell,
180        ListViewColumn,
181        MadView,
182        ProgressBar,
183        TextView,
184    },
185};
186
187use tokens::*;
188
189/// Return a reference to the global skin
190///
191/// If you want a new default skin so that you can set
192/// colors or styles, get a separate instance
193/// with `Skin::default()` instead.
194pub fn get_default_skin() -> &'static MadSkin {
195    use minimad::once_cell::sync::Lazy;
196    static DEFAULT_SKIN: Lazy<MadSkin> = Lazy::new(MadSkin::default);
197    &DEFAULT_SKIN
198}
199
200/// Return a formatted line, which implements Display.
201///
202/// This uses the default skin.
203/// Don't use if you expect your markdown to be several lines.
204pub fn inline(src: &str) -> FmtInline<'_, '_> {
205    get_default_skin().inline(src)
206}
207
208/// Return an unwrapped formatted text, implementing Display.
209///
210/// This uses the default skin and doesn't wrap the lines
211///  at all. Most often you'll prefer to use `term_text`
212///  which makes a text wrapped for the current terminal.
213pub fn text(src: &str) -> FmtText<'_, '_> {
214    get_default_skin().text(src, None)
215}
216
217/// Return a terminal wrapped formatted text, implementing Display.
218///
219/// This uses the default skin and the terminal's width
220pub fn term_text(src: &str) -> FmtText<'_, '_> {
221    get_default_skin().term_text(src)
222}
223
224/// Write a string interpreted as markdown with the default skin.
225pub fn print_inline(src: &str) {
226    get_default_skin().print_inline(src);
227}
228
229/// Write a text interpreted as markdown with the default skin.
230pub fn print_text(src: &str) {
231    get_default_skin().print_text(src);
232}