Improvements to playground editor
This commit is contained in:
@@ -33,7 +33,7 @@
|
|||||||
],
|
],
|
||||||
"onEnterRules": [
|
"onEnterRules": [
|
||||||
{
|
{
|
||||||
"beforeText": "\\b(where|of|case)$",
|
"beforeText": "\\b(where|of|do)\\s*$",
|
||||||
"action": { "indent": "indent" }
|
"action": { "indent": "indent" }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,4 +7,9 @@ export const ABBREV: Record<string, string> = {
|
|||||||
"\\circ": "∘",
|
"\\circ": "∘",
|
||||||
"\\1": "₁",
|
"\\1": "₁",
|
||||||
"\\2": "₂",
|
"\\2": "₂",
|
||||||
|
"\\<": "⟨",
|
||||||
|
"\\>": "⟩",
|
||||||
|
"\\_0": "₀",
|
||||||
|
"\\_1": "₁",
|
||||||
|
"\\bN": "ℕ"
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { AbstractEditor, EditorDelegate, Marker } from "./types";
|
import { AbstractEditor, EditorDelegate, Marker } from "./types";
|
||||||
import { basicSetup } from "codemirror";
|
import { basicSetup } from "codemirror";
|
||||||
import { EditorView, hoverTooltip, Tooltip } from "@codemirror/view";
|
import { defaultKeymap, indentMore, indentLess, toggleLineComment } from "@codemirror/commands";
|
||||||
import { Compartment } from "@codemirror/state";
|
import { EditorView, hoverTooltip, keymap, Tooltip } from "@codemirror/view";
|
||||||
|
import { Compartment, Prec } from "@codemirror/state";
|
||||||
import { oneDark } from "@codemirror/theme-one-dark";
|
import { oneDark } from "@codemirror/theme-one-dark";
|
||||||
import { linter } from "@codemirror/lint";
|
import { linter } from "@codemirror/lint";
|
||||||
import {
|
import {
|
||||||
|
indentService,
|
||||||
LanguageSupport,
|
LanguageSupport,
|
||||||
StreamLanguage,
|
StreamLanguage,
|
||||||
StringStream,
|
StringStream,
|
||||||
@@ -61,7 +63,7 @@ interface State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function tokenizer(stream: StringStream, state: State): string | null {
|
function tokenizer(stream: StringStream, state: State): string | null {
|
||||||
stream.eatSpace();
|
if (stream.eatSpace()) return null
|
||||||
if (stream.match("--")) {
|
if (stream.match("--")) {
|
||||||
stream.skipToEnd();
|
stream.skipToEnd();
|
||||||
return "comment";
|
return "comment";
|
||||||
@@ -70,17 +72,19 @@ function tokenizer(stream: StringStream, state: State): string | null {
|
|||||||
state.tokenizer = commentTokenizer;
|
state.tokenizer = commentTokenizer;
|
||||||
return state.tokenizer(stream, state);
|
return state.tokenizer(stream, state);
|
||||||
}
|
}
|
||||||
if (stream.match(/^[\w_][\w\d_']*/)) {
|
|
||||||
|
// TODO match tokenizer better..
|
||||||
|
if (stream.match(/[^\\(){}[\],.@;\s][^()\\{}\[\],.@;\s]*/)) {
|
||||||
let word = stream.current();
|
let word = stream.current();
|
||||||
if (keywords.includes(word)) return "keyword";
|
if (keywords.includes(word)) return "keyword";
|
||||||
if (word[0] >= "A" && word[0] <= "Z") return "typename";
|
if (word[0] >= "A" && word[0] <= "Z") return "typename";
|
||||||
|
console.log('IDENT', )
|
||||||
return "identifier";
|
return "identifier";
|
||||||
}
|
}
|
||||||
// unhandled
|
// unhandled
|
||||||
stream.next();
|
stream.next()
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function commentTokenizer(stream: StringStream, state: State): string | null {
|
function commentTokenizer(stream: StringStream, state: State): string | null {
|
||||||
console.log("ctok");
|
console.log("ctok");
|
||||||
let dash = false;
|
let dash = false;
|
||||||
@@ -100,6 +104,12 @@ const newtLanguage2 = StreamLanguage.define({
|
|||||||
token(stream, st) {
|
token(stream, st) {
|
||||||
return st.tokenizer(stream, st);
|
return st.tokenizer(stream, st);
|
||||||
},
|
},
|
||||||
|
languageData: {
|
||||||
|
commentTokens: {
|
||||||
|
line: "--"
|
||||||
|
},
|
||||||
|
wordChars: "!#$%^&*_+-=<>|",
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function newt() {
|
function newt() {
|
||||||
@@ -120,12 +130,46 @@ export class CMEditor implements AbstractEditor {
|
|||||||
extensions: [
|
extensions: [
|
||||||
basicSetup,
|
basicSetup,
|
||||||
linter((view) => this.delegate.lint(view)),
|
linter((view) => this.delegate.lint(view)),
|
||||||
this.theme.of(EditorView.baseTheme({})),
|
// For indent on return
|
||||||
|
indentService.of((ctx, pos) => {
|
||||||
|
let line = ctx.lineAt(pos)
|
||||||
|
if (!line) return null
|
||||||
|
let prevLine = ctx.lineAt(line.from - 1);
|
||||||
|
if (prevLine.text.trimEnd().match(/\b(of|where|do)\s*$/)) {
|
||||||
|
let pindent = prevLine.text.match(/^\s*/)?.[0].length ?? 0
|
||||||
|
return pindent + 2
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}),
|
||||||
|
Prec.highest(keymap.of([
|
||||||
|
{
|
||||||
|
key: "Tab",
|
||||||
|
preventDefault: true,
|
||||||
|
run: indentMore,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "Cmd-/",
|
||||||
|
run: toggleLineComment,
|
||||||
|
},
|
||||||
|
// ok, we can do multiple keys (we'll want this for Idris)
|
||||||
|
{
|
||||||
|
key: "c-c c-s",
|
||||||
|
run: () => {
|
||||||
|
console.log("C-c C-s")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "Shift-Tab",
|
||||||
|
preventDefault: true,
|
||||||
|
run: indentLess,
|
||||||
|
},
|
||||||
|
])),
|
||||||
EditorView.updateListener.of((update) => {
|
EditorView.updateListener.of((update) => {
|
||||||
let doc = update.state.doc;
|
let doc = update.state.doc;
|
||||||
|
|
||||||
update.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
|
update.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
|
||||||
if (" ')\\".includes(inserted.toString())) {
|
if (" ')\\_".includes(inserted.toString())) {
|
||||||
console.log("changes", update.changes, update.changes.desc);
|
console.log("changes", update.changes, update.changes.desc);
|
||||||
let line = doc.lineAt(fromA);
|
let line = doc.lineAt(fromA);
|
||||||
let e = fromA - line.from;
|
let e = fromA - line.from;
|
||||||
@@ -146,6 +190,7 @@ export class CMEditor implements AbstractEditor {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
this.theme.of(EditorView.baseTheme({})),
|
||||||
hoverTooltip((view, pos) => {
|
hoverTooltip((view, pos) => {
|
||||||
let cursor = this.view.state.doc.lineAt(pos);
|
let cursor = this.view.state.doc.lineAt(pos);
|
||||||
let line = cursor.number;
|
let line = cursor.number;
|
||||||
@@ -155,7 +200,8 @@ export class CMEditor implements AbstractEditor {
|
|||||||
let col = range.from - cursor.from;
|
let col = range.from - cursor.from;
|
||||||
let word = this.view.state.doc.sliceString(range.from, range.to);
|
let word = this.view.state.doc.sliceString(range.from, range.to);
|
||||||
let entry = this.delegate.getEntry(word, line, col);
|
let entry = this.delegate.getEntry(word, line, col);
|
||||||
console.log("entry", entry);
|
if (!entry) entry = this.delegate.getEntry('_'+word+'_', line, col);
|
||||||
|
console.log("entry for", word, "is", entry);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
let rval: Tooltip = {
|
let rval: Tooltip = {
|
||||||
pos: range.head,
|
pos: range.head,
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ const language: EditorDelegate = {
|
|||||||
return topData?.context.find((entry) => entry.name === word);
|
return topData?.context.find((entry) => entry.name === word);
|
||||||
},
|
},
|
||||||
onChange(value) {
|
onChange(value) {
|
||||||
|
// run via the linter now
|
||||||
// clearTimeout(timeout);
|
// clearTimeout(timeout);
|
||||||
// timeout = setTimeout(() => {
|
// timeout = setTimeout(() => {
|
||||||
// run(value);
|
// run(value);
|
||||||
@@ -199,15 +200,17 @@ const language: EditorDelegate = {
|
|||||||
async lint(view) {
|
async lint(view) {
|
||||||
console.log("LINT");
|
console.log("LINT");
|
||||||
let src = view.state.doc.toString();
|
let src = view.state.doc.toString();
|
||||||
|
localStorage.code = src
|
||||||
|
// we'll want to pull it from the file.
|
||||||
const fileName = state.currentFile.value;
|
const fileName = state.currentFile.value;
|
||||||
console.log("FN", fileName);
|
console.log("FN", fileName);
|
||||||
// console.log("SRC", src);
|
|
||||||
try {
|
try {
|
||||||
let out = await runCommand({
|
let out = await runCommand({
|
||||||
id: nextID(),
|
id: nextID(),
|
||||||
type: "compileRequest",
|
type: "compileRequest",
|
||||||
fileName,
|
fileName,
|
||||||
src,
|
src,
|
||||||
|
compile: false,
|
||||||
});
|
});
|
||||||
console.log("OUT", out);
|
console.log("OUT", out);
|
||||||
let markers = processOutput(out);
|
let markers = processOutput(out);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export interface CompileReq {
|
|||||||
type: "compileRequest";
|
type: "compileRequest";
|
||||||
fileName: string;
|
fileName: string;
|
||||||
src: string;
|
src: string;
|
||||||
|
compile: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CompileRes {
|
export interface CompileRes {
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import { archive, preload } from "./preload";
|
|||||||
import { CompileReq, CompileRes } from "./types";
|
import { CompileReq, CompileRes } from "./types";
|
||||||
|
|
||||||
console.log = (m) => {
|
console.log = (m) => {
|
||||||
shim.stdout += '\n' + m
|
shim.stdout += "\n" + m;
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleMessage = async function (ev: { data: CompileReq }) {
|
const handleMessage = async function (ev: { data: CompileReq }) {
|
||||||
console.log("message", ev.data);
|
console.log("message", ev.data);
|
||||||
@@ -12,7 +12,10 @@ const handleMessage = async function (ev: { data: CompileReq }) {
|
|||||||
shim.archive = archive;
|
shim.archive = archive;
|
||||||
let { id, src, fileName } = ev.data;
|
let { id, src, fileName } = ev.data;
|
||||||
const outfile = "out.js";
|
const outfile = "out.js";
|
||||||
shim.process.argv = ["browser", "newt", fileName, "-o", outfile, "--top"];
|
if (ev.data.compile)
|
||||||
|
shim.process.argv = ["browser", "newt", fileName, "-o", outfile, "--top"];
|
||||||
|
else
|
||||||
|
shim.process.argv = ["browser", "newt", fileName, "--top"];
|
||||||
shim.files[fileName] = new TextEncoder().encode(src);
|
shim.files[fileName] = new TextEncoder().encode(src);
|
||||||
shim.files[outfile] = new TextEncoder().encode("No JS output");
|
shim.files[outfile] = new TextEncoder().encode("No JS output");
|
||||||
shim.stdout = "";
|
shim.stdout = "";
|
||||||
@@ -29,7 +32,7 @@ const handleMessage = async function (ev: { data: CompileReq }) {
|
|||||||
console.log(`process ${fileName} in ${duration} ms`);
|
console.log(`process ${fileName} in ${duration} ms`);
|
||||||
let javascript = new TextDecoder().decode(shim.files[outfile]);
|
let javascript = new TextDecoder().decode(shim.files[outfile]);
|
||||||
let output = shim.stdout;
|
let output = shim.stdout;
|
||||||
sendResponse({ id, type: 'compileResult', javascript, output, duration });
|
sendResponse({ id, type: "compileResult", javascript, output, duration });
|
||||||
};
|
};
|
||||||
|
|
||||||
// hooks for worker.html to override
|
// hooks for worker.html to override
|
||||||
|
|||||||
@@ -286,10 +286,6 @@ stmtToDoc (JError str) = text "throw new Error(" ++ text (quoteString str) ++ te
|
|||||||
stmtToDoc (JCase sc alts) =
|
stmtToDoc (JCase sc alts) =
|
||||||
text "switch (" ++ expToDoc sc ++ text ")" <+> bracket "{" (stack $ map altToDoc alts) "}"
|
text "switch (" ++ expToDoc sc ++ text ")" <+> bracket "{" (stack $ map altToDoc alts) "}"
|
||||||
|
|
||||||
mkArgs : Nat -> List String -> List String
|
|
||||||
mkArgs Z acc = acc
|
|
||||||
mkArgs (S k) acc = mkArgs k ("h\{show k}" :: acc)
|
|
||||||
|
|
||||||
-- use iife to turn stmts into expr
|
-- use iife to turn stmts into expr
|
||||||
maybeWrap : JSStmt Return -> JSExp
|
maybeWrap : JSStmt Return -> JSExp
|
||||||
maybeWrap (JReturn exp) = exp
|
maybeWrap (JReturn exp) = exp
|
||||||
@@ -399,6 +395,7 @@ process name = do
|
|||||||
eraseEntries
|
eraseEntries
|
||||||
liftWhere
|
liftWhere
|
||||||
entries <- readIORef ref
|
entries <- readIORef ref
|
||||||
|
-- Now working with defs
|
||||||
exprs <- mapM defToCExp $ toList entries
|
exprs <- mapM defToCExp $ toList entries
|
||||||
let cexpMap = foldMap const EmptyMap exprs
|
let cexpMap = foldMap const EmptyMap exprs
|
||||||
cexpMap <- tailCallOpt cexpMap
|
cexpMap <- tailCallOpt cexpMap
|
||||||
|
|||||||
Reference in New Issue
Block a user