| Crates.io | ndg-commonmark |
| lib.rs | ndg-commonmark |
| version | 2.0.0 |
| created_at | 2025-09-15 08:27:23.344978+00 |
| updated_at | 2025-09-15 08:27:23.344978+00 |
| description | Flavored CommonMark processor for Nix-related projects, with support for CommonMark, GFM, and Nixpkgs extensions. |
| homepage | |
| repository | |
| max_upload_size | |
| id | 1839619 |
| size | 308,943 |
High-performance, extensible Nixpkgs-flavored CommonMark processor designed specifically for ndg in order to document Nix, NixOS and Nixpkgs adjacent projects.
Features AST-based processing, syntax highlighting, and generous documentation.
ls -la,/etc/nixos/configuration.nix,$XDG_CONFIG_HOMEnix.conf{=include=} blocks for modular documentation{man}
role and a manpage map.[]{#custom-id} syntax for precise linkinguse ndg_commonmark::{MarkdownProcessor, MarkdownOptions};
let processor = MarkdownProcessor::new(MarkdownOptions::default());
let result = processor.render("# Hello World\n\nThis is **bold** text.");
// The entire document
println!("HTML: {}", result.html);
// Fine-grained components
println!("Title: {:?}", result.title);
println!("Headers: {:?}", result.headers);
use ndg_commonmark::{MarkdownProcessor, MarkdownOptions};
let mut options = MarkdownOptions::default();
options.highlight_code = true;
options.highlight_theme = Some("one-dark".to_string());
let processor = MarkdownProcessor::new(options);
let markdown = r#"
# Code Example
```rust
fn main() {
println!("Hello, world!");
}
```
```nix
{ pkgs, ... }: {
environment.systemPackages = with pkgs; [ vim git ];
}
```
"#;
let result = processor.render(markdown);
use ndg_commonmark::MarkdownOptions;
let mut options = MarkdownOptions::default();
// Enable GitHub Flavored Markdown (GFM)
options.gfm = true;
// Enable Nixpkgs-specific extensions
options.nixpkgs = true;
// Configure syntax highlighting
options.highlight_code = true;
options.highlight_theme = Some("gruvbox-dark".to_string());
// Set manpage URL mappings
// XXX: this is required for {man} role to function correctly
options.manpage_urls_path = Some("manpage-urls.json".to_string());
let processor = MarkdownProcessor::new(options);
Some of ndg-commonmark's features are gated behind feature flags. This allows compile-time control over what will be made available. Namely you can decide which parts of the flavored CommonMark will be supported.
default: Enables ndg-flavoredndg-flavored: All NDG-specific features (gfm + nixpkgs + syntastica)gfm: GitHub Flavored Markdown extensionsnixpkgs: NixOS/Nixpkgs documentation featuressyntastica: Modern tree-sitter based syntax highlighting (recommended)syntect: Legacy, less robust and more lightweight syntax highlighting[!NOTE] The
syntasticaandsyntectfeatures are mutually exclusive. Enable only one at a time.
[dependencies]
# Recommended: Modern syntax highlighting
ndg-commonmark = { version = "1.0", features = ["gfm", "nixpkgs", "syntastica"] }
# Alternative: Legacy syntax highlighting
ndg-commonmark = { version = "1.0", features = ["gfm", "nixpkgs", "syntect"] }
# No syntax highlighting
ndg-commonmark = { version = "1.0", features = ["gfm", "nixpkgs"] }
MarkdownProcessorThe main processor class:
impl MarkdownProcessor {
pub fn new(options: MarkdownOptions) -> Self;
pub fn render(&self, markdown: &str) -> MarkdownResult;
pub fn extract_headers(&self, content: &str) -> (Vec<Header>, Option<String>);
}
MarkdownOptionsConfiguration options:
pub struct MarkdownOptions {
pub gfm: bool, // GitHub Flavored Markdown
pub nixpkgs: bool, // NixOS documentation features
pub highlight_code: bool, // Syntax highlighting
pub manpage_urls_path: Option<String>, // Manpage URL mappings
pub highlight_theme: Option<String>, // Syntax highlighting theme
}
MarkdownResultProcessing result:
pub struct MarkdownResult {
pub html: String, // Generated HTML
pub headers: Vec<Header>, // Extracted headers
pub title: Option<String>, // Document title (first h1)
}
For advanced syntax highlighting control:
use ndg_commonmark::syntax::{create_default_manager, SyntaxManager};
let manager = create_default_manager()?;
// Highlight code directly
let html = manager.highlight_code("fn main() {}", "rust", Some("one-dark"))?;
// Language detection
if let Some(lang) = manager.highlighter().language_from_filename("script.py") {
println!("Detected: {}", lang);
}
// Available languages and themes
println!("Languages: {:?}", manager.highlighter().supported_languages());
println!("Themes: {:?}", manager.highlighter().available_themes());
use ndg_commonmark::{MarkdownProcessor, MarkdownOptions};
let processor = MarkdownProcessor::new(MarkdownOptions::default());
let markdown = r#"
# Documentation Example
This document demonstrates **ndg-commonmark** features.
## Code Highlighting
```rust
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("key", "value");
println!("{:?}", map);
}
```
## NixOS Configuration
```nix
{ config, pkgs, ... }: {
services.nginx = {
enable = true;
virtualHosts."example.com" = {
enableACME = true;
forceSSL = true;
root = "/var/www/example.com";
};
};
}
```
use ndg_commonmark::{MarkdownProcessor, MarkdownOptions};
use std::collections::HashMap;
let mut options = MarkdownOptions::default();
options.gfm = true;
options.nixpkgs = true;
options.highlight_code = true;
options.highlight_theme = Some("gruvbox-dark".to_string());
options.manpage_urls_path = Some("manpages.json".to_string());
let processor = MarkdownProcessor::new(options);
// Process multiple files
let files = ["intro.md", "configuration.md", "examples.md"];
for file in files {
let content = std::fs::read_to_string(file)?;
let result = processor.render(&content);
println!("Title: {:?}", result.title);
println!("Headers: {:?}", result.headers);
// Write HTML output
let output_file = file.replace(".md", ".html");
std::fs::write(output_file, result.html)?;
}
use ndg_commonmark::{MarkdownProcessor, MarkdownOptions};
use std::path::Path;
use walkdir::WalkDir;
fn build_site(input_dir: &Path, output_dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
let mut options = MarkdownOptions::default();
options.gfm = true;
options.nixpkgs = true;
options.highlight_code = true;
let processor = MarkdownProcessor::new(options);
for entry in WalkDir::new(input_dir) {
let entry = entry?;
if entry.path().extension() == Some("md".as_ref()) {
let content = std::fs::read_to_string(entry.path())?;
let result = processor.render(&content);
let output_path = output_dir.join(
entry.path()
.strip_prefix(input_dir)?
.with_extension("html")
);
std::fs::create_dir_all(output_path.parent().unwrap())?;
std::fs::write(output_path, result.html)?;
}
}
Ok(())
}
This project is licensed under the Mozilla Public License 2.0. See the LICENSE file for more details.
Nix syntax highlighting is available only if using Syntastica as the highlighting backend. Syntect requires an external parser collection, which we no longer support. ↩