Skip to content

Commit

Permalink
pseudocode
Browse files Browse the repository at this point in the history
  • Loading branch information
rsk0315 committed Dec 4, 2023
1 parent ecac6ef commit 6ba9ec2
Show file tree
Hide file tree
Showing 4 changed files with 335 additions and 0 deletions.
99 changes: 99 additions & 0 deletions playground/css/pseudocode.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
body {
font-family: Lato;
}
button {
font-family: Lato;
color: #5f6368;
background-color: white;
border-radius: 4px;
border: 1px solid #dadce0;
}
button:focus {
color: white;
background-color: #ffadba;
border-radius: 4px;
border: 1px solid #ffadba;
font-weight: bold;
outline: 2px solid rgba(255, 173, 186, 0.7);
}
.error {
font-family: monospace;
color: #a11
}
.frame-wrapper {
position: relative;
}
.frame-wrapper .text-label {
background-color: white;
box-shadow: 5px 0 0 white,-5px 0 0 white;
color: #5f6368;
display: inline;
font-size: 12px;
left: 12px;
margin-bottom: 0;
max-width: 300px;
padding: 0;
position: absolute;
top: 0px;
word-wrap: break-word;
}
.frame-wrapper .div-label {
background-color: white;
box-shadow: 5px 0 0 white,-5px 0 0 white;
color: #5f6368;
display: inline;
font-size: 12px;
left: 12px;
margin-bottom: 0;
max-width: 300px;
padding: 0;
position: absolute;
top: -8px;
word-wrap: break-word;
}
.frame-wrapper .text-label.focused, .frame-wrapper .div-label.focused {
color: #ffadba;
}
.frame-wrapper .textinput {
border: 1px solid #dadce0;
border-radius: 4px;
box-sizing: border-box;
color: #3c4043;
font-size: 14px;
margin: 8px 0;
}
.frame-wrapper input.textinput {
padding: 1px 8px;
height: 36px;
}
.frame-wrapper textarea.textinput {
padding: 8px;
min-height: 36px;
width: 100%;
}
.frame-wrapper div.textinput {
padding: 8px;
min-height: 30px;
}
.frame-wrapper .textinput:focus {
border: 1px solid #ffadba;
outline: 1px solid rgba(255, 173, 186, 0.7);
}

.pseudocode {
-moz-border-radius: 3px;
-moz-box-shadow: 0 2px 0 rgba(34,58,112,0.4),0 0 0 2px #fff inset;
-webkit-border-radius :3px;
-webkit-box-shadow: 0 2px 0 rgba(34,58,112,0.4),0 0 0 2px #fff inset;
background-color: #eee;
border: 1px solid #ccc;
border-radius: 5px;
box-shadow: 0 2px 0 rgba(34,58,112,0.4),0 0 0 2px #fff inset;
color: #333;
display: block;
font-family: Menlo, monospace;
line-height: 1.4;
margin: .4em .1em;
padding: .8em 1.8em;
text-shadow: 0 0px 0 #fff;
}
1 change: 1 addition & 0 deletions playground/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
- [コマンドをコピペする UI のやつ](rich-terminal.html)
- [mod 998244353 の計算機](mod_calculator/)
- [mod 1000000007 の計算機](mod_calculator/?mod=1000000007)
- [pseudocode](pseudocode.html)
208 changes: 208 additions & 0 deletions playground/js/pseudocode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
const macros = {
'\\halfopen': '[#1, #2)',
'\\floor': '\\lfloor #1\\rfloor',
'\\ceil': '\\lceil #1\\rceil',
'\\rounded': '\\lfloor #1\\rceil',
'\\Floor': '\\left\\lfloor #1\\right\\rfloor',
'\\Ceil': '\\left\\lceil #1\\right\\rceil',
'\\Rounded': '\\left\\lfloor #1\\right\\rceil',
'\\angled': '\\langle #1\\rangle',
'\\Angled': '\\left\\langle #1\\right\\rangle',
'\\lcm': '\\operatorname*{lcm}',
'\\gcd': '\\operatorname*{gcd}',
'\\poly': '\\operatorname{poly}',
'\\polylog': '\\operatorname{polylog}',
'\\concat': '\\mathrel{+\\!\\!+}',
'\\mex': '\\operatorname*{mex}',
'\\qed': '\\square',
'\\Q': '\\mathbb{Q}',
'\\dd': '\\mathrm{d}',
'\\ForallL': '{}^{\\forall}#1.\\:#2',
'\\Forall': '{}^{\\forall}#1.\\,\\left[#2\\right]',
'\\ExistsL': '{}^{\\exists}#1.\\:#2',
'\\Exists': '{}^{\\exists}#1.\\,\\left[#2\\right]',
'\\roundp': '(\\kern-.2em[#1]\\kern-.2em)',
'\\bigroundp': '\\big(\\kern-.25em\\big[#1\\big]\\kern-.25em\\big)',
'\\Bigroundp': '\\Big(\\kern-.3em\\Big[#1\\Big]\\kern-.3em\\Big)',
'\\biggroundp': '\\bigg(\\kern-.3em\\bigg[#1\\bigg]\\kern-.3em\\bigg)',
'\\Biggroundp': '\\Bigg(\\kern-.35em\\Bigg[#1\\Bigg]\\kern-.35em\\Bigg)',
'\\hfloor': '\\lfloor\\hspace{-.25em}\\lfloor#1\\rfloor\\hspace{-.25em}\\rfloor',
'\\xgets': '\\xleftarrow{#1}',
'\\eod': '\\blacksquare', // end of <details>
};
const KaTeXOptions = {
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '\\[', right: '\\]', display: true},
{left: '$', right: '$', display: false},
{left: '\\(', right: '\\)', display: false},
],
macros: macros,
};

