Skip to content

Instantly share code, notes, and snippets.

@zicklag
Created December 20, 2019 22:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zicklag/e91c85fd67e0e08a3518d76e750b7395 to your computer and use it in GitHub Desktop.
Save zicklag/e91c85fd67e0e08a3518d76e750b7395 to your computer and use it in GitHub Desktop.
Termimad example
//! run this example with
//! cargo run --example scrollable
//!
use crossterm::{
cursor::Hide,
cursor::Show,
event::{
self,
Event,
KeyEvent,
KeyCode::*,
},
queue,
terminal::{self, EnterAlternateScreen, LeaveAlternateScreen},
style::Color::*,
};
use std::io::{stderr, Write};
use termimad::*;
use minimad::*;
fn run_app(skin: MadSkin) -> Result<()> {
let mut w = stderr(); // we could also have used stdout
queue!(w, EnterAlternateScreen)?;
terminal::enable_raw_mode()?;
queue!(w, Hide)?; // hiding the cursor
let mut area = Area::full_screen();
area.pad_for_max_width(120); // we don't want a too wide text column
// let mut view = MadView::from(MD.to_owned(), area, skin);
let template = TextTemplate::from(MD);
let exp = template.expander();
let doc = exp.expand();
let fmt_text = FmtText::from_text(&skin, doc.clone(), Some(area.width as usize));
let mut view = TextView::from(&area, &fmt_text);
loop {
view.write_on(&mut w)?;
w.flush()?;
if let Ok(Event::Key(KeyEvent{code, ..})) = event::read() {
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,
};
}
}
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<()> {
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 some side margin to be prettier)
* a markdown text **parsed**, **skinned**, **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. The margin in this example is just here to show that wrapping is handled:
let mut area = Area::full_screen();
area.pad(2, 1); // let's add some margin
*(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)
"#;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment