436 lines
20 KiB
Markdown
436 lines
20 KiB
Markdown
+++
|
|
title = 'New Tool Page Generator'
|
|
subtitle = "Creates nicely formatted markdown for a new tool, so you don't have to"
|
|
date = 2025-08-21
|
|
+++
|
|
|
|
This page is useful to generate copy-and-paste source code in Markdown for a new tool.
|
|
**Publications:** Coming soon.
|
|
|
|
Reset the form with **Double Click** on reset button for safety.
|
|
|
|
{{<rawhtml>}}
|
|
|
|
|
|
<script>
|
|
function arr(str) {
|
|
return str.split(',').map(s => s.trim()).filter(Boolean);
|
|
}
|
|
function bool(val) {
|
|
return val ? 'false' : 'true';
|
|
}
|
|
function generateMarkdown() {
|
|
const title = document.getElementById('title').value;
|
|
const subtitle = document.getElementById('subtitle').value;
|
|
const date = new Date().toISOString().slice(0, 10);
|
|
|
|
const homepage = arr(document.getElementById('homepage').value);
|
|
const sourcecode = arr(document.getElementById('sourcecode').value);
|
|
const playground = arr(document.getElementById('playground').value);
|
|
|
|
const applications = arr(document.getElementById('applications').value);
|
|
const developers = arr(document.getElementById('developers').value);
|
|
const licenses = arr(document.getElementById('licenses').value);
|
|
const inputs = arr(document.getElementById('inputs').value);
|
|
const interfaces = arr(document.getElementById('interfaces').value);
|
|
const updatedYear = parseInt(document.getElementById('updated-year').value, 10);
|
|
const currentYear = new Date().getFullYear();
|
|
let maintenance = "Actively Maintained";
|
|
let maintenance_year = "";
|
|
let description = document.getElementById('description').value;
|
|
if (updatedYear && currentYear - updatedYear > 5) {
|
|
maintenance = "Not Maintained";
|
|
maintenance_year = `updated_year = ${updatedYear}\n`;
|
|
description = `\{\{<inactive year="${updatedYear}">\}\}\n\n` + description
|
|
}
|
|
let md = `+++
|
|
title = '${title}'
|
|
subtitle = '${subtitle}'
|
|
links = [${homepage.length ? `\n\t{ title = "Homepage", url = "${homepage}", icon = 'fa-solid fa-home' },\n` : ''}${sourcecode.length ? `\t{ title = "Source Code", url = "${sourcecode}", icon = 'fa-solid fa-code' },\n` : ''}${playground.length ? `\t{ title = "Playground", url = "${playground}", icon = 'fa-solid fa-gamepad' }\n` : ''}]
|
|
applications = ${JSON.stringify(applications)}
|
|
developers = ${JSON.stringify(developers)}
|
|
licenses = ${JSON.stringify(licenses)}
|
|
inputs = ${JSON.stringify(inputs)}
|
|
interfaces = ${JSON.stringify(interfaces)}
|
|
maintenance = [${JSON.stringify(maintenance)}]
|
|
${maintenance_year}draft = false
|
|
date = ${date}
|
|
+++\n\n`;
|
|
|
|
md += description;
|
|
document.getElementById('output').textContent = md;
|
|
}
|
|
</script>
|
|
|
|
<table style="width: 100%">
|
|
<style>
|
|
input[type="text"],
|
|
input[type="url"],
|
|
input[type="date"],
|
|
textarea {
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
}
|
|
input,textarea {
|
|
margin: 0.2rem 0.2rem;
|
|
font-weight: 500;
|
|
}
|
|
table {
|
|
border-collapse: collapse;
|
|
width: 100%;
|
|
background: #eee;
|
|
color: #000;
|
|
border-radius: 0.5rem;
|
|
}
|
|
th, td {
|
|
padding: 8px;
|
|
text-align: left;
|
|
}
|
|
tr:nth-child(even) {
|
|
background: #ccc;
|
|
}
|
|
label {
|
|
color: #000;
|
|
font-weight: 600;
|
|
margin-right: 0.5rem;
|
|
}
|
|
input, textarea, select {
|
|
background: #fff;
|
|
color: #000;
|
|
border: 2px solid #888;
|
|
padding: 4px;
|
|
padding: 0.2rem 1rem;
|
|
font-size: 0.9rem;
|
|
}
|
|
button {
|
|
background: #000;
|
|
color: #ccc;
|
|
border: 2px solid white;
|
|
padding: 8px 38px;
|
|
font-size: 1rem;
|
|
font-weight: bold;
|
|
cursor: pointer;
|
|
}
|
|
button:hover {
|
|
background: #444;
|
|
}
|
|
</style>
|
|
<tr>
|
|
<td><label for="title">Title:</label></td>
|
|
<td><input type="text" id="title" required></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="subtitle">Subtitle:</label></td>
|
|
<td><input type="text" id="subtitle"></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="description">Description:</label></td>
|
|
<td><textarea id="description" rows="3" cols="50"></textarea></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="homepage">Homepage URL:</label></td>
|
|
<td><input type="url" id="homepage" placeholder="https://example.com"></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="sourcecode">Source Code URL:</label></td>
|
|
<td><input type="url" id="sourcecode" placeholder="https://github.com/example"></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="playground">Playground URL:</label></td>
|
|
<td><input type="url" id="playground" placeholder="https://play.example.com"></td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="applications">Applications:</label></td>
|
|
<td>
|
|
<div id="applications-checkboxes">
|
|
<label><input type="checkbox" value="Theorem Prover">Theorem Prover</label>
|
|
<label><input type="checkbox" value="SMT Solver">SMT Solver</label>
|
|
<label><input type="checkbox" value="SAT Solver">SAT Solver</label>
|
|
<label><input type="checkbox" value="SAT Solver">Constraint Solver</label>
|
|
<br>
|
|
<label><input type="checkbox" value="Model Checker">Model Checker</label>
|
|
<label><input type="checkbox" value="Runtime Verifier">Runtime Verifier</label>
|
|
<label><input type="checkbox" value="Proof Assistant">Proof Assistant</label>
|
|
<label><input type="checkbox" value="Program Prover">Program Prover</label>
|
|
<label><input type="checkbox" value="Protocol Verifier">Protocol Verifier</label>
|
|
<br>
|
|
<label><input type="checkbox" value="Static Analyzer">Static Analyzer</label>
|
|
<label><input type="checkbox" value="Type Checker">Type Checker</label>
|
|
<label><input type="checkbox" value="Code Synthesizer">Code Synthesizer</label>
|
|
<label><input type="checkbox" value="Parameter Synthesizer">Parameter Synthesizer</label>
|
|
<br>
|
|
<label><input type="checkbox" value="Test Generator">Test Generator</label>
|
|
<label><input type="checkbox" value="Model Simulator">Model Simulator</label>
|
|
<label><input type="checkbox" value="Counterexample Generator">Counterexample Generator</label>
|
|
<br>
|
|
<label><input type="checkbox" value="Specification Language">Specification Language</label>
|
|
<label><input type="checkbox" value="Refinement Tool">Refinement Tool</label>
|
|
<label><input type="checkbox" value="Visualizer">Visualizer</label>
|
|
<br>
|
|
<label><input type="checkbox" value="Probabilistic Program Prover">Probabilistic Program Prover</label>
|
|
<label><input type="checkbox" value="Probabilistic Model Checker">Probabilistic Model Checker</label>
|
|
<label><input type="checkbox" value="Stochastic Simulator">Stochastic Simulator</label>
|
|
<br>
|
|
<!-- <label for="other-applications">Other:</label> -->
|
|
<input type="text" id="other-applications" placeholder="Other application">
|
|
<script>
|
|
document.getElementById('other-applications').addEventListener('input', updateApplications);
|
|
Array.from(document.querySelectorAll('#applications-checkboxes input[type="checkbox"]')).forEach(cb => {
|
|
cb.addEventListener('change', updateApplications);
|
|
});
|
|
function updateApplications() {
|
|
const otherValue = document.getElementById('other-applications').value.trim();
|
|
const checkboxes = Array.from(document.querySelectorAll('#applications-checkboxes input[type="checkbox"]:checked')).map(cb => cb.value);
|
|
const applications = otherValue ? [...checkboxes, otherValue] : checkboxes;
|
|
document.getElementById('applications').value = applications.join(', ');
|
|
}
|
|
</script> </script>
|
|
<input type="hidden" id="applications">
|
|
</div>
|
|
</td>
|
|
<script>
|
|
function getCheckedApplications() {
|
|
return Array.from(document.querySelectorAll('#applications-checkboxes input[type="checkbox"]:checked'))
|
|
.map(cb => cb.value);
|
|
}
|
|
</script>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="developers">Developers:</label></td>
|
|
<td>
|
|
<input type="text" id="developers" placeholder="Devs separated by commas, e.g. Alice, Bob, Carol">
|
|
</td>
|
|
</tr>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="licenses">License:</label></td>
|
|
<td>
|
|
<select id="licenses">
|
|
<optgroup label="Copyleft (GPL)">
|
|
<option value="GPL-1.0">GPL-1.0</option>
|
|
<option value="GPL-2.0">GPL-2.0</option>
|
|
<option value="GPL-3.0">GPL-3.0</option>
|
|
<option value="AGPL-3.0">AGPL-3.0</option>
|
|
</optgroup>
|
|
<optgroup label="Copyleft (LGPL)">
|
|
<option value="LGPL-2.1">LGPL-2.1</option>
|
|
<option value="LGPL-3.0">LGPL-3.0</option>
|
|
</optgroup>
|
|
<optgroup label="Copyleft (Other)">
|
|
<option value="EPL-2.0">EPL-2.0</option>
|
|
<option value="CDDL-1.0">CDDL-1.0</option>
|
|
<option value="OSL-3.0">OSL-3.0</option>
|
|
<option value="CECILL-2.1">CECILL-2.1</option>
|
|
<option value="Artistic-2.0">Artistic-2.0</option>
|
|
<option value="IPL-1.0">IPL-1.0</option>
|
|
<option value="OCamlPro Non-Commercial">OCamlPro Non-Commercial</option>
|
|
</optgroup>
|
|
<optgroup label="Permissive">
|
|
<option value="MIT">MIT</option>
|
|
<option value="Apache-1.1">Apache-1.1</option>
|
|
<option value="Apache-2.0">Apache-2.0</option>
|
|
<option value="BSD-2-Clause">BSD-2-Clause</option>
|
|
<option value="BSD-3-Clause">BSD-3-Clause</option>
|
|
<option value="ISC">ISC</option>
|
|
<option value="MPL-2.0">MPL-2.0</option>
|
|
<option value="Zlib">Zlib</option>
|
|
<option value="Unlicense">Unlicense</option>
|
|
<option value="CC0-1.0">CC0-1.0</option>
|
|
</optgroup>
|
|
<optgroup label="Proprietary / Other">
|
|
<option value="All Rights Reserved">All Rights Reserved</option>
|
|
</optgroup>
|
|
<option value="">Select a license</option> document.getElementById('licenses').addEventListener('change', function() {
|
|
document.getElementById('licenses-hidden').value = this.value;
|
|
});
|
|
</script>
|
|
<input type="hidden" id="licenses-hidden">
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="inputs">Inputs:</label></td>
|
|
<td>
|
|
<div id="inputs-checkboxes">
|
|
<!-- SAT/SMT/Model Checking formats -->
|
|
<label><input type="checkbox" value="SMT-LIB">SMT-LIB</label>
|
|
<label><input type="checkbox" value="DIMACS CNF">DIMACS CNF</label>
|
|
<label><input type="checkbox" value="AIGER">AIGER</label>
|
|
<label><input type="checkbox" value="TPTP">TPTP</label>
|
|
<label><input type="checkbox" value="SyGuS">SyGuS</label>
|
|
<label><input type="checkbox" value="WhyML">WhyML</label>
|
|
<br>
|
|
<!-- Model Checking languages -->
|
|
<label><input type="checkbox" value="Promela">Promela</label>
|
|
<label><input type="checkbox" value="NuSMV">NuSMV</label>
|
|
<label><input type="checkbox" value="LTL">LTL</label>
|
|
<label><input type="checkbox" value="CTL">CTL</label>
|
|
<br>
|
|
<!-- Hardware description languages -->
|
|
<label><input type="checkbox" value="Verilog">Verilog</label>
|
|
<label><input type="checkbox" value="VHDL">VHDL</label>
|
|
<br>
|
|
<!-- Formal specification languages -->
|
|
<label><input type="checkbox" value="B">B</label>
|
|
<label><input type="checkbox" value="Z">Z</label>
|
|
<label><input type="checkbox" value="Alloy">Alloy</label>
|
|
<label><input type="checkbox" value="TLA+">TLA+</label>
|
|
<br>
|
|
<!-- Proof assistant formats -->
|
|
<label><input type="checkbox" value="Coq">Coq</label>
|
|
<label><input type="checkbox" value="Isabelle/HOL">Isabelle/HOL</label>
|
|
<label><input type="checkbox" value="HOL Light">HOL Light</label>
|
|
<label><input type="checkbox" value="ACL2">ACL2</label>
|
|
<label><input type="checkbox" value="PVS">PVS</label>
|
|
<br>
|
|
<!-- Rewriting and algebraic specification -->
|
|
<label><input type="checkbox" value="Maude">Maude</label>
|
|
<label><input type="checkbox" value="CASL">CASL</label>
|
|
<br>
|
|
<!-- Simulation/visualization formats -->
|
|
<label><input type="checkbox" value="SPIN">SPIN</label>
|
|
<label><input type="checkbox" value="DOT">DOT (Graphviz)</label>
|
|
<br>
|
|
<!-- Data formats -->
|
|
<label><input type="checkbox" value="JSON">JSON</label>
|
|
<label><input type="checkbox" value="XML">XML</label>
|
|
<label><input type="checkbox" value="CSV">CSV</label>
|
|
<br>
|
|
<input type="text" id="other-inputs" placeholder="Other input format(s), separated by commas">
|
|
<script>
|
|
document.getElementById('other-inputs').addEventListener('input', function() {
|
|
const otherValues = this.value.split(',').map(s => s.trim()).filter(Boolean);
|
|
const checkboxes = Array.from(document.querySelectorAll('#inputs-checkboxes input[type="checkbox"]:checked'))
|
|
.map(cb => cb.value);
|
|
const inputs = otherValues.length ? [...checkboxes, ...otherValues] : checkboxes;
|
|
document.getElementById('inputs').value = inputs.join(', ');
|
|
});
|
|
</script> <script>
|
|
document.getElementById('other-inputs').addEventListener('input', function() {
|
|
const otherValue = this.value.trim();
|
|
const checkboxes = Array.from(document.querySelectorAll('#inputs-checkboxes input[type="checkbox"]:checked'))
|
|
.map(cb => cb.value);
|
|
const inputs = otherValue ? [...checkboxes, otherValue] : checkboxes;
|
|
document.getElementById('inputs').value = inputs.join(', ');
|
|
});
|
|
</script>
|
|
<input type="hidden" id="inputs">
|
|
</div>
|
|
</td>
|
|
<script>
|
|
function getCheckedInputs() {
|
|
return Array.from(document.querySelectorAll('#inputs-checkboxes input[type="checkbox"]:checked'))
|
|
.map(cb => cb.value);
|
|
}
|
|
</script>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="interfaces">Interfaces:</label></td>
|
|
<td>
|
|
<div id="interfaces-checkboxes">
|
|
<!-- Web interfaces -->
|
|
<label><input type="checkbox" value="Web">Web</label>
|
|
<label><input type="checkbox" value="REST">REST</label>
|
|
<label><input type="checkbox" value="gRPC">gRPC</label>
|
|
<label><input type="checkbox" value="API">API</label>
|
|
<br>
|
|
<!-- Desktop interfaces -->
|
|
<label><input type="checkbox" value="CLI">CLI (Command Line)</label>
|
|
<label><input type="checkbox" value="GUI">GUI (Graphical)</label>
|
|
<label><input type="checkbox" value="REPL">REPL</label>
|
|
<br>
|
|
<!-- Integration interfaces -->
|
|
<label><input type="checkbox" value="Toolset Integration">Toolset Integration</label>
|
|
<label><input type="checkbox" value="Library">Library</label>
|
|
<label><input type="checkbox" value="Plugin">Plugin</label>
|
|
<label><input type="checkbox" value="IDE Integration">IDE Integration</label>
|
|
<br>
|
|
<!-- Other interfaces -->
|
|
<!-- <label for="other-interfaces">Other:</label> -->
|
|
<input type="text" id="other-interfaces" placeholder="Other interface(s), separated by commas">
|
|
<script>
|
|
document.getElementById('other-interfaces').addEventListener('input', updateInterfaces);
|
|
Array.from(document.querySelectorAll('#interfaces-checkboxes input[type="checkbox"]')).forEach(cb => {
|
|
cb.addEventListener('change', updateInterfaces);
|
|
});
|
|
function updateInterfaces() {
|
|
const otherValues = document.getElementById('other-interfaces').value.split(',').map(s => s.trim()).filter(Boolean);
|
|
const checkboxes = Array.from(document.querySelectorAll('#interfaces-checkboxes input[type="checkbox"]:checked')).map(cb => cb.value);
|
|
const interfaces = otherValues.length ? [...checkboxes, ...otherValues] : checkboxes;
|
|
document.getElementById('interfaces').value = interfaces.join(', ');
|
|
} </script>
|
|
<input type="hidden" id="interfaces"> </div>
|
|
</td>
|
|
<script>
|
|
function getCheckedInterfaces() {
|
|
return Array.from(document.querySelectorAll('#interfaces-checkboxes input[type="checkbox"]:checked'))
|
|
.map(cb => cb.value);
|
|
}
|
|
</script>
|
|
</tr>
|
|
<tr>
|
|
<td><label for="updated-year">Last Updated:</label></td>
|
|
<td>
|
|
<input type="number" id="updated-year" min="1900" max="2099" style="width:6em;">
|
|
<script>
|
|
document.getElementById('updated-year').addEventListener('input', function() {
|
|
const year = parseInt(this.value, 10);
|
|
const currentYear = new Date().getFullYear();
|
|
let status = "Actively Maintained";
|
|
if (currentYear - year > 5) {
|
|
status = "Not Maintained";
|
|
}
|
|
});
|
|
// Update hidden input when radio changes
|
|
Array.from(document.getElementsByName('maintenance')).forEach(radio => {
|
|
radio.addEventListener('change', function() {
|
|
document.getElementById('maintenance').value = this.value;
|
|
});
|
|
});
|
|
</script>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="2" style="text-align:center;">
|
|
<button type="button" onclick="generateMarkdown()">Generate Markdown</button>
|
|
<button type="button" ondblclick="resetForm()" onclick="this.style.background='rgba(255, 0, 0, 0.85)';" style="background: rgba(85, 6, 6, 1)">Reset Form</button>
|
|
<script>
|
|
function resetForm() {
|
|
document.getElementById('title').value = '';
|
|
document.getElementById('subtitle').value = '';
|
|
document.getElementById('homepage').value = '';
|
|
document.getElementById('sourcecode').value = '';
|
|
document.getElementById('playground').value = '';
|
|
document.getElementById('developers').value = '';
|
|
document.getElementById('licenses').value = '';
|
|
document.getElementById('licenses-hidden').value = '';
|
|
document.getElementById('inputs').value = '';
|
|
document.getElementById('interfaces').value = '';
|
|
document.getElementById('updated-year').value = '';
|
|
document.getElementById('description').value = '';
|
|
document.getElementById('other-applications').value = '';
|
|
document.getElementById('other-inputs').value = '';
|
|
// Uncheck all checkboxes
|
|
Array.from(document.querySelectorAll('input[type="checkbox"]')).forEach(cb => cb.checked = false);
|
|
// Clear output
|
|
document.getElementById('output').textContent = '';
|
|
}
|
|
// Accept "Enter" to trigger Generate Markdown in any field
|
|
Array.from(document.querySelectorAll('input,select,number')).forEach(el => {
|
|
el.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Enter') {
|
|
e.preventDefault();
|
|
generateMarkdown();
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<h3>Output Markdown:</h3>
|
|
<button type="button" onclick="navigator.clipboard.writeText(document.getElementById('output').textContent)">Copy to Clipboard</button>
|
|
<pre id="output" style="background:#000; padding:1em; border:1px solid #ccc;"></pre>
|
|
|
|
{{</rawhtml>}}
|