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
|
//! run this example with
//! cargo run --example scrollable
//!
use std::io::{stdout, Write};
use termimad::crossterm::{
cursor::{ Hide, Show},
event::{
self,
Event,
KeyEvent,
KeyCode::*,
},
queue,
terminal::{
self,
Clear,
ClearType,
EnterAlternateScreen,
LeaveAlternateScreen,
},
style::Color::*,
};
use termimad::*;
fn view_area() -> Area {
let mut area = Area::full_screen();
area.pad_for_max_width(120); // we don't want a too wide text column
area
}
fn run_app(skin: MadSkin) -> Result<(), Error> {
let mut w = stdout(); // we could also have used stderr
queue!(w, EnterAlternateScreen)?;
terminal::enable_raw_mode()?;
queue!(w, Hide)?; // hiding the cursor
let mut view = MadView::from(MD.to_owned(), view_area(), skin);
loop {
view.write_on(&mut w)?;
w.flush()?;
match event::read() {
Ok(Event::Key(KeyEvent{code, ..})) => {
match code {
Up => view.try_scroll_lines(-1),
Down => view.try_scroll_lines(1),
PageUp => view.try_scroll_pages(-1),
PageDown => view.try_scroll_pages(1),
_ => break,
}
}
Ok(Event::Resize(..)) => {
queue!(w, Clear(ClearType::All))?;
view.resize(&view_area());
}
_ => {}
}
}
terminal::disable_raw_mode()?;
queue!(w, Show)?; // we must restore the cursor
queue!(w, LeaveAlternateScreen)?;
w.flush()?;
Ok(())
}
fn make_skin() -> MadSkin {
let mut skin = MadSkin::default();
skin.table.align = Alignment::Center;
skin.set_headers_fg(AnsiValue(178));
skin.bold.set_fg(Yellow);
skin.italic.set_fg(Magenta);
skin.scrollbar.thumb.set_fg(AnsiValue(178));
skin.code_block.align = Alignment::Center;
skin
}
fn main() -> Result<(), Error> {
let skin = make_skin();
run_app(skin)
}
static MD: &str = r#"# Scrollable Markdown in Termimad
Use the **↓** and **↑** arrow keys to scroll this page.
Use any other key to quit the application.
*Now I'll describe this example with more words than necessary, in order to be sure to demonstrate scrolling (and **wrapping**, too, thanks to long sentences).*
## What's shown
* an **area** fitting the screen (with a max width of 120, to be prettier)
* a markdown text
* **parsed**,
* **skinned**,
* and **wrapped** to fit the width
* a **scrollable** view in *raw terminal mode*
## Area
The area specifies the part of the screen where we'll display our markdown.
let mut area = Area::full_screen();
area.pad_for_max_width(120); // we don't want a too wide text column
*(yes the code block centering in this example is a little too much, it's just here to show what's possible)*
## Parsed Markdown
The text is parsed from a string. In this example we directly wrap it for the width of the area:
let text = skin.area_wrapped_text(markdown, &area);
If we wanted to modify the parsed representation, or modify the area width, we could also have kept the parsed text (*but parsing is cheap*).
## The TextView
It's just a text put in an area, tracking your **scroll** position (and whether you want the scrollbar to be displayed).
let mut text_view = TextView::from(&area, &text);
## Really Scrolling
Not two applications handle events in the same way. **Termimad** doesn't try to handle this but lets you write it yourself, which is fairly easily done with **Crossterm** for example:
```
let mut events = TerminalInput::new().read_sync();
loop {
text_view.write()?;
if let Some(Keyboard(key)) = events.next() {
match key {
Up => text_view.try_scroll_lines(-1),
Down => text_view.try_scroll_lines(1),
PageUp => text_view.try_scroll_pages(-1),
PageDown => text_view.try_scroll_pages(1),
_ => break,
}
}
}
```
## Skin
We want *shiny **colors*** (and unreasonnable centering):
let mut skin = MadSkin::default();
skin.set_headers_fg(rgb(255, 187, 0));
skin.bold.set_fg(Yellow);
skin.italic.set_fgbg(Magenta, rgb(30, 30, 40));
skin.scrollbar.track.set_fg(Rgb{r:30, g:30, b:40});
skin.scrollbar.thumb.set_fg(Rgb{r:67, g:51, b:0});
skin.code_block.align = Alignment::Center;
The scrollbar's colors were also adjusted to be consistent.
## Usage
* **↓** and **↑** arrow keys : scroll this page
* any other key : quit
## And let's just finish by a table
It's a little out of context but it shows how a wide table can be wrapped in a thin terminal.
|feature|supported|details|
|-|:-:|-
| tables | yes | pipe based only, alignement not yet supported
| italic, bold | yes | star based only|
| inline code | yes |
| code bloc | yes |with tabs. Fences not supported
| crossed text | ~~not yet~~ | wait... now it works!
| phpbb like links | no | (because it's preferable to show an URL in a terminal)
(resize your terminal if it's too wide for wrapping to occur)
"#;
|