markterm/
lib.rs

1#![warn(missing_docs)]
2
3//! A cross-platform library to render colored markdown to the terminal.
4//! The rendered markdown is colored and is themeable.
5//!
6//! The module exposes 4 functions that for handling markdown
7//! * [`render_file_to_stdout`][]
8//!   - Renders the passed in file to stdout using the theme.
9//! * [`render_file`]
10//!   - Themes and renders the passed in file to the implementation of `std::io::Write`` that is passed in.
11//! * [`render_text_to_stdout`]
12//!   - Renders the passed in string to stdout using the theme.
13//! * [`render_text`][]
14//!   - Renders the passed in string to an implementation of std::io::Write that is passed in.
15//!
16//! ## Status
17//! This project started out as a way for me to learn rust. It's gone beyond that now.
18//! At this point, markterm is not compatible with inline html and tables. It also does not support multi level indentations.
19//! These features are in the works
20//!
21//! ## Roadmap
22//! There is a lot we want to do to markterm. The items we have in our immediate queue are listed
23//! below.
24//! - Add support for nested lists.
25//! - Add support for generic colors rather than always having to use RGB.
26//! - Add support for tables.
27//! - Add support for inline html.
28//!
29//! ## Credits
30//! This project would not be possible without [markdown-rs](https://github.com/wooorm/markdown-rs).
31//! Their ast parsing module powers the library.
32
33/// Modules to help theme the output
34pub mod themes;
35
36pub use themes::{color::Color, get_default_theme, ElementTheme, TextStyle, Theme};
37
38/// A module to write the appropriate terminal escape sequence to color the text
39mod writer;
40
41use std::io::{IsTerminal, Read};
42use std::{
43    fs::File,
44    io::{self},
45    path::PathBuf,
46};
47
48/// Indicates whether the output should be colorized or not.
49#[derive(Debug, PartialEq)]
50pub enum ColorChoice {
51    /// Enables colored output only when the output is going to a terminal or TTY.
52    Auto,
53
54    /// Enables colored output regardless of whether or not the output is going to a terminal/TTY.
55    Always,
56
57    /// Disables colored output no matter if the output is going to a terminal/TTY, or not.
58    Never,
59}
60
61/// Renders the contents of the passed in file to stdout.
62///
63/// ### Example
64/// ```rust
65/// use markterm::ColorChoice;
66/// let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
67/// path.push("benches/sample.md");
68///
69/// markterm::render_file_to_stdout(&path, None, ColorChoice::Auto);
70/// ```
71pub fn render_file_to_stdout(
72    file_path: &PathBuf,
73    theme: Option<&self::Theme>,
74    color_choice: ColorChoice,
75) -> Result<(), std::io::Error> {
76    let mut stdout = std::io::stdout().lock();
77    let should_colorize = match color_choice {
78        ColorChoice::Always => true,
79        ColorChoice::Never => false,
80        ColorChoice::Auto => stdout.is_terminal(),
81    };
82
83    render_file(file_path, theme, &mut stdout, should_colorize)
84}
85
86/// Renders the contents of the passed in file to any implementation of std::io::Write.
87///
88/// ### Example
89/// ```rust
90/// use std::io::Write;
91///
92/// let mut path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
93/// path.push("benches/sample.md");
94///
95/// let mut dest = Vec::new();
96/// markterm::render_file(&path, None, &mut dest, false);
97/// ```
98pub fn render_file(
99    file_path: &PathBuf,
100    theme: Option<&Theme>,
101    writer: &mut impl std::io::Write,
102    should_colorize: bool,
103) -> Result<(), std::io::Error> {
104    let file = match File::open(file_path) {
105        Ok(f) => f,
106        Err(e) => {
107            panic!("Unable to open file: {e}");
108        }
109    };
110
111    let mut file_contents = String::new();
112
113    let _files = io::BufReader::new(file)
114        .read_to_string(&mut file_contents)
115        .unwrap();
116
117    render_text(&file_contents, theme, writer, should_colorize)
118}
119
120/// Renders the contents of the passed in string to stdout.
121///
122/// ### Example
123/// ```rust
124/// use markterm::ColorChoice;
125/// let str = "> This is a `test`";
126/// markterm::render_text_to_stdout(str, None, ColorChoice::Auto);
127/// ```
128pub fn render_text_to_stdout(
129    text: &str,
130    theme: Option<&Theme>,
131    color_choice: ColorChoice,
132) -> Result<(), std::io::Error> {
133    let mut stdout = std::io::stdout().lock();
134
135    let should_colorize = match color_choice {
136        ColorChoice::Always => true,
137        ColorChoice::Never => false,
138        ColorChoice::Auto => stdout.is_terminal(),
139    };
140
141    render_text(text, theme, &mut stdout, should_colorize)
142}
143
144/// Renders the contents of the passed in string to any implementation of std::io::Write.
145///
146/// ### Example
147/// ```rust
148/// use std::io::Write;
149///
150/// let str = "> This is a `test`";
151///
152/// let mut dest = Vec::new();
153/// markterm::render_text(str, None, &mut dest, true);
154/// ```
155pub fn render_text(
156    text: &str,
157    theme: Option<&Theme>,
158    writer: &mut impl std::io::Write,
159    should_colorize: bool,
160) -> Result<(), std::io::Error> {
161    let default_theme = get_default_theme();
162    let theme = match theme {
163        Some(x) => x,
164        None => &default_theme,
165    };
166
167    writer::write(text, theme, writer, should_colorize)
168}