// ---

function split(input) {
const res = [];
let inside = false;
let cur = "";
for (const line of input.split('\n')) {
if (line === "```") {
if (inside) {
res.push(cur);
cur = "";
}
inside = !inside;
} else {
if (inside) {
cur += line + "\n";
}
}
}
return res;
}

function modifyMessage(msg, e) {
return `${msg} + ${e}`
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/(.)\u0332/g, '<u>$1</u>');
}

function markup(code, elt) {
const RE = /(?:\[(?<CK>[^\]\}]+)\])|(?:\{(?<CE>.+)\})|(?<NL>\n)/g;

let out = "$\\begin{aligned}";
let indent = 0;
let blank = true;
let lineno = 0;
let opened = false;
let opening = false;
for (const match of code.matchAll(RE)) {
if (match.groups.NL) {
out += "\\\\\n";
blank = true;
if (opening) {
out += "&\\begin{aligned}";
opening = false;
opened = true;
}
continue;
}

if (blank) {
if (match.groups.CK === 'function') {
if (opened) {
out += "\\end{aligned}\\\\\n";
lineno = 0;
opened = false;
}
opening = true;
} else {
if (opened) {
out += `\\qquad{\\scriptsize ${++lineno}\\colon}`;
}
out += "&";
if (match.groups.CK && match.groups.CK.startsWith('end')) {
--indent;
}
out += "\\quad ".repeat(indent);
if (match.groups.CK && !match.groups.CK.startsWith('end')) {
if (opened && !["function", "return"].includes(match.groups.CK)) {
++indent;
}
}
}
blank = false;
} else {
out += "\\;";
}

if (match.groups.CK) {
if (match.groups.CK === "function") {
out += "&";
}
out += `\\text{\\textbf{${match.groups.CK}}}`;
} else if (match.groups.CE) {
out += ` ${match.groups.CE} `;
}
}
if (opened) {
out += "\\end{aligned}"
}
out += "\\end{aligned}$";

elt.innerHTML = out;

let err = "";
renderMathInElement(elt, {
delimiters: [
{ left: '$$', right: '$$', display: true },
{ left: '$', right: '$', display: false },
],
macros,
errorCallback: ((msg, e) => {
console.error(e);
}),
});
if (err) {
elt.innerText += 'error, see console.';
}
}

function render() {
const input = window.document.getElementById('input');
const inputText = input.value;

const codeInputs = split(inputText);
const output = window.document.getElementById('output');
output.innerHTML = "";
for (const code of codeInputs) {
const div = document.createElement("div");
const span = document.createElement("span");
span.classList.add("pseudocode");
markup(code, span);
div.appendChild(span);
output.appendChild(div);
}
}

const CACHE_KEY = 'PseudocodeInput';

function loadCache() {
const input = window.document.getElementById('input');
const cache = localStorage.getItem(CACHE_KEY)
if (cache !== null) input.value = cache;
}

function storeCache() {
const input = window.document.getElementById('input');
localStorage.setItem(CACHE_KEY, input.value);
}

window.onload = function() {
const input = window.document.getElementById('input');
input.addEventListener('input', function() {
storeCache();
});
loadCache();
render();

for (const io of ['input', 'output']) {
const ioEl = window.document.getElementById(io);
const ioLabel = window.document.getElementById(`${io}-label`);
ioEl.addEventListener('focus', function() {
ioLabel.classList.add('focused');
});
ioEl.addEventListener('focusout', function() {
ioLabel.classList.remove('focused');
});
}

{
const el = window.document.getElementById('output-label');
renderMathInElement(el);
}
input.focus();
}
27 changes: 27 additions & 0 deletions playground/pseudocode.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://rsk0315.github.io/KaTeX/dist/katex.min.css" integrity="sha384-h4/xDgXNao+EQ+xvZ0a/7QRoxZo9huqoHfvb1LFx/zbFh1aBxP9Al8yIzgcLYEsM" crossorigin="anonymous">
<script defer src="https://rsk0315.github.io/KaTeX/dist/katex.min.js" integrity="sha384-uTtSJt9XPLiqIUfRVfOITjgIvmh5bzXv8CWqNvlv0Gd5jXgLOUU0grHCGKhXhMD/" crossorigin="anonymous"></script>
<script defer src="https://rsk0315.github.io/KaTeX/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous" onload=""></script>

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">

<script src="js/pseudocode.js"></script>
<link rel="stylesheet" href="css/pseudocode.css">
</head>

<body>
<h1 id="title">Pseudocode Playground</h1>
<div class="frame-wrapper">
<label id="input-label" class="text-label" for="input">input</label>
<textarea class="textinput" id="input" rows="16" oninput="render();"></textarea>
</div>
<div class="frame-wrapper">
<label id="output-label" class="div-label">output</label>
<div id="output" class="textinput" tabindex="0"></div>
</div>
</body>
</html>

0 comments on commit 6ba9ec2

Please sign in to comment.