1 /** 2 * Converts embedded code sections to plain text inside `(D_CODE)` without any 3 * syntax highlighting applied. This can be used as lightweight alternative to 4 * ddoc.highlight when syntax highlighting the code is not actually needed. 5 * 6 * Copyright: © 2014 Economic Modeling Specialists, Intl. 7 * Authors: Brian Schott, Mathias 'Geod24' Lang, Jan Jurzitza 8 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 */ 10 module ddoc.unhighlight; 11 12 import std.array; 13 14 /** 15 * Parses a string and replace embedded code (code between at least 3 '-') with 16 * plaintext. 17 * 18 * Params: 19 * str = A string that might contain embedded code. Only code will be modified. 20 * If the string doesn't contain any embedded code, it will be returned as is. 21 * 22 * Returns: 23 * A (possibly new) string containing the embedded code inside `D_CODE` macros. 24 */ 25 string unhighlight(string str) 26 { 27 return highlightBase(str, (code, ref o) { o.put(code); }); 28 } 29 30 /** 31 * Base code for highlight and unhighlight, calling the $(LREF highlightCode) 32 * callback parameter on all embedded sections to handle how it is emitted. 33 * 34 * Params: 35 * str = A string that might contain embedded code. Only code will be modified. 36 * If the string doesn't contain any embedded code, it will be returned as is. 37 * highlightCode = The callback to call for embedded and inlined code sections. 38 * `D_CODE` macross will be automatically prefixed and suffixed before/after 39 * the call to this function. 40 */ 41 string highlightBase(string str, void delegate(string code, ref Appender!string output) highlightCode) 42 { 43 import ddoc.lexer; 44 import ddoc.macros : tokOffset; 45 46 auto lex = Lexer(str, true); 47 auto output = appender!string; 48 size_t start; 49 // We need this because there's no way to tell how many dashes precede 50 // an embedded. 51 size_t end; 52 while (!lex.empty) 53 { 54 if (lex.front.type == Type.embedded) 55 { 56 if (start != end) 57 output.put(lex.text[start .. end]); 58 output.put("$(D_CODE "); 59 highlightCode(lex.front.text, output); 60 output.put(")"); 61 start = lex.offset; 62 } 63 else if (lex.front.type == Type.inlined) 64 { 65 if (start != end) 66 output.put(lex.text[start .. end]); 67 output.put("$(DDOC_BACKQUOTED "); 68 highlightCode(lex.front.text, output); 69 output.put(")"); 70 start = lex.offset; 71 } 72 end = lex.offset; 73 lex.popFront(); 74 } 75 76 if (start) 77 { 78 output.put(lex.text[start .. end]); 79 return output.data; 80 } 81 else 82 { 83 return str; 84 } 85 } 86 87 unittest 88 { 89 import ddoc.lexer; 90 import ddoc.macros; 91 92 string[string] macros = null; 93 94 string text = `description 95 96 Something else 97 98 --- 99 // an example 100 --- 101 Throws: a fit 102 --- 103 /// another example 104 ---`; 105 text = unhighlight(text); 106 auto lexer = Lexer(text, true); 107 assert(expand(lexer, macros, false) == `description 108 109 Something else 110 111 <pre class="d_code">// an example</pre> 112 Throws: a fit 113 <pre class="d_code">/// another example</pre>`); 114 }