Skip to content

Commit

Permalink
Add initial version of Numbat editor interface
Browse files Browse the repository at this point in the history
  • Loading branch information
sharkdp authored and David Peter committed Aug 22, 2024
1 parent 6bbc73e commit 6dade59
Show file tree
Hide file tree
Showing 3 changed files with 306 additions and 0 deletions.
115 changes: 115 additions & 0 deletions numbat-wasm/www/editor.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
@import url('https://fonts.googleapis.com/css2?family=Fira+Mono:wght@400;700&family=Lustria&family=Lato:wght@700&display=swap');

body,
html {
margin: 0;
padding: 0;
height: 100%;
font-size: 30px;
}

.split {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
}

.gutter {
background-color: #eee;
background-repeat: no-repeat;
background-position: 50%;
}

.gutter.gutter-horizontal {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==');
cursor: col-resize;
}

#editor {
font-family: 'Fira Mono', monospace;
font-size: 1em;
}


.type-expr {
font-family: 'Fira Mono', monospace;
font-size: 1em;
margin-top: 0em;
margin-bottom: 0;
padding: 1em;
overflow: auto;
display: block;
}

#results {
font-family: 'Fira Mono', monospace;
font-size: 1em;
padding: 0.1em;
background-color: #f6f8f6;
overflow: auto;
}

.numbat-type-identifier {
color: #ca3b63;
}

.ace_type {
color: #ca3b63 !important;
}

.numbat-value {
color: #0040ff;
}

.ace_numeric {
color: #0040ff !important;
}

.numbat-keyword {
color: #c802ff !important;
}

.ace_keyword {
color: #c802ff !important;
}

.ace_comment {
color: #8c8c8c !important;
}

.ace_string {
color: #27a85f !important;
}

.ace_decorator {
color: #27a85f !important;
}

.numbat-string {
color: #27a85f;
}

.ace_operator {
color: #db2828 !important;
}

.numbat-unit {
color: #5c12a6;
}

.numbat-dimmed {
color: #888;
}

.numbat-diagnostic-red {
color: #cc3b0a;
}

.numbat-diagnostic-blue {
color: #0040ff;
}

.numbat-diagnostic-bold {
font-weight: bold;
}
31 changes: 31 additions & 0 deletions numbat-wasm/www/editor.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Numbat</title>
<link rel="stylesheet" href="editor.css">
</head>
<body>
<div class="split">
<div id="editor">8 km / (1 h + 25 min)

atan2(30 cm, 1 m) -> deg

let ω = 2π c / 660 nm
ℏ ω -> eV


fn braking_distance(v) = v t_reaction + v² / 2 µ g0
where t_reaction = 1 s # driver reaction time
and µ = 0.7 # coefficient of friction

braking_distance(50 km/h) -> m</div>
<div id="results"></div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/split.js/1.6.0/split.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.9.6/ace.js"></script>
<script type="module" src="editor.js"></script>
</body>
</html>
160 changes: 160 additions & 0 deletions numbat-wasm/www/editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import init, {
setup_panic_hook,
Numbat,
FormatType,
} from "./pkg/numbat_wasm.js";

async function main() {
await init();

setup_panic_hook();

initializeEditor();
initializeSplit();
}

main();

function interpret(input) {
var numbat = Numbat.new(true, false, FormatType.Html);

let parts = input.split("\n\n");

let results = parts.map((part) => {
let res = part.match(/\n/g);
let num_newlines = res ? res.length : 0;

let brs = "<br>".repeat(num_newlines);

return brs + numbat.interpret(part).output;
});

return results.join("<br><br>");
}

ace.config.set("basePath", "https://cdnjs.cloudflare.com/ajax/libs/ace/1.9.6/");

ace.define(
"ace/mode/numbat_highlight_rules",
function (require, exports, module) {
var oop = require("ace/lib/oop");
var TextHighlightRules =
require("ace/mode/text_highlight_rules").TextHighlightRules;

var NumbatHighlightRules = function () {
this.$rules = {
start: [
{
token: "comment",
regex: "#.*$",
},
{
token: "keyword",
regex:
"\\b(?:per|to|let|fn|where|and|dimension|unit|use|long|short|both|none|print|assert|assert_eq|type|if|then|else|true|false)\\b",
},
{
token: "constant.numeric",
regex:
"\\b(?:[0-9]+(?:[._][0-9]+)*" +
"|0x[0-9A-Fa-f]+|0o[0-7]+|0b[01]+(?:_[01]+)*" +
"|\\.[0-9]+(?:[eE][-+]?[0-9]+)?" +
"|[0-9]+[eE][-+]?[0-9]+)\\b",
},
// {
// token: "variable",
// regex: "\\b[a-z\u00B0\u0394\u03C0\u00B5][A-Za-z0-9_\u00B0\u0394\u03C0\u00B5]*\\b"
// },
{
token: "support.type",
regex: "\\b[A-Z][A-Za-z]*\\b",
},
{
token: "string",
regex: '"[^"]*"',
},
{
token: "keyword.operator",
regex: "\\+|-|\\*|/|\\^|➞|→|:|÷|×|≤|≥|≠|<|>|²|³|\\(|\\)",
},
{
token: "meta.decorator",
regex: "@[\\w_]+",
},
],
};
};

oop.inherits(NumbatHighlightRules, TextHighlightRules);

exports.NumbatHighlightRules = NumbatHighlightRules;
},
);

ace.define("ace/mode/numbat", function (require, exports, module) {
var oop = require("ace/lib/oop");
var TextMode = require("ace/mode/text").Mode;
var NumbatHighlightRules =
require("ace/mode/numbat_highlight_rules").NumbatHighlightRules;

var Mode = function () {
this.HighlightRules = NumbatHighlightRules;
};
oop.inherits(Mode, TextMode);

(function () {
this.lineCommentStart = "#";

this.$id = "ace/mode/numbat";
}).call(Mode.prototype);

exports.Mode = Mode;
});

function debounce(func, wait, immediate) {
var timeout;
return function () {
var context = this,
args = arguments;
var later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}

function initializeEditor() {
const editor = ace.edit("editor", {
mode: "ace/mode/numbat",
showPrintMargin: false,
showGutter: true,
highlightActiveLine: false,
highlightGutterLine: false,
});

function evaluate() {
let code = editor.getValue();

let output = interpret(code);

document.getElementById("results").innerHTML = output;
}

var debouncedEvaluate = debounce(evaluate, 500);

editor.getSession().on("change", debouncedEvaluate);

evaluate();

editor.focus();
}

function initializeSplit() {
Split(['#editor', '#results'], {
gutterSize: 15,
});
}

0 comments on commit 6dade59

Please sign in to comment.