# Yarner [![Test status](https://github.com/mlange-42/yarner/actions/workflows/tests.yml/badge.svg)](https://github.com/mlange-42/yarner/actions/workflows/tests.yml) [![GitHub](https://img.shields.io/badge/github-repo-blue?logo=github)](https://github.com/mlange-42/yarner) [![Crate](https://img.shields.io/crates/v/yarner.svg)](https://crates.io/crates/yarner) [![Book](https://img.shields.io/badge/book-master-blue.svg)](https://mlange-42.github.io/yarner) [![MIT license](https://img.shields.io/github/license/mlange-42/yarner)](https://github.com/mlange-42/yarner/blob/master/LICENSE) A language-independent [Literate Programming](https://en.wikipedia.org/wiki/Literate_programming) tool for Markdown. From Markdown documents written and structured for humans, Yarner extracts code blocks into compilable source code. It offers sufficient features and flexibility to be usable also for larger projects with numerous files and multiple languages. Yarner works with familiar syntax, which can be further customized to suit your needs exactly. See the [examples](examples) directory for full working examples using different programming languages. See the [**User Guide**](https://mlange-42.github.io/yarner/) for documentation. * [Features](#features) * [Installation](#installation) * [Getting started](#getting-started) * [Configuration](#configuration) * [Contributing](#contributing) * [Acknowledgements](#acknowledgements) ## Features * Macros and named code blocks * Multiple files, multiple entrypoints * File transclusions * Reverse mode * Custom plugins * ... See the [**User Guide**](https://mlange-42.github.io/yarner/) for a complete and detailed explanation of all features. ## Installation **Pre-compiled binaries** 1. Download the [latest binaries](https://github.com/mlange-42/yarner/releases) for your platform 2. Unzip somewhere 3. *Optional:* add the parent directory of the executable to your `PATH` environmental variable **Using `cargo`** In case you have [Rust](https://www.rust-lang.org/) installed, you can install with `cargo`: ```plaintext > cargo install yarner ``` ## Getting started To set up a new project, use the `init` sub-command. Run the following in your project's base directory: ```plaintext > yarner init ``` This creates a file `Yarner.toml` with default settings, and a file `README.md` as starting point for Literate Programming. The generated file already contains some content to get started with Yarner's basic features. For details, see the [User Guide](https://mlange-42.github.io/yarner/). To build the project (extract code and create documentation), simply run: ```plaintext > yarner ``` This creates two sub-directories, one containing the extracted code (a minimal but working Rust project), and another containing the final documentation. Note that the contents of these directories can then be treated as usual, i.e. compiling the code with the normal compiler, or rendering Markdown to HTML or PDF. ## Examples ### Macros Macros are what enables the literate program to be written in logical order for the human reader. Using Yarner, this is accomplished by naming the code blocks, and then referencing them later by "invoking" the macro. By default, macro invocations start with `// ==>` and end with a period `.`. Both of these sequences can be customized to suit your needs better. The only restriction with macro invocations is that they must be the only thing on the line. Here, we have an unnamed code block as entrypoint, and "draw" code from two other code blocks into the main function. These code blocks are named by their first line of code, starting with `//-`. ~~~markdown The program starts in the main function. It calculates something and prints the result: ```rust fn main() { // ==> Calculate something. // ==> Print the result. } ``` The calculation does the following: ```rust //- Calculate something let result = 100; ``` Printing the result looks like this: ```rust //- Print the result println!("{}", result); ``` ~~~ The rendered document looks like this:
The program starts in the main function. It calculates something and prints the result: ```rust fn main() { // ==> Calculate something. // ==> Print the result. } ``` The calculation does the following: ```rust //- Calculate something let result = 100; ``` Printing the result looks like this: ```rust //- Print the result println!("{}", result); ``` |