From 9818fc661d8483b48a0d6932b76b15e0f64c2837 Mon Sep 17 00:00:00 2001 From: Melvin-Abraham Date: Tue, 20 Nov 2018 18:31:04 +0530 Subject: [PATCH] Adding Syntax Highlighting Support --- sketch.js | 91 +++++++++++++++++++++++++++++++++++++++++-------------- style.css | 7 +++-- 2 files changed, 73 insertions(+), 25 deletions(-) diff --git a/sketch.js b/sketch.js index 01297fd..6e35cf9 100644 --- a/sketch.js +++ b/sketch.js @@ -1,6 +1,10 @@ // Coding Challenge 121: Logo // https://youtu.be/i-k04yzfMpw +// @TODO: Performance: +// Prevent Syntax Highlighting again and again when resizing... +// REFER `goTurtle()` + let canvas; let editor; let editor_bg; @@ -21,13 +25,53 @@ let canvasScrollY = 0; let canvasScaleX = 1; let canvasScaleY = 1; let drawingBounds = new BoundingBox(); + +let primary_keywords = ['fd', 'bd', 'rt', 'lt']; +let secondary_keywords = ['color', 'colorrgb', 'pensize', 'repeat', 'pu', 'pd']; + +function syntaxHighlight(code) { + let tokens = code.split(/(\[\s*\d+\s+\d+\s+\d+\s*\])|(\[)|(\])|(\s+)/).filter(x => (x !== undefined && x != '')); + let newHTML = ''; + + for (i of tokens) { + if (primary_keywords.includes(i)) { // #f48771 + newHTML += `${i}`; + } + + else if (secondary_keywords.includes(i)) { + newHTML += `${i}`; + } + + else if (['[', ']'].includes(i)) { + newHTML += `${i}`; + } + + else if (/#[a-zA-z0-9]/.test(i) || /\[\s*\d+\s+\d+\s+\d+\s*\]/.test(i)) { + newHTML += `${i}`; + } + + else if (parseInt(i) !== NaN) { + newHTML += `${i}`; + } + + else { + newHTML += `${i}`; + } + } + + return newHTML; +} + function showError(start,end) { let text = editor.value(); + start = (start > 0) ? start + 1 : start; + end = (start < text.length) ? end - 1 : end; + let beforeErr= text.substring(0,start); let afterErr = text.substring(end); let err = text.substring(start,end); - let bg_text = `${beforeErr}${err}${afterErr}`; + let bg_text = `${syntaxHighlight(beforeErr)}${err}${syntaxHighlight(afterErr)}`; editor_bg.html(bg_text); } @@ -57,20 +101,20 @@ function setup() { const canvasSize = getCanvasSize(); canvas = createCanvas(canvasSize.width, canvasSize.height); div = document.querySelector("#logo-canvas"); - + div.appendChild(canvas.elt); - + // Use a setTimeout with length 0 to call windowResized immediately after the DOM has updated (since we are dynamically injecting a canvas element) setTimeout(windowResized, 0); angleMode(DEGREES); background(bgcolor); - + canvas.mousePressed(function () { dragStartMousePos = new p5.Vector(mouseX, mouseY); dragStartCanvasOffset = new p5.Vector(canvasScrollX, canvasScrollY); }); - + canvas.mouseMoved(function () { if (mouseIsPressed) { canvasScrollX = dragStartCanvasOffset.x + dragStartMousePos.x - mouseX; @@ -78,34 +122,34 @@ function setup() { goTurtle(); } }); - + recentreBtn = document.querySelector("#recentre"); bgcolorBtn = document.querySelector("#bgcolor"); - + recentreBtn.onclick = function () { scaleToFitBoundingBox(drawingBounds); } - + bgcolorBtn.onclick = function () { let r = floor(random(0, 255)); let g = floor(random(0, 255)); let b = floor(random(0, 255)); - + let hexR = `${r <= 15 ? '0' : ''}${r.toString(16)}`; let hexG = `${g <= 15 ? '0' : ''}${g.toString(16)}`; let hexB = `${b <= 15 ? '0' : ''}${b.toString(16)}`; - + let col = `#${hexR}${hexG}${hexB}`; bgcolor = col; goTurtle(); } - + editor = select("#code"); setDefaultDrawing(); editor.input(goTurtle); editor_bg = select("#code_bg"); scaleToFitBoundingBox(drawingBounds); // This also redraws (it has to in order to measure the size of the drawing) - + editor.elt.addEventListener('scroll', ev => { select('#code_bg').elt.scrollTop = editor.elt.scrollTop; }, { passive: true }); // The 'passive: true' parameter increases performance when scrolling by making it impossible to cancel the scroll events @@ -131,16 +175,17 @@ function afterCommandExecuted() { } function goTurtle() { - editor_bg.html( editor.value()); + editor_bg.html(syntaxHighlight(editor.value())); + turtle = new Turtle(0, 0, 0); drawingBounds.reset(); drawingBounds.move(turtle.x, turtle.y); background(bgcolor); - + push(); translate(-canvasScrollX, -canvasScrollY); scale(canvasScaleX, canvasScaleY); - + push(); turtle.reset(); let code = editor.value(); @@ -153,7 +198,7 @@ function goTurtle() { } catch (err) { showError(err.startIndex,err.endIndex); } - + pop(); pop(); @@ -170,13 +215,13 @@ function setDefaultDrawing() { function createTestDataView(cases) { let selector = select("#testdata"); - + selector.option("Logo Default", -1); - + for (i = 0; i < cases.length; i++) { selector.option(cases[i].name, i); } - + // because why not do it here selector.changed(function () { let val = parseInt(selector.value()); @@ -187,19 +232,19 @@ function createTestDataView(cases) { // Use a drawing from tests.json editor.value(cases[val].code); } - + // Reset default parameters for turtle turtle.strokeColor = 255; turtle.dir = 0; turtle.x = 0; turtle.y = 0; - + // Reset default parameters for camera canvasScrollX = 0; canvasScrollY = 0; canvasScaleX = 1; canvasScaleY = 1; - + // Move and scale the drawing to fit on-screen scaleToFitBoundingBox(drawingBounds); @@ -230,7 +275,7 @@ function resizeHandleMouseDown(ev) { function windowMouseMove(ev) { if (resizingEditor) - updateEditorSize(ev.clientY); + updateEditorSize(ev.clientY); } function windowMouseUp() { diff --git a/style.css b/style.css index 427d7aa..fafa0f1 100644 --- a/style.css +++ b/style.css @@ -138,12 +138,15 @@ a { } mark { - color: transparent; - background-color: red; + color: #ffffff; + background-color: rgba(255, 0, 0, .6); + border-radius: 5px; } textarea#code { resize: none; + color: transparent; + caret-color: #528bff; /* Browser Compatibility Warning */ } #code:focus {