1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
// Copyright by Alexander Willner. See the LICENCE file for the license information. //! Simple rust library and CLI to extract code blocks marked with triple backticks from markdown files into source files. //! //! [![Build Status](https://github.com/alexanderwillner/md2src/workflows/Build-Test/badge.svg)](https://github.com/AlexanderWillner/md2src/actions) [![Coverage Status](https://coveralls.io/repos/github/AlexanderWillner/md2src/badge.svg?branch=master)](https://coveralls.io/github/AlexanderWillner/md2src?branch=master) [![Crates.io](https://img.shields.io/crates/d/md2src?label=crate%20downloads)](https://crates.io/crates/md2src) [![download](https://img.shields.io/github/downloads/AlexanderWillner/md2src/total?label=binary%20downloads)](https://github.com/AlexanderWillner/md2src/releases) //! //! ## Installation //! //! To download the latest release, please run either ```cargo install md2src``` or ```brew install AlexanderWillner/tap/md2src```. //! //! ## Example //! //! Run run ```md2src README.md``` to create the source file named ```code_snippet_000.rs```. //! use exitfailure::ExitFailure; use failure::ResultExt; use pulldown_cmark::{CodeBlockKind, CowStr, Event, Options, Parser, Tag}; use std::fs; use std::path::Path; /// Markdown to source code pub struct MD2Src; impl MD2Src { /// Returns a vector of extracted code snippets. /// /// # Arguments /// /// * `markdown` - The markdown string /// * `lang` - The language of the code snippets defined after three backticks /// * `ignore` - Ignore those code snippets that include this string /// pub fn get_snippets_from_string( self: &Self, markdown: String, lang: String, ignore: Vec<String>, ) -> Result<Vec<String>, ExitFailure> { let parser = Parser::new_ext(&markdown, Options::empty()); let mut active = false; let mut result: Vec<String> = vec![]; for element in parser { if let Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(CowStr::Borrowed(language)))) = element { active = language == lang } if let Event::End(Tag::CodeBlock(CodeBlockKind::Fenced(CowStr::Borrowed(_)))) = element { active = false; } if let Event::Text(code) = element { if active && ignore.iter().all(|s| s.is_empty() || !code.contains(s)) { result.push(code.to_string()); } } } Ok(result) } /// Returns a vector of extracted code snippets. /// /// # Arguments /// /// * `file` - The markdown filename /// * `lang` - The language of the code snippets defined after three backticks /// * `ignore` - Ignore those code snippets that include this string /// pub fn get_snippets_from_file( self: &Self, file: String, lang: String, ignore: Vec<String>, ) -> Result<Vec<String>, ExitFailure> { self.get_snippets_from_string(fs::read_to_string(&file)?, lang, ignore) } /// Writes a vector of extracted code snippets (each snippet one file: `folder/prefix000.ext`). /// /// # Arguments /// /// * `snippets` - The extracted code snippets. /// * `folder` - The target folder for the code files. /// * `prefix` - The prefix of the code files. /// * `ext` - The extension of the code files. /// pub fn write_snippets( self: &Self, snippets: Vec<String>, folder: String, prefix: String, ext: String, ) -> Result<(), ExitFailure> { let mut counter = 0; let mut target: String; for snippet in snippets { target = format!("{}/{}{:0>3}.{}", folder, prefix, counter, ext); counter += 1; fs::write(Path::new(&target), snippet) .with_context(|_| format!("could not write file `{}`", &target))?; } Ok(()) } }