Skip to content

Commit 7dfdd3f

Browse files
authored
Merge pull request #42 from theiskaa/feature/embedable-config-source
Feature/embedable config source
2 parents 6c80cc5 + 592e72b commit 7dfdd3f

File tree

5 files changed

+414
-156
lines changed

5 files changed

+414
-156
lines changed

README.md

Lines changed: 58 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,112 @@
1-
# markdown2pdf
2-
markdown2pdf is a versatile command-line tool and library designed to convert Markdown content into pre-styled PDF documents. It uses a lexical analyzer to parse the Markdown and a PDF module to generate PDF documents based on the parsed tokens.
1+
<img width="600px" src="https://github.com/user-attachments/assets/fe2e96b8-a0bd-43b4-9360-e6cce43693f2">
32

4-
The library employs a pipeline that first tokenizes Markdown text into semantic elements (like headings, emphasis, code blocks, and lists), then processes these tokens through a styling module that applies configurable visual formatting. The styling engine supports extensive customization of fonts, colors, spacing, and other typographic properties through a TOML configuration file. For more information on how to configure the styling rules, please refer to the [Configuration](#configuration) section down below.
3+
<p align="center">
54

6-
This project includes both a binary and a library:
7-
- **Binary (cli)**: A command-line interface that provides an easy way to convert Markdown files, URLs, or direct string input into styled PDF documents. Supports custom styling through configuration files.
8-
- **Library (lib)**: A robust Rust library that can be integrated into your projects for programmatic Markdown parsing and PDF generation. Offers fine-grained control over the conversion process, styling rules, and document formatting.
5+
[![Crates.io](https://img.shields.io/crates/v/markdown2pdf)](https://crates.io/crates/markdown2pdf)
6+
[![Documentation](https://img.shields.io/docsrs/markdown2pdf)](https://docs.rs/markdown2pdf)
7+
[![License](https://img.shields.io/crates/l/markdown2pdf)](LICENSE)
8+
[![Downloads](https://img.shields.io/crates/d/markdown2pdf)](https://crates.io/crates/markdown2pdf)
9+
[![GitHub Stars](https://img.shields.io/github/stars/theiskaa/markdown2pdf)](https://github.com/theiskaa/markdown2pdf/stargazers)
910

10-
---
11+
</p>
1112

12-
> **Note:** This project is under active development and welcomes community contributions!
13-
> We're continuously adding new features and improvements. If you have suggestions, find bugs, or want to contribute:
14-
> - Open an [issue](https://github.com/theiskaa/markdown2pdf/issues) for bugs or feature requests
15-
> - Submit a [pull request](https://github.com/theiskaa/markdown2pdf/pulls) to help improve the project
16-
> - Check our [CONTRIBUTING.md](CONTRIBUTING.md) guide for development guidelines
13+
markdown2pdf is a command-line tool and library for converting Markdown content into styled PDF documents. It uses a lexical analyzer to parse Markdown and a PDF module to generate documents based on the parsed tokens.
14+
15+
The library employs a pipeline that tokenizes Markdown text into semantic elements, then processes these tokens through a styling module that applies configurable visual formatting. The styling engine supports customization of fonts, colors, spacing, and other typographic properties through TOML configuration. For containerized deployments and self-contained binaries, configurations can be embedded directly at compile time, eliminating runtime file dependencies.
16+
17+
This project includes both a binary and a library. The binary provides a command-line interface for converting Markdown files, URLs, or direct string input into styled PDF documents. The library offers programmatic Markdown parsing and PDF generation with fine-grained control over the conversion process, styling rules, and document formatting, including embedded configuration support for Docker, Nix, and containerized deployments.
18+
19+
The library is fast and reliable, built in Rust for performance and memory safety. It handles comprehensive Markdown syntax including headings, lists, code blocks, links, and images. Configuration is flexible through TOML files that can be loaded from disk or embedded at compile time. The library supports multiple input sources and can generate files or return PDF bytes for in-memory processing.
1720

1821
## Install
1922

20-
You can install the `markdown2pdf` binary globally using cargo by running:
23+
Install the binary globally using cargo:
24+
2125
```bash
2226
cargo install markdown2pdf
2327
```
2428

25-
If you want to install the latest git version:
29+
For the latest git version:
30+
2631
```bash
2732
cargo install --git https://github.com/theiskaa/markdown2pdf
2833
```
2934

3035
## Install as library
3136

32-
Run the following Cargo command in your project directory:
37+
Add to your project:
38+
3339
```bash
3440
cargo add markdown2pdf
3541
```
3642

37-
Or add the following line to your Cargo.toml:
43+
Or add to your Cargo.toml:
44+
3845
```toml
3946
markdown2pdf = "0.1.5"
4047
```
4148

4249
## Usage
43-
To use the `markdown2pdf` tool, you can either specify a Markdown file path, provide Markdown content directly, or set the output PDF path.
44-
### Options
45-
- `-p`, `--path`: Specify the path to the Markdown file to convert.
46-
- `-s`, `--string`: Provide Markdown content directly as a string.
47-
- `-u`, `--url`: Specify a URL to fetch Markdown content from.
48-
- `-o`, `--output`: Specify the output file path for the generated PDF.
4950

50-
### Examples
51-
1. Convert a Markdown file to a PDF:
52-
```bash
53-
markdown2pdf -p "docs/resume.md" -o "resume.pdf"
54-
```
51+
The markdown2pdf tool accepts Markdown file paths, direct content strings, or URLs as input. Options include `-p` for file paths, `-s` for direct string content, `-u` for URLs, and `-o` for output file specification. If multiple input options are provided, precedence follows: path > url > string. Default output is 'output.pdf' if not specified.
5552

56-
Convert the 'resume.md' file in the 'docs' folder to 'resume.pdf'.
53+
Convert a Markdown file:
54+
```bash
55+
markdown2pdf -p "docs/resume.md" -o "resume.pdf"
56+
```
5757

58-
2. Convert Markdown content provided as a string:
59-
```bash
60-
markdown2pdf -s "**bold text** *italic text*." -o "output.pdf"
61-
```
58+
Convert string content:
59+
```bash
60+
markdown2pdf -s "**bold text** *italic text*." -o "output.pdf"
61+
```
6262

63-
Convert the provided Markdown string to 'output.pdf'.
63+
Convert from URL:
64+
```bash
65+
markdown2pdf -u "https://raw.githubusercontent.com/user/repo/main/README.md" -o "readme.pdf"
66+
```
6467

65-
3. Convert Markdown from a URL:
66-
```bash
67-
markdown2pdf -u "https://raw.githubusercontent.com/user/repo/main/README.md" -o "readme.pdf"
68-
```
68+
## Library Usage
6969

70-
Convert the Markdown content from the URL to 'readme.pdf'.
70+
The library exposes two main functions: `parse_into_file()` and `parse_into_bytes()`. Both accept raw Markdown text and handle all intermediate processing steps internally. They leverage the lexer to build an abstract syntax tree, apply styling rules from configuration, and render the final PDF output.
7171

72-
### Notes
73-
- If multiple input options (-p, -s, -u) are provided, only one will be used in this order: path > url > string
74-
- If no output file is specified with `-o`, the default output file will be 'output.pdf'.
72+
The `parse_into_file()` function saves the PDF directly to a file. The `parse_into_bytes()` function returns the PDF data as a byte vector for scenarios requiring more flexibility, such as web services, API responses, or network transmission.
7573

76-
## Using as Library
77-
The library exposes two high-level functions that orchestrate the entire conversion process: `parse_into_file()` and `parse_into_bytes()`. Both functions accept raw Markdown text and handle all intermediate processing steps internally. Under the hood, they leverage the lexer to build an abstract syntax tree, apply styling rules from configuration, and render the final PDF output.
74+
The library uses a `ConfigSource` enum to specify how styling configuration should be loaded. This supports three approaches: default built-in styling, file-based configuration loaded at runtime, or embedded configuration compiled directly into the binary.
7875

79-
The `parse_into_file()` function is perfect for basic usage where you want to save the PDF directly to a file - simply pass your Markdown content as a string along with the desired output path. For scenarios where you need more flexibility, such as web services, API responses, or network transmission, the `parse_into_bytes()` function returns the PDF data as a byte vector that you can manipulate in memory before saving, streaming, or transmitting.
76+
Configuration sources include `ConfigSource::Default` for built-in styling with no external dependencies, `ConfigSource::File("path")` for runtime loading from TOML files, and `ConfigSource::Embedded(content)` for compile-time embedded configuration strings.
8077

8178
```rust
82-
use markdown2pdf::{parse_into_file, parse_into_bytes};
79+
use markdown2pdf::{parse_into_file, config::ConfigSource};
8380

84-
// Direct file output
85-
parse_into_file(markdown, "output.pdf", None)?;
81+
// Default styling
82+
parse_into_file(markdown, "output.pdf", ConfigSource::Default)?;
8683

87-
// Get PDF as bytes for flexible handling
88-
let pdf_bytes = parse_into_bytes(markdown, None)?;
89-
// Use bytes as needed: save, send over network, etc.
90-
std::fs::write("output.pdf", &pdf_bytes)?;
91-
```
84+
// File-based configuration
85+
parse_into_file(markdown, "output.pdf", ConfigSource::File("config.toml"))?;
9286

93-
For more advanced usage, you can work directly with the lexer and PDF generation components. First, create a lexer instance to parse your Markdown content into tokens
94-
```rust
95-
let mut lexer = Lexer::new(markdown);
96-
let tokens = lexer.parse().unwrap(); // handle errors
87+
// Embedded configuration
88+
const CONFIG: &str = include_str!("../config.toml");
89+
parse_into_file(markdown, "output.pdf", ConfigSource::Embedded(CONFIG))?;
9790
```
9891

99-
Next, you'll need to create a PDF renderer to transform the tokens into a formatted document. Before initializing the renderer, you'll need to define styling rules through a `StyleMatch` instance. See the [Configuration](#configuration) section below for details on customizing the styling rules.
100-
```rust
101-
let style = config::load_config(None);
102-
let pdf = Pdf::new(tokens, style);
103-
let document = pdf.render_into_document();
104-
```
92+
For embedded configuration, TOML content can be included at compile time using `include_str!()` or defined as string literals. This approach eliminates runtime file dependencies and creates truly portable executables suitable for containerized deployments.
10593

106-
Finally, the `Document` object can be rendered to a PDF file using the `Pdf::render()` function, or converted to bytes using `Pdf::render_to_bytes()`. These functions handle the actual PDF generation, applying all the styling rules and formatting defined earlier:
94+
For advanced usage, you can work directly with the lexer and PDF generation components. Create a lexer instance to parse Markdown content into tokens, then create a PDF renderer with styling rules through a `StyleMatch` instance loaded via `load_config_from_source()`. Finally, render the document to a file or convert to bytes.
10795

10896
## Configuration
109-
The `markdown2pdf` tool supports customization through a TOML configuration file. You can configure various styling options for the generated PDFs by creating a `markdown2pdfrc.toml` file in your home directory, or by specifying a custom configuration file path.
11097

111-
Under the hood the file is translated to the `StyleMatch` instance which determines how different Markdown elements will be rendered in the final PDF. When using the library, you can load custom styling configurations using `config::load_config()` or create a custom `StyleMatch` implementation. For direct binary usage, the tool automatically looks for a configuration file in your home directory.
98+
The markdown2pdf tool and library support extensive customization through TOML configuration. Configuration can be provided through three methods: default built-in styles, file-based configuration loaded at runtime, or embedded configuration compiled into the binary.
11299

113-
The configuration file supports customization of fonts, colors, spacing, and other visual properties for all Markdown elements. When using the library, you can also programmatically override these settings by modifying the `StyleMatch` instance before passing it to the PDF renderer.
100+
The configuration is translated to a `StyleMatch` instance which determines how different Markdown elements are rendered in the final PDF. Configuration supports customization of fonts, colors, spacing, and other visual properties for all Markdown elements.
114101

115-
### Custom Configuration Path
116-
When using `markdown2pdf` as a library, you can specify a custom configuration file path. This is particularly useful for library usage, project-specific configurations, or when you want to maintain multiple configuration files:
102+
Default configuration uses built-in styling with sensible defaults and requires no external files. File-based configuration loads TOML files at runtime and supports both relative and absolute paths. Embedded configuration compiles TOML content directly into the binary, creating self-contained executables perfect for Docker, Nix, and containerized environments.
117103

118-
Use custom config path - supports both relative and absolute paths
119-
```rust
120-
// For file output
121-
markdown2pdf::parse_into_file(markdown, "output.pdf", Some("../config.toml"))?;
122-
markdown2pdf::parse_into_file(markdown, "output.pdf", Some("/home/user/configs/style.toml"))?;
104+
Embedded configuration provides several advantages: self-contained binaries with no external dependencies, container compatibility with no filesystem concerns, version control integration where configuration changes are tracked with code, compile-time validation where errors are caught early, and production reliability that eliminates missing file errors.
123105

124-
// For bytes output
125-
let pdf_bytes = markdown2pdf::parse_into_bytes(markdown, Some("../config.toml"))?;
126-
let pdf_bytes = markdown2pdf::parse_into_bytes(markdown, Some("/home/user/configs/style.toml"))?;
127-
```
106+
Error handling is graceful - if a specified configuration file cannot be found or contains invalid syntax, the library falls back to default styling without crashing, ensuring PDF generation always succeeds.
128107

129-
Use default config (~/markdown2pdfrc.toml or ./markdown2pdfrc.toml)
130-
```rust
131-
// For file output
132-
markdown2pdf::parse_into_file(markdown, "output.pdf", None)?;
133-
134-
// For bytes output
135-
let pdf_bytes = markdown2pdf::parse_into_bytes(markdown, None)?;
136-
```
137-
138-
**Error Handling:**
139-
If the specified configuration file cannot be found or contains invalid syntax, the library will gracefully fall back to default styling without crashing. This ensures that PDF generation always succeeds, even with configuration issues.
140-
141-
### Getting Started with Configuration for binary
142-
1. Create the config file:
143-
```bash
144-
touch ~/markdown2pdfrc.toml
145-
```
146-
147-
2. Copy the example configuration:
148-
- View the example config at [markdown2pdfrc.example.toml](markdown2pdfrc.example.toml)
149-
- Copy the contents to your `~/markdown2pdfrc.toml` file
150-
- Modify the values according to your preferences
108+
For binary usage, create a config file at `~/markdown2pdfrc.toml` and copy the example configuration from `markdown2pdfrc.example.toml`. For library usage with embedded config, create your configuration file and embed it using `include_str!()` or define it as a string literal, then use it with `ConfigSource::Embedded(content)`.
151109

152110
## Contributing
111+
153112
For information regarding contributions, please refer to [CONTRIBUTING.md](CONTRIBUTING.md) file.

src/bin/main.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,12 @@ fn run(matches: clap::ArgMatches) -> Result<(), AppError> {
4545
.to_str()
4646
.ok_or_else(|| AppError::PathError("Invalid output path".to_string()))?;
4747

48-
markdown2pdf::parse_into_file(markdown, output_path_str, None)
49-
.map_err(|e| AppError::ConversionError(e.to_string()))?;
48+
markdown2pdf::parse_into_file(
49+
markdown,
50+
output_path_str,
51+
markdown2pdf::config::ConfigSource::Default,
52+
)
53+
.map_err(|e| AppError::ConversionError(e.to_string()))?;
5054

5155
println!("[✓] Successfully saved PDF to {}", output_path_str);
5256
Ok(())

0 commit comments

Comments
 (0)