1 /*! This crate lets you display simple markdown snippets
2 or scrollable wrapped markdown texts in the terminal.
3 
4 In 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 
8 Additionnaly, you might define an *area* of the screen in which to draw (and maybe scroll).
9 
10 # The skin
11 
12 It's an instance of [`MadSkin`](struct.MadSkin.html) whose fields you customize according
13 to your tastes or (better) to your application's configuration.
14 
15 
16 ```rust
17 use crossterm::style::{Color::*, Attribute::*};
18 use termimad::*;
19 
20 // start with the default skin
21 let mut skin = MadSkin::default();
22 // let's decide bold is in light gray
23 skin.bold.set_fg(gray(20));
24 // let's make strikeout not striked out but red, with no specific background, and bold
25 skin.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
30 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).
31 * 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.
32 
33 # Display a simple inline snippet
34 
35 
36 ```
37 # use termimad::*;
38 // with the default skin, nothing simpler:
39 termimad::print_inline("value: **52**");
40 ```
41 # Print a text
42 
43 A 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.
44 
45 ```rust,no_run
46 # use termimad::*;
47 # let skin = MadSkin::default();
48 # let my_markdown = "#title\n* item 1\n* item 2";
49 eprintln!("{}", skin.term_text(my_markdown));
50 ```
51 
52 [`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`.
53 
54 # Display a text, maybe scroll it
55 
56 A 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.
57 
58 You may also want to display a scrollbar if the text doesn't fit the area. A [`MadView`](struct.MadView.html) makes that simple:
59 
60 ```
61 # use termimad::*;
62 # let markdown = String::from("#title\n* item 1\n* item 2");
63 # let skin = MadSkin::default();
64 let area = Area::new(0, 0, 10, 12);
65 let mut view = MadView::from(markdown, area, skin);
66 view.write().unwrap();
67 ```
68 
69 If you don't want to give ownership of the skin, markdown and area, you may prefer to use a [`TextView`](struct.TextView.html).
70 
71 You 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).
72 
73 # Templates
74 
75 In 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.
76 
77 A solution is to use one of the templating functions or macros.
78 
79 Example:
80 
81 ```
82 # #[macro_use] extern crate minimad;
83 # #[macro_use] extern crate lazy_static;
84 # use termimad::*;
85 # let skin = MadSkin::default();
86 mad_print_inline!(
87 	&skin,
88 	"**$0 formula:** *$1*", // the markdown template, interpreted once
89 	"Disk",  // fills $0
90 	"2*π*r", // fills $1. Note that the stars don't mess the markdown
91 );
92 ```
93 
94 Main difference with using `print!(format!( ... ))`:
95 * the markdown parsing and template building are done only once (using `lazy_static` internally)
96 * the given values aren't interpreted as markdown fragments and don't impact the style
97 * arguments can be omited, repeated, given in any order
98 * no support for fmt parameters or arguments other than `&str` *(in the current version)*
99 
100 You'll find more examples and advice in the *templates* example.
101 
102 Note that there's no macro yet supporting templates for whole markdown *texts* but they should be available soon.
103 
104 # Examples
105 
106 The 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.
107 
108 */
109 
110 #[macro_use]
111 extern crate lazy_static;
112 
113 #[allow(unused_imports)]
114 #[macro_use]
115 extern crate minimad;
116 
117 mod area;
118 mod code;
119 mod color;
120 mod composite;
121 mod compound_style;
122 mod displayable_line;
123 mod errors;
124 mod events;
125 mod fit;
126 mod inline;
127 mod line;
128 mod line_style;
129 mod macros;
130 mod scrollbar_style;
131 mod skin;
132 mod spacing;
133 mod str_fit;
134 mod styled_char;
135 mod tbl;
136 mod text;
137 mod views;
138 mod wrap;
139 
140 pub use area::{compute_scrollbar, terminal_size, Area};
141 pub use color::{ansi, gray, rgb};
142 pub use composite::FmtComposite;
143 pub use compound_style::CompoundStyle;
144 pub use errors::{Error, Result};
145 pub use events::{Event, EventSource};
146 pub use fit::Fitter;
147 pub use inline::FmtInline;
148 pub use line::FmtLine;
149 pub use line_style::LineStyle;
150 pub use minimad::Alignment;
151 pub use scrollbar_style::ScrollBarStyle;
152 pub use skin::MadSkin;
153 pub use str_fit::StrFit;
154 pub use spacing::Spacing;
155 pub use styled_char::StyledChar;
156 pub use text::FmtText;
157 pub use views::{
158     InputField, ListView, ListViewCell, ListViewColumn, MadView, ProgressBar, TextView,
159 };
160 
161 /// Return a reference to the global skin (modifiable).
162 ///
163 /// If you want a new default skin without messing with
164 /// the other default printings, get a separate instance
165 /// with `Skin::default()` instead.
get_default_skin() -> &'static MadSkin166 pub fn get_default_skin() -> &'static MadSkin {
167     lazy_static! {
168         static ref DEFAULT_SKIN: MadSkin = MadSkin::default();
169     }
170     &DEFAULT_SKIN
171 }
172 
173 /// Return a formatted line, which implements Display.
174 ///
175 /// This uses the default skin.
176 /// Don't use if you expect your markdown to be several lines.
inline(src: &str) -> FmtInline<'_, '_>177 pub fn inline(src: &str) -> FmtInline<'_, '_> {
178     get_default_skin().inline(src)
179 }
180 
181 /// Return an unwrapped formatted text, implementing Display.
182 ///
183 /// This uses the default skin and doesn't wrap the lines
184 ///  at all. Most often you'll prefer to use `term_text`
185 ///  which makes a text wrapped for the current terminal.
text(src: &str) -> FmtText<'_, '_>186 pub fn text(src: &str) -> FmtText<'_, '_> {
187     get_default_skin().text(src, None)
188 }
189 
190 /// Return a terminal wrapped formatted text, implementing Display.
191 ///
192 /// This uses the default skin and the terminal's width
term_text(src: &str) -> FmtText<'_, '_>193 pub fn term_text(src: &str) -> FmtText<'_, '_> {
194     get_default_skin().term_text(src)
195 }
196 
197 /// Write a string interpreted as markdown with the default skin.
print_inline(src: &str)198 pub fn print_inline(src: &str) {
199     get_default_skin().print_inline(src);
200 }
201 
202 /// Write a text interpreted as markdown with the default skin.
print_text(src: &str)203 pub fn print_text(src: &str) {
204     get_default_skin().print_text(src);
205 }
206