brushed up
This commit is contained in:
parent
a92f19180e
commit
8f8a860dbb
6 changed files with 163 additions and 129 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -5,3 +5,4 @@ node_modules
|
||||||
dist
|
dist
|
||||||
.cache
|
.cache
|
||||||
.idea/
|
.idea/
|
||||||
|
.DS_Store
|
||||||
|
|
|
||||||
17
Dockerfile
Normal file
17
Dockerfile
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
FROM node:22-alpine AS build
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
COPY --from=build /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
|
|
@ -1,14 +1,27 @@
|
||||||
html {
|
html {
|
||||||
|
color: #222;
|
||||||
background: rgb(249,235,213);
|
background: rgb(249,235,213);
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
font: 13px monospace, sans-serif;
|
||||||
|
color: black;
|
||||||
|
position: fixed;
|
||||||
|
left: 10px;
|
||||||
|
bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
#console {
|
#console {
|
||||||
font: 13px monospace, sans-serif;
|
font: 13px monospace, sans-serif;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
color: black;
|
color: #222;
|
||||||
background: rgb(255,241,219);
|
background: rgb(255,241,219);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: 1px;
|
right: 1px;
|
||||||
|
|
@ -18,6 +31,7 @@ html {
|
||||||
border: 2px solid darkgray;
|
border: 2px solid darkgray;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#help{
|
#help{
|
||||||
|
|
@ -45,7 +59,7 @@ html {
|
||||||
#log{
|
#log{
|
||||||
font: 13px monospace, sans-serif;
|
font: 13px monospace, sans-serif;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
color: black;
|
color: #222;
|
||||||
background: rgb(255,241,219);
|
background: rgb(255,241,219);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: 1px;
|
right: 1px;
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ moving_pillars(5, 10,1, false);
|
||||||
</textarea>
|
</textarea>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<a href="https://git.sanderhautvast.nl/sander/szpakowski-lang">https://git.sanderhautvast.nl/sander/szpakowski-lang</a>
|
||||||
|
|
||||||
<span id="help" style="visibility: hidden"></span>
|
<span id="help" style="visibility: hidden"></span>
|
||||||
|
|
||||||
|
|
|
||||||
253
js/app.js
253
js/app.js
|
|
@ -2,146 +2,149 @@
|
||||||
import {interpret} from "./interpreter.js";
|
import {interpret} from "./interpreter.js";
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
const command_input_element = document.getElementById('command_input');
|
const command_input_element = document.getElementById('command_input');
|
||||||
const canvas_element = document.getElementById('canvas');
|
const canvas_element = document.getElementById('canvas');
|
||||||
const canvas = canvas_element.getContext('2d');
|
const canvas = canvas_element.getContext('2d');
|
||||||
const width = window.innerWidth;
|
const width = window.innerWidth;
|
||||||
const height = window.innerHeight;
|
const height = window.innerHeight;
|
||||||
canvas.clearRect(0, 0, width, height);
|
canvas.clearRect(0, 0, width, height);
|
||||||
canvas.lineWidth = 2;
|
canvas.lineWidth = 2;
|
||||||
canvas.globalAlpha = 1;
|
canvas.globalAlpha = 1;
|
||||||
canvas.strokeStyle = 'black';
|
canvas.strokeStyle = '#000';
|
||||||
canvas.fillStyle = 'black';
|
canvas_element.width = width;
|
||||||
canvas_element.width = width;
|
canvas_element.height = height;
|
||||||
canvas_element.height = height;
|
|
||||||
|
|
||||||
const help_element = document.getElementById('help');
|
const help_element = document.getElementById('help');
|
||||||
let script;
|
let script;
|
||||||
let tx = 0;
|
let tx = 0;
|
||||||
let ty = 0;
|
let ty = 0;
|
||||||
let tangle = 0;
|
let tangle = 0;
|
||||||
|
|
||||||
document.body.onkeydown = function (event) {
|
document.body.onkeydown = function (event) {
|
||||||
if (event.key === 'Tab') {
|
if (event.key === 'Tab') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const count = function (string, substring) {
|
||||||
|
if (!substring) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
let count = 0;
|
||||||
|
let pos = string.indexOf(substring);
|
||||||
|
|
||||||
|
while (pos !== -1) {
|
||||||
|
count++;
|
||||||
|
pos = string.indexOf(substring, pos + substring.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
const count = function (string, substring) {
|
return count;
|
||||||
if (!substring) {
|
};
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
let count = 0;
|
|
||||||
let pos = string.indexOf(substring);
|
|
||||||
|
|
||||||
while (pos !== -1) {
|
const help = [
|
||||||
count++;
|
{v1: "start(x,y)", v2: "start(0,0);"},
|
||||||
pos = string.indexOf(substring, pos + substring.length);
|
{v1: "go(distance)", v2: "go(1);"},
|
||||||
|
{v1: "turn(angle)", v2: "turn(90);"},
|
||||||
|
{v1: "left(angle)", v2: "left(90);"},
|
||||||
|
{v1: "right(angle)", v2: "right(90);"},
|
||||||
|
{v1: "pillars(number, length, shift = 0, direction = UP)", v2: "pillars(3, 10, 0, DOWN);"},
|
||||||
|
{v1: "moving_pillars(number, length, shift = 1, direction = DOWN)", v2: "moving_pillars(3, 10, 1, DOWN);"},
|
||||||
|
{v1: "staircase(number, size, direction = DOWN)", v2: "staircase(3, 1, DOWN);"},
|
||||||
|
{v1: "repeat([start], end){...}", v2: "repeat(5){\n \n}"},
|
||||||
|
{v1: "random(range-start, range-end)", v2: "random(0,1);"},
|
||||||
|
{v1: "sin(alpha)", v2: "sin();"},
|
||||||
|
{v1: "cos(alpha)", v2: "cos();"},
|
||||||
|
{v1: "tan(alpha)", v2: "tan();"},
|
||||||
|
{v1: "atan(tangent)", v2: "atan();"},
|
||||||
|
];
|
||||||
|
const slices = {};
|
||||||
|
for (let i = 0; i < help.length; i++) {
|
||||||
|
for (let j = 1; j < help[i].v1.length; j++) {
|
||||||
|
const sub = help[i].v1.substring(0, j);
|
||||||
|
if (!slices[sub]) {
|
||||||
|
slices[sub] = [];
|
||||||
}
|
}
|
||||||
|
slices[sub].push(help[i]);
|
||||||
return count;
|
|
||||||
};
|
|
||||||
|
|
||||||
const help = [
|
|
||||||
{v1: "start(x,y)", v2: "start(0,0);"},
|
|
||||||
{v1: "go(distance)", v2: "go(1);"},
|
|
||||||
{v1: "turn(angle)", v2: "turn(90);"},
|
|
||||||
{v1: "left(angle)", v2: "left(90);"},
|
|
||||||
{v1: "right(angle)", v2: "right(90);"},
|
|
||||||
{v1: "pillars(number, length, shift = 0, direction = UP)", v2: "pillars(3, 10, 0, DOWN);"},
|
|
||||||
{v1: "moving_pillars(number, length, shift = 1, direction = DOWN)", v2: "moving_pillars(3, 10, 1, DOWN);"},
|
|
||||||
{v1: "staircase(number, size, direction = DOWN)", v2: "staircase(3, 1, DOWN);"},
|
|
||||||
{v1: "repeat([start], end){...}", v2: "repeat(5){\n \n}"},
|
|
||||||
{v1: "random(range-start, range-end)", v2: "random(0,1);"},
|
|
||||||
{v1: "sin(alpha)", v2: "sin();"},
|
|
||||||
{v1: "cos(alpha)", v2: "cos();"},
|
|
||||||
{v1: "tan(alpha)", v2: "tan();"},
|
|
||||||
{v1: "atan(tangent)", v2: "atan();"},
|
|
||||||
];
|
|
||||||
const slices = {};
|
|
||||||
for (let i = 0; i < help.length; i++) {
|
|
||||||
for (let j = 1; j < help[i].v1.length; j++) {
|
|
||||||
const sub = help[i].v1.substring(0, j);
|
|
||||||
if (!slices[sub]) {
|
|
||||||
slices[sub] = [];
|
|
||||||
}
|
|
||||||
slices[sub].push(help[i]);
|
|
||||||
}
|
|
||||||
slices[help[i].v1] = [help[i]];
|
|
||||||
}
|
}
|
||||||
|
slices[help[i].v1] = [help[i]];
|
||||||
|
}
|
||||||
|
|
||||||
function refresh() {
|
function refresh() {
|
||||||
script = command_input_element.value;
|
canvas.beginPath();
|
||||||
try {
|
canvas.lineWidth = 1.8;
|
||||||
canvas.clearRect(0, 0, width, height);
|
canvas.moveTo(0, 0);
|
||||||
interpret({canvas: canvas, x: tx, y: ty, angle: tangle, unit: 10, width: width, height: height}, script);
|
script = command_input_element.value;
|
||||||
} catch (e) {
|
try {
|
||||||
document.getElementById('log').innerHTML = e;
|
canvas.clearRect(0, 0, width, height);
|
||||||
}
|
interpret({canvas: canvas, x: tx, y: ty, angle: tangle, unit: 10, width: width, height: height}, script);
|
||||||
|
canvas.stroke();
|
||||||
|
} catch (e) {
|
||||||
|
document.getElementById('log').innerHTML = e;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
command_input_element.onkeyup = function handle_key_input(event) {
|
command_input_element.onkeyup = function handle_key_input(event) {
|
||||||
if (event.key === 'Tab') {
|
if (event.key === 'Tab') {
|
||||||
const script = command_input_element.value;
|
const script = command_input_element.value;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const cursor_position = command_input_element.selectionStart;
|
const cursor_position = command_input_element.selectionStart;
|
||||||
const textUpToCursor = script.slice(0, cursor_position);
|
const textUpToCursor = script.slice(0, cursor_position);
|
||||||
const startOfLine = textUpToCursor.lastIndexOf('\n') + 1;
|
const startOfLine = textUpToCursor.lastIndexOf('\n') + 1;
|
||||||
const endOfLine = script.indexOf('\n', cursor_position);
|
const endOfLine = script.indexOf('\n', cursor_position);
|
||||||
const lineEndPosition = endOfLine === -1 ? script.length : endOfLine;
|
const lineEndPosition = endOfLine === -1 ? script.length : endOfLine;
|
||||||
const currentLineText = script.slice(startOfLine, lineEndPosition).trim();
|
const currentLineText = script.slice(startOfLine, lineEndPosition).trim();
|
||||||
|
|
||||||
if (slices[currentLineText]) {
|
if (slices[currentLineText]) {
|
||||||
const helpOptions = slices[currentLineText].map(x => x.v2);
|
const helpOptions = slices[currentLineText].map(x => x.v2);
|
||||||
const firstOption = helpOptions[0];
|
const firstOption = helpOptions[0];
|
||||||
|
|
||||||
command_input_element.value = script.slice(0, startOfLine) + firstOption + script.slice(lineEndPosition);
|
|
||||||
command_input_element.setSelectionRange(startOfLine + firstOption.length, startOfLine + firstOption.length);
|
|
||||||
command_input_element.focus();
|
|
||||||
help_element.style.visibility = 'hidden';
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
|
|
||||||
script = command_input_element.value;
|
|
||||||
|
|
||||||
|
command_input_element.value = script.slice(0, startOfLine) + firstOption + script.slice(lineEndPosition);
|
||||||
|
command_input_element.setSelectionRange(startOfLine + firstOption.length, startOfLine + firstOption.length);
|
||||||
|
command_input_element.focus();
|
||||||
help_element.style.visibility = 'hidden';
|
help_element.style.visibility = 'hidden';
|
||||||
const cursor_position = command_input_element.selectionStart;
|
|
||||||
const textUpToCursor = script.slice(0, cursor_position);
|
|
||||||
const startOfLine = textUpToCursor.lastIndexOf('\n') + 1;
|
|
||||||
|
|
||||||
const endOfLine = script.indexOf('\n', cursor_position);
|
|
||||||
const lineEndPosition = endOfLine === -1 ? script.length : endOfLine;
|
|
||||||
|
|
||||||
const currentLineText = script.slice(startOfLine, lineEndPosition);
|
|
||||||
if (currentLineText.length > 0) {
|
|
||||||
const command = currentLineText.trim();
|
|
||||||
if (slices[command]) {
|
|
||||||
const help = slices[command].map(x => x.v1);
|
|
||||||
let help_text = "";
|
|
||||||
for (let x = 0; x < help.length; x++) {
|
|
||||||
help_text += `<div id="l-${x}">${help[x]}</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const computedStyle = window.getComputedStyle(command_input_element);
|
|
||||||
const fontSize = parseFloat(computedStyle.fontSize);
|
|
||||||
const lineHeight = computedStyle.lineHeight === 'normal' ? fontSize * 1.2 : parseFloat(computedStyle.lineHeight);
|
|
||||||
|
|
||||||
const textBounding = command_input_element.getBoundingClientRect();
|
|
||||||
const topPosition = textBounding.top + window.scrollY + (count(script, '\n') + 4) * lineHeight;
|
|
||||||
|
|
||||||
help_element.style.visibility = 'visible';
|
|
||||||
help_element.style.left = `${textBounding.left + window.scrollX}px`;
|
|
||||||
help_element.style.top = `${topPosition - help_element.offsetHeight}px`;
|
|
||||||
help_element.innerHTML = help_text;
|
|
||||||
help_element.style.display = 'block';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//main
|
if (!['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
|
||||||
refresh();
|
script = command_input_element.value;
|
||||||
})
|
|
||||||
|
help_element.style.visibility = 'hidden';
|
||||||
|
const cursor_position = command_input_element.selectionStart;
|
||||||
|
const textUpToCursor = script.slice(0, cursor_position);
|
||||||
|
const startOfLine = textUpToCursor.lastIndexOf('\n') + 1;
|
||||||
|
|
||||||
|
const endOfLine = script.indexOf('\n', cursor_position);
|
||||||
|
const lineEndPosition = endOfLine === -1 ? script.length : endOfLine;
|
||||||
|
|
||||||
|
const currentLineText = script.slice(startOfLine, lineEndPosition);
|
||||||
|
if (currentLineText.length > 0) {
|
||||||
|
const command = currentLineText.trim();
|
||||||
|
if (slices[command]) {
|
||||||
|
const help = slices[command].map(x => x.v1);
|
||||||
|
let help_text = "";
|
||||||
|
for (let x = 0; x < help.length; x++) {
|
||||||
|
help_text += `<div id="l-${x}">${help[x]}</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const computedStyle = window.getComputedStyle(command_input_element);
|
||||||
|
const fontSize = parseFloat(computedStyle.fontSize);
|
||||||
|
const lineHeight = computedStyle.lineHeight === 'normal' ? fontSize * 1.2 : parseFloat(computedStyle.lineHeight);
|
||||||
|
|
||||||
|
const textBounding = command_input_element.getBoundingClientRect();
|
||||||
|
const topPosition = textBounding.top + window.scrollY + (count(script, '\n') + 4) * lineHeight;
|
||||||
|
|
||||||
|
help_element.style.visibility = 'visible';
|
||||||
|
help_element.style.left = `${textBounding.left + window.scrollX}px`;
|
||||||
|
help_element.style.top = `${topPosition - help_element.offsetHeight}px`;
|
||||||
|
help_element.innerHTML = help_text;
|
||||||
|
help_element.style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//main
|
||||||
|
refresh();
|
||||||
|
})
|
||||||
();
|
();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,6 @@ export function interpret(init_env, code) {
|
||||||
tx = x * unit;
|
tx = x * unit;
|
||||||
ty = y * unit;
|
ty = y * unit;
|
||||||
tangle = 0;
|
tangle = 0;
|
||||||
canvas.beginPath();
|
|
||||||
canvas.moveTo(x0 + tx, y0 + ty);
|
canvas.moveTo(x0 + tx, y0 + ty);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -141,7 +140,6 @@ export function interpret(init_env, code) {
|
||||||
tx += distance * unit * Math.cos(tangle);
|
tx += distance * unit * Math.cos(tangle);
|
||||||
ty += distance * unit * Math.sin(tangle);
|
ty += distance * unit * Math.sin(tangle);
|
||||||
canvas.lineTo(x0 + tx, y0 + ty);
|
canvas.lineTo(x0 + tx, y0 + ty);
|
||||||
canvas.stroke();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
turn: (degrees) => {
|
turn: (degrees) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue