33 template <
typename A,
typename B>
34 std::string generateDiff(
const A& prev,
const B& curr) {
35 TempFileStream in_prev;
36 TempFileStream in_curr;
41 std::string diff_cmd =
42 "diff --new-line-format='+%L' "
43 " --old-line-format='-%L' "
44 " --unchanged-line-format=' %L' ";
45 return execStdOut(diff_cmd + in_prev.getFileName() +
" " + in_curr.getFileName()).str();
48 std::string replaceAll(std::string_view text, std::string_view key, std::string_view replacement) {
49 std::ostringstream
ss;
50 for (
auto tail = text; !
tail.empty();) {
51 auto i =
tail.find(key);
53 if (
i == std::string::npos)
break;
63 out <<
"<a href=\"#" <<
id <<
"\">" <<
title <<
"</a>\n";
67 if (subsection.hasSubsections()) {
74 out <<
"<li class='leaf'>";
78 subsection.printIndex(out);
85 out <<
"<a id=\"" <<
id <<
"\"></a>\n";
86 out <<
"<div class='headerdiv'>\n";
87 out <<
"<h1>" <<
title <<
"</h1>\n";
88 out <<
"<a href='#'>(return to top)</a>\n";
89 out <<
"</div><div style='clear:both'></div>\n";
94 out <<
"<div style='padding-left: 1em'>\n";
97 subsection.printContent(out);
104 endSection(
"forced-closed",
"Forcing end of unknown section");
112 if (dst.empty() ||
empty())
return;
114 std::ofstream(dst) << *
this;
119 std::move(
id), std::move(title),
tfm::format(
"<pre>%s</pre>", replaceAll(code,
"<",
"<"))));
123 std::string_view prev, std::string_view curr) {
125 replaceAll(replaceAll(prev.empty() ? curr : generateDiff(prev, curr),
"\\",
"\\\\"),
"`",
"\\`");
128 <div id="code-id-%d"></div>
129 <script type="text/javascript"> renderDiff('%s', 'code-id-%d', `%s`) </script>
132 std::move(id), std::move(title),
tfm::format(html, divId, language, divId, diff)));
139 std::move(currentSectionName), std::move(currentSectionTitle), std::move(subsections),
""));
148 <meta charset=\"UTF-8\">
149 <title>Souffle Debug Report ()";
152 ul { list-style-type: none; }
153 ul > li.leaf { display: inline-block; padding: 0em 1em; }
154 ul > li.nonleaf { padding: 0em 1em; }
155 * { font-family: sans-serif; }
156 pre { white-space: pre-wrap; font-family: monospace; }
157 a:link { text-decoration: none; color: blue; }
158 a:visited { text-decoration: none; color: blue; }
159 div.headerdiv { background-color:lightgrey; margin:10px; padding-left:10px; padding-right:10px;
160 padding-top:3px; padding-bottom:3px; border-radius:5px }
161 .headerdiv h1 { display:inline; }
162 .headerdiv a { float:right; }
165 <link rel="stylesheet" type="text/css" href=
166 "https://cdn.jsdelivr.net/npm/highlight.js@10.0.0/styles/default.min.css" />
167 <script type="text/javascript" src=
168 "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.0.0/build/highlight.min.js"></script>
170 <link rel="stylesheet" type="text/css" href=
171 "https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css" />
172 <script type="text/javascript" src=
173 "https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui-base.min.js"></script>
176 function toggleVisibility(id) {
177 var element = document.getElementById(id);
178 if (element.style.display == 'none') {
179 element.style.display = 'block';
181 element.style.display = 'none';
185 if (typeof hljs !== 'undefined') {
186 hljs.registerLanguage('souffle', function (hljs) {
187 let COMMENT_MODES = [
188 hljs.C_LINE_COMMENT_MODE,
189 hljs.C_BLOCK_COMMENT_MODE,
193 $pattern: '\\.?\\w+',
194 literal: 'true false',
195 keyword: '.pragma .functor .component .decl .input .output ' +
196 'ord strlen strsub range matches land lor lxor lnot bwand bwor bwxor bwnot bshl bshr bshru',
199 let STRING = hljs.QUOTE_STRING_MODE
201 className: 'number', relevance: 0, variants: [
202 { begin: /0b[01]+/ },
203 { begin: /\d+\.\d+/ }, // float
204 { begin: /\d+\.\d+.\d+.\d+/ }, // IPv4 literal
206 { begin: /0x[a-fA-F0-9]+u?/ }
212 begin: /#\s*[a-z]+\b/,
215 'meta-keyword': 'if else elif endif define undef warning error line pragma ifdef ifndef include'
218 { begin: /\\\n/, relevance: 0 },
219 hljs.inherit(STRING, { className: 'meta-string' }),
220 ].concat(COMMENT_MODES)
223 let ATOM = { begin: /[a-z][A-Za-z0-9_]*/, relevance: 0 }
225 className: 'symbol', relevance: 0, variants: [
226 { begin: /[A-Z][a-zA-Z0-9_]*/ },
227 { begin: /_[A-Za-z0-9_]*/ },
230 let PARENTED = { begin: /\(/, end: /\)/, relevance: 0 }
231 let LIST = { begin: /\[/, end: /\]/ }
232 let PRED_OP = { begin: /:-/ } // relevance booster
242 ].concat(COMMENT_MODES)
244 PARENTED.contains = INNER;
245 LIST.contains = INNER;
250 contains: INNER.concat([{ begin: /\.$/ }]) // relevance booster
253 // TODO: Add a highlighter for `ram`
254 hljs.configure({ languages: ['souffle'] })
257 if (typeof Diff2HtmlUI !== 'undefined' && typeof hljs !== 'undefined') {
258 function renderDiff(lang, id, diff) {
259 // file extension determines the language used for highlighting
260 let file = `Datalog.${lang}`
261 let prefix = `diff ${file} ${file}
266 new Diff2HtmlUI(document.getElementById(id), prefix + diff, {
270 outputFormat: 'side-by-side',
271 synchronisedScroll: true,
274 } else { // fallback to plain text
275 function renderDiff(lang, id, diff) {
276 document.getElementById(id).innerText = diff
282 <div class='headerdiv'><h1>Souffle Debug Report ()";
284 for (
const DebugReportSection& section :
sections) {
285 section.printIndex(out);
287 for (
const DebugReportSection& section :
sections) {
288 section.printContent(out);
290 out << R
"(<a href='#'>(return to top)</a>