Wire web playground to LSP code
This commit is contained in:
9
Makefile
9
Makefile
@@ -60,11 +60,14 @@ audit: .PHONY
|
|||||||
lsp.js: ${SRCS}
|
lsp.js: ${SRCS}
|
||||||
node newt.js src/LSP.newt -o lsp.js
|
node newt.js src/LSP.newt -o lsp.js
|
||||||
|
|
||||||
newt-vscode-lsp/src/newt.js: ${SRCS}
|
newt-vscode-lsp/src/newt.js: lsp.js
|
||||||
node newt.js src/LSP.newt -o $@
|
cp lsp.js $@
|
||||||
|
|
||||||
|
playground/src/newt.js: lsp.js
|
||||||
|
cp lsp.js $@
|
||||||
|
|
||||||
newt-vscode-lsp/dist/lsp.js: newt-vscode-lsp/src/lsp.ts newt-vscode-lsp/src/newt.js
|
newt-vscode-lsp/dist/lsp.js: newt-vscode-lsp/src/lsp.ts newt-vscode-lsp/src/newt.js
|
||||||
(cd newt-vscode-lsp && node esbuild.js)
|
(cd newt-vscode-lsp && node esbuild.js)
|
||||||
|
|
||||||
lsp: newt-vscode-lsp/dist/lsp.js
|
lsp: newt-vscode-lsp/dist/lsp.js playground/src/newt.js
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
mkdir -p public
|
mkdir -p public
|
||||||
|
echo copy newt
|
||||||
|
#cp ../lsp.js src/newt.js
|
||||||
|
(cd .. && make lsp)
|
||||||
echo build newt worker
|
echo build newt worker
|
||||||
esbuild src/worker.ts --bundle --format=esm --platform=browser > public/worker.js
|
esbuild src/worker.ts --bundle --format=esm --platform=browser > public/worker.js
|
||||||
esbuild src/frame.ts --bundle --format=esm --platform=browser > public/frame.js
|
esbuild src/frame.ts --bundle --format=esm --platform=browser > public/frame.js
|
||||||
echo copy newt
|
|
||||||
cp ../newt.js src/newt.js
|
|
||||||
cp -r static/* public
|
cp -r static/* public
|
||||||
(cd samples && zip -r ../public/files.zip .)
|
(cd samples && zip -r ../public/files.zip .)
|
||||||
|
|||||||
@@ -234,32 +234,29 @@ export class CMEditor implements AbstractEditor {
|
|||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
this.theme.of(EditorView.baseTheme({})),
|
this.theme.of(EditorView.baseTheme({})),
|
||||||
hoverTooltip((view, pos) => {
|
hoverTooltip(async (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 - 1;
|
||||||
let range = this.view.state.wordAt(pos);
|
let col = pos - cursor.from;
|
||||||
console.log(range);
|
// let range = this.view.state.wordAt(pos);
|
||||||
if (range) {
|
console.log('getting hover for ',line, col);
|
||||||
let col = range.from - cursor.from;
|
let entry = await this.delegate.getEntry('', line, col)
|
||||||
let word = this.view.state.doc.sliceString(range.from, range.to);
|
|
||||||
let entry = this.delegate.getEntry(word, line, col);
|
|
||||||
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,
|
// TODO pull in position from LSP (currently it only has the jump-to FC)
|
||||||
|
pos,
|
||||||
above: true,
|
above: true,
|
||||||
create: () => {
|
create: () => {
|
||||||
let dom = document.createElement("div");
|
let dom = document.createElement("div");
|
||||||
dom.className = "tooltip";
|
dom.className = "tooltip";
|
||||||
dom.textContent = entry.type;
|
dom.textContent = entry.info;
|
||||||
return { dom };
|
return { dom };
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// we'll iterate the syntax tree for word.
|
// we'll iterate the syntax tree for word.
|
||||||
// let entry = delegate.getEntry(word, line, col)
|
// let entry = delegate.getEntry(word, line, col)
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1,10 +1,54 @@
|
|||||||
|
|
||||||
|
//// Copy of LSP types
|
||||||
|
|
||||||
|
export interface Location { uri: string; range: Range; }
|
||||||
|
export interface Position { line: number; character: number; }
|
||||||
|
export interface Range { start: Position; end: Position; }
|
||||||
|
export interface HoverResult { info: string; location: Location; }
|
||||||
|
export interface TextEdit { range: Range; newText: string; }
|
||||||
|
export type DiagnosticSeverity = 1 | 2 | 3 | 4
|
||||||
|
export interface DiagnosticRelatedInformation { location: Location; message: string; }
|
||||||
|
export interface Diagnostic {
|
||||||
|
range: Range
|
||||||
|
message: string
|
||||||
|
severity?: DiagnosticSeverity
|
||||||
|
source?: string
|
||||||
|
// we don't emit this yet, but I think we will
|
||||||
|
relatedInformation?: DiagnosticRelatedInformation[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WorkspaceEdit {
|
||||||
|
changes?: {
|
||||||
|
[uri: string]: TextEdit[];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CodeAction {
|
||||||
|
title: string;
|
||||||
|
edit?: WorkspaceEdit;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BuildResult {
|
||||||
|
diags: Diagnostic[]
|
||||||
|
output: string
|
||||||
|
}
|
||||||
|
|
||||||
|
//// IPC Thinger
|
||||||
|
|
||||||
export type Result<A> =
|
export type Result<A> =
|
||||||
| { status: "ok"; value: A }
|
| { status: "ok"; value: A }
|
||||||
| { status: "err"; error: string };
|
| { status: "err"; error: string };
|
||||||
|
|
||||||
export interface API {
|
export interface API {
|
||||||
save(fileName: string, content: string): string;
|
// Invalidates stuff and writes to an internal cache that overlays the "filesystem"
|
||||||
typeCheck(fileName: string): string;
|
updateFile(fileName: string, content: string): unknown;
|
||||||
|
// Run checking, return diagnostics
|
||||||
|
typeCheck(fileName: string): BuildResult;
|
||||||
|
// returns True if we need to recheck - usually for files invalidating other files
|
||||||
|
// The playground rarely hits this situation at the moment
|
||||||
|
hoverInfo(fileName: string, row: number, col: number): HoverResult | boolean | null;
|
||||||
|
codeActionInfo(fileName: string, row: number, col: number): CodeAction[] | null;
|
||||||
|
// we need to add this to the LSP build
|
||||||
compile(fileName: string): string;
|
compile(fileName: string): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,9 +58,9 @@ export interface Message<K extends keyof API> {
|
|||||||
args: Parameters<API[K]>;
|
args: Parameters<API[K]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResponseMSG {
|
export interface ResponseMSG<K extends keyof API> {
|
||||||
id: number;
|
id: number;
|
||||||
result: string;
|
result: Awaited<ReturnType<API[K]>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Suspense = {
|
type Suspense = {
|
||||||
@@ -33,7 +77,8 @@ export class IPC {
|
|||||||
this._postMessage = <K extends keyof API>(msg: Message<K>) =>
|
this._postMessage = <K extends keyof API>(msg: Message<K>) =>
|
||||||
newtWorker.postMessage(msg);
|
newtWorker.postMessage(msg);
|
||||||
// Safari/MobileSafari have small stacks in webworkers.
|
// Safari/MobileSafari have small stacks in webworkers.
|
||||||
if (navigator.vendor.includes("Apple")) {
|
// But support for the frame needs to be fixed
|
||||||
|
if (navigator.vendor.includes("Apple") && false) {
|
||||||
const workerFrame = document.createElement("iframe");
|
const workerFrame = document.createElement("iframe");
|
||||||
workerFrame.src = "worker.html";
|
workerFrame.src = "worker.html";
|
||||||
workerFrame.style.display = "none";
|
workerFrame.style.display = "none";
|
||||||
@@ -46,7 +91,7 @@ export class IPC {
|
|||||||
}
|
}
|
||||||
// Need to handle messages from the other iframe too? Or at least ignore them.
|
// Need to handle messages from the other iframe too? Or at least ignore them.
|
||||||
}
|
}
|
||||||
onmessage = (ev: MessageEvent<ResponseMSG>) => {
|
onmessage = <K extends keyof API>(ev: MessageEvent<ResponseMSG<K>>) => {
|
||||||
console.log("GET", ev.data);
|
console.log("GET", ev.data);
|
||||||
// Maybe key off of type
|
// Maybe key off of type
|
||||||
if (ev.data.id) {
|
if (ev.data.id) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
import { CMEditor } from "./cmeditor.ts";
|
import { CMEditor } from "./cmeditor.ts";
|
||||||
import { deflate } from "./deflate.ts";
|
import { deflate } from "./deflate.ts";
|
||||||
import { inflate } from "./inflate.ts";
|
import { inflate } from "./inflate.ts";
|
||||||
import { IPC } from "./ipc.ts";
|
import { IPC, Position } from "./ipc.ts";
|
||||||
import helpText from "./help.md?raw";
|
import helpText from "./help.md?raw";
|
||||||
import { basicSetup, EditorView } from "codemirror";
|
import { basicSetup, EditorView } from "codemirror";
|
||||||
import {Compartment, EditorState} from "@codemirror/state";
|
import {Compartment, EditorState} from "@codemirror/state";
|
||||||
@@ -81,7 +81,7 @@ if (!state.javascript.value) {
|
|||||||
console.log("SEND TO", iframe.contentWindow);
|
console.log("SEND TO", iframe.contentWindow);
|
||||||
const fileName = state.currentFile.value;
|
const fileName = state.currentFile.value;
|
||||||
// maybe send fileName, src?
|
// maybe send fileName, src?
|
||||||
await ipc.sendMessage("save", [fileName, src]);
|
await ipc.sendMessage("updateFile", [fileName, src]);
|
||||||
let js = await ipc.sendMessage("compile", [fileName]);
|
let js = await ipc.sendMessage("compile", [fileName]);
|
||||||
state.javascript.value = bundle(js);
|
state.javascript.value = bundle(js);
|
||||||
}
|
}
|
||||||
@@ -210,8 +210,12 @@ interface EditorProps {
|
|||||||
initialValue: string;
|
initialValue: string;
|
||||||
}
|
}
|
||||||
const language: EditorDelegate = {
|
const language: EditorDelegate = {
|
||||||
getEntry(word, _row, _col) {
|
async getEntry(word, row, col) {
|
||||||
return topData?.context.find((entry) => entry.name === word);
|
let fileName = state.currentFile.value
|
||||||
|
let res = await ipc.sendMessage("hoverInfo", [fileName, row, col])
|
||||||
|
console.log('HOVER', res, 'for', row, col)
|
||||||
|
if (res == true) return null
|
||||||
|
return res || null
|
||||||
},
|
},
|
||||||
onChange(_value) {
|
onChange(_value) {
|
||||||
// we're using lint() now
|
// we're using lint() now
|
||||||
@@ -228,31 +232,37 @@ const language: EditorDelegate = {
|
|||||||
let module = src.match(/module\s+([^\s]+)/)?.[1];
|
let module = src.match(/module\s+([^\s]+)/)?.[1];
|
||||||
if (module) {
|
if (module) {
|
||||||
// This causes problems with stuff like aoc/...
|
// This causes problems with stuff like aoc/...
|
||||||
state.currentFile.value = module.replace(".", "/") + ".newt";
|
state.currentFile.value = './' + module.replace(".", "/") + ".newt";
|
||||||
}
|
}
|
||||||
// This is a little flashy
|
// This is a little flashy
|
||||||
// state.javascript.value = ''
|
// state.javascript.value = ''
|
||||||
let fileName = state.currentFile.value;
|
let fileName = state.currentFile.value;
|
||||||
console.log("FN", fileName);
|
console.log("FN", fileName);
|
||||||
try {
|
try {
|
||||||
await ipc.sendMessage("save", [fileName, src]);
|
await ipc.sendMessage("updateFile", [fileName, src]);
|
||||||
let out = await ipc.sendMessage("typeCheck", [fileName]);
|
let res = await ipc.sendMessage("typeCheck", [fileName]);
|
||||||
setOutput(out);
|
|
||||||
let markers = processOutput(out);
|
|
||||||
let diags: Diagnostic[] = [];
|
let diags: Diagnostic[] = [];
|
||||||
for (let marker of markers) {
|
for (let marker of res.diags) {
|
||||||
let col = marker.startColumn;
|
let {start,end} = marker.range
|
||||||
|
let xlate = (pos: Position): number =>
|
||||||
|
view.state.doc.line(pos.line + 1).from + pos.character
|
||||||
|
|
||||||
let line = view.state.doc.line(marker.startLineNumber);
|
// TODO double check the last two are right
|
||||||
const pos = line.from + col - 1;
|
const SEVERITY: Diagnostic["severity"][] = [ "error", "error", "warning", "info", "hint"]
|
||||||
let word = view.state.wordAt(pos);
|
console.error({
|
||||||
|
from: xlate(start),
|
||||||
|
to: xlate(end),
|
||||||
|
severity: SEVERITY[marker.severity ?? 1],
|
||||||
|
message: marker.message,
|
||||||
|
})
|
||||||
diags.push({
|
diags.push({
|
||||||
from: word?.from ?? pos,
|
from: xlate(start),
|
||||||
to: word?.to ?? pos + 1,
|
to: xlate(end),
|
||||||
severity: marker.severity,
|
severity: SEVERITY[marker.severity ?? 1],
|
||||||
message: marker.message,
|
message: marker.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
setOutput(res.output)
|
||||||
// less flashy version
|
// less flashy version
|
||||||
ipc.sendMessage("compile", [fileName]).then(js => state.javascript.value = bundle(js));
|
ipc.sendMessage("compile", [fileName]).then(js => state.javascript.value = bundle(js));
|
||||||
return diags;
|
return diags;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { EditorView } from "codemirror";
|
import { EditorView } from "codemirror";
|
||||||
import { linter, Diagnostic } from "@codemirror/lint";
|
import { Diagnostic } from "@codemirror/lint";
|
||||||
|
import { HoverResult } from "./ipc";
|
||||||
|
|
||||||
|
|
||||||
export interface CompileReq {
|
export interface CompileReq {
|
||||||
id: string
|
id: string
|
||||||
@@ -55,7 +54,7 @@ export interface TopData {
|
|||||||
context: TopEntry[];
|
context: TopEntry[];
|
||||||
}
|
}
|
||||||
export interface EditorDelegate {
|
export interface EditorDelegate {
|
||||||
getEntry(word: string, row: number, col: number): TopEntry | undefined
|
getEntry(word: string, row: number, col: number): Promise<HoverResult | null>
|
||||||
onChange(value: string): unknown
|
onChange(value: string): unknown
|
||||||
getFileName(): string
|
getFileName(): string
|
||||||
lint(view: EditorView): Promise<Diagnostic[]> | Diagnostic[]
|
lint(view: EditorView): Promise<Diagnostic[]> | Diagnostic[]
|
||||||
|
|||||||
@@ -1,52 +1,50 @@
|
|||||||
import { shim } from "./emul";
|
import { shim } from "./emul";
|
||||||
import { API, Message, ResponseMSG } from "./ipc";
|
import { API, Message, ResponseMSG } from "./ipc";
|
||||||
import { archive, preload } from "./preload";
|
import { archive, preload } from "./preload";
|
||||||
import { Main_main } from './newt';
|
import { LSP_checkFile, LSP_codeActionInfo, LSP_compileJS, LSP_hoverInfo, LSP_updateFile } from './newt';
|
||||||
|
|
||||||
const LOG = console.log
|
const LOG = console.log
|
||||||
|
|
||||||
console.log = (m) => {
|
// console.log = (m) => {
|
||||||
LOG(m)
|
// LOG(m)
|
||||||
shim.stdout += "\n" + m;
|
// shim.stdout += "\n" + m;
|
||||||
};
|
// };
|
||||||
|
|
||||||
|
const invoke = <T extends (...args: any[]) => any>(fun:T, args: Parameters<T>): ReturnType<T> => {
|
||||||
|
return fun.apply(undefined, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
const api: API = {
|
||||||
|
// none of these are promises...
|
||||||
|
updateFile: LSP_updateFile,
|
||||||
|
typeCheck(filename) {
|
||||||
|
shim.stdout = ""
|
||||||
|
let diags = LSP_checkFile(filename);
|
||||||
|
let output = shim.stdout
|
||||||
|
return {diags,output}
|
||||||
|
},
|
||||||
|
hoverInfo: LSP_hoverInfo,
|
||||||
|
codeActionInfo: LSP_codeActionInfo,
|
||||||
|
compile: LSP_compileJS,
|
||||||
|
}
|
||||||
|
|
||||||
const handleMessage = async function <K extends keyof API>(ev: { data: Message<K> }) {
|
const handleMessage = async function <K extends keyof API>(ev: { data: Message<K> }) {
|
||||||
LOG("HANDLE", ev.data);
|
LOG("HANDLE", ev.data);
|
||||||
await preload;
|
await preload;
|
||||||
shim.archive = archive;
|
shim.archive = archive;
|
||||||
let key = ev.data.key
|
|
||||||
if (key === 'typeCheck' || key === 'compile') {
|
|
||||||
let {id, args: [fileName]} = ev.data
|
|
||||||
LOG(key, fileName)
|
|
||||||
const outfile = "out.js";
|
|
||||||
const isCompile = key === 'compile';
|
|
||||||
if (isCompile)
|
|
||||||
shim.process.argv = ["browser", "newt", fileName, "-o", outfile, "--top"];
|
|
||||||
else
|
|
||||||
shim.process.argv = ["browser", "newt", fileName, "--top"];
|
|
||||||
shim.stdout = "";
|
|
||||||
shim.files[outfile] = new TextEncoder().encode("No JS output");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Main_main();
|
shim.stdout = ''
|
||||||
|
let {id, key, args} = ev.data
|
||||||
|
let result = await invoke(api[key], args)
|
||||||
|
LOG('got', result)
|
||||||
|
sendResponse<typeof key>({id, result})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// make it clickable in console
|
console.error(e)
|
||||||
console.error(e);
|
|
||||||
// make it visable on page
|
|
||||||
shim.stdout += "\n" + String(e);
|
|
||||||
}
|
|
||||||
let result = isCompile ? new TextDecoder().decode(shim.files[outfile]) : shim.stdout
|
|
||||||
sendResponse({id, result})
|
|
||||||
} else if (key === 'save') {
|
|
||||||
let {id, args: [fileName, content]} = ev.data
|
|
||||||
LOG(`SAVE ${content?.length} to ${fileName}`)
|
|
||||||
shim.files[fileName] = new TextEncoder().encode(content)
|
|
||||||
LOG('send', {id, result: ''})
|
|
||||||
sendResponse({id, result: ''})
|
|
||||||
}
|
}
|
||||||
|
console.log(shim.stdout)
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// hooks for worker.html to override
|
// hooks for worker.html to override
|
||||||
let sendResponse: <K extends keyof API>(_: ResponseMSG) => void = postMessage;
|
let sendResponse: <K extends keyof API>(_: ResponseMSG<K>) => void = postMessage;
|
||||||
onmessage = handleMessage;
|
onmessage = handleMessage;
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ decomposeName fn =
|
|||||||
then go (x :: acc) xs
|
then go (x :: acc) xs
|
||||||
else (joinBy "/" (xs :< x <>> Nil), joinBy "." acc)
|
else (joinBy "/" (xs :< x <>> Nil), joinBy "." acc)
|
||||||
|
|
||||||
|
|
||||||
switchModule : FileSource → String → M (Maybe ModContext)
|
switchModule : FileSource → String → M (Maybe ModContext)
|
||||||
switchModule repo modns = do
|
switchModule repo modns = do
|
||||||
-- TODO processing on hover is expensive, but info is not always there
|
-- TODO processing on hover is expensive, but info is not always there
|
||||||
@@ -69,10 +68,18 @@ getHoverInfo repo modns row col = do
|
|||||||
pure $ HasHover e.fc ("\{show e.name} : \{rpprint Nil ty}")
|
pure $ HasHover e.fc ("\{show e.name} : \{rpprint Nil ty}")
|
||||||
|
|
||||||
where
|
where
|
||||||
|
-- We don't want to pick up the paren token when on the border
|
||||||
|
isIdent : BTok → Bool
|
||||||
|
isIdent (MkBounded (Tok Ident _) _) = True
|
||||||
|
isIdent (MkBounded (Tok UIdent _) _) = True
|
||||||
|
isIdent (MkBounded (Tok MixFix _) _) = True
|
||||||
|
isIdent (MkBounded (Tok Projection _) _) = True
|
||||||
|
isIdent _ = False
|
||||||
|
|
||||||
getTok : List BTok → Maybe String
|
getTok : List BTok → Maybe String
|
||||||
getTok Nil = Nothing
|
getTok Nil = Nothing
|
||||||
getTok (tok :: toks) =
|
getTok (tok :: toks) =
|
||||||
if tok.bounds.startCol <= col && (col <= tok.bounds.endCol)
|
if tok.bounds.startCol <= col && col <= tok.bounds.endCol && isIdent tok
|
||||||
then Just $ value tok else getTok toks
|
then Just $ value tok else getTok toks
|
||||||
|
|
||||||
data FileEdit = MkEdit FC String
|
data FileEdit = MkEdit FC String
|
||||||
|
|||||||
24
src/LSP.newt
24
src/LSP.newt
@@ -16,6 +16,7 @@ import Commands
|
|||||||
import Lib.ProcessDecl
|
import Lib.ProcessDecl
|
||||||
import Lib.Prettier
|
import Lib.Prettier
|
||||||
import Lib.Error
|
import Lib.Error
|
||||||
|
import Lib.Compile
|
||||||
|
|
||||||
pfunc js_castArray : Array JSObject → JSObject := `x => x`
|
pfunc js_castArray : Array JSObject → JSObject := `x => x`
|
||||||
pfunc js_castInt : Int → JSObject := `x => x`
|
pfunc js_castInt : Int → JSObject := `x => x`
|
||||||
@@ -224,4 +225,25 @@ checkFile fn = unsafePerformIO $ do
|
|||||||
modifyIORef state $ [ topContext := top ]
|
modifyIORef state $ [ topContext := top ]
|
||||||
pure $ jsonToJObject $ JsonArray json
|
pure $ jsonToJObject $ JsonArray json
|
||||||
|
|
||||||
#export updateFile checkFile hoverInfo codeActionInfo
|
compileJS : String → JSObject
|
||||||
|
compileJS fn = unsafePerformIO $ do
|
||||||
|
let (base, modName) = decomposeName fn
|
||||||
|
st <- readIORef state
|
||||||
|
when (st.baseDir /= base) $ \ _ => resetState base
|
||||||
|
repo <- lspFileSource
|
||||||
|
(Right (top, src)) <- (do
|
||||||
|
putStrLn "woo"
|
||||||
|
mod <- processModule emptyFC repo Nil modName
|
||||||
|
docs <- compile
|
||||||
|
let src = unlines $
|
||||||
|
( "const bouncer = (f,ini) => { let obj = ini; while (obj.tag) obj = f(obj); return obj.h0 };"
|
||||||
|
:: Nil)
|
||||||
|
++ map (render 90 ∘ noAlt) docs
|
||||||
|
pure src).runM st.topContext
|
||||||
|
| Left err => pure $ js_castStr "// \{errorMsg err}"
|
||||||
|
modifyIORef state [ topContext := top ]
|
||||||
|
pure $ js_castStr src
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#export updateFile checkFile hoverInfo codeActionInfo compileJS
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ deriveEq fc name = do
|
|||||||
|
|
||||||
where
|
where
|
||||||
arr : Raw → Raw → Raw
|
arr : Raw → Raw → Raw
|
||||||
arr a b = RPi emptyFC (BI fc "_" Explicit Many) a b
|
arr a b = RPi fc (BI fc "_" Explicit Many) a b
|
||||||
|
|
||||||
rvar : String → Raw
|
rvar : String → Raw
|
||||||
rvar nm = RVar emptyFC nm
|
rvar nm = RVar fc nm
|
||||||
|
|
||||||
getExplictNames : SnocList String → Tm → List String
|
getExplictNames : SnocList String → Tm → List String
|
||||||
getExplictNames acc (Pi fc nm Explicit quant a b) = getExplictNames (acc :< nm) b
|
getExplictNames acc (Pi fc nm Explicit quant a b) = getExplictNames (acc :< nm) b
|
||||||
@@ -49,7 +49,7 @@ deriveEq fc name = do
|
|||||||
getExplictNames acc _ = acc <>> Nil
|
getExplictNames acc _ = acc <>> Nil
|
||||||
|
|
||||||
buildApp : String → List Raw → Raw
|
buildApp : String → List Raw → Raw
|
||||||
buildApp nm nms = foldl (\ t u => RApp emptyFC t u Explicit) (rvar nm) $ nms
|
buildApp nm nms = foldl (\ t u => RApp fc t u Explicit) (rvar nm) $ nms
|
||||||
|
|
||||||
equate : (Raw × Raw) → Raw
|
equate : (Raw × Raw) → Raw
|
||||||
equate (a,b) = buildApp "_==_" (a :: b :: Nil)
|
equate (a,b) = buildApp "_==_" (a :: b :: Nil)
|
||||||
@@ -89,13 +89,13 @@ deriveShow fc name = do
|
|||||||
|
|
||||||
where
|
where
|
||||||
arr : Raw → Raw → Raw
|
arr : Raw → Raw → Raw
|
||||||
arr a b = RPi emptyFC (BI fc "_" Explicit Many) a b
|
arr a b = RPi fc (BI fc "_" Explicit Many) a b
|
||||||
|
|
||||||
rvar : String → Raw
|
rvar : String → Raw
|
||||||
rvar nm = RVar emptyFC nm
|
rvar nm = RVar fc nm
|
||||||
|
|
||||||
lstring : String → Raw
|
lstring : String → Raw
|
||||||
lstring s = RLit emptyFC (LString s)
|
lstring s = RLit fc (LString s)
|
||||||
|
|
||||||
getExplictNames : SnocList String → Tm → List String
|
getExplictNames : SnocList String → Tm → List String
|
||||||
getExplictNames acc (Pi fc nm Explicit quant a b) = getExplictNames (acc :< nm) b
|
getExplictNames acc (Pi fc nm Explicit quant a b) = getExplictNames (acc :< nm) b
|
||||||
@@ -104,7 +104,7 @@ deriveShow fc name = do
|
|||||||
getExplictNames acc _ = acc <>> Nil
|
getExplictNames acc _ = acc <>> Nil
|
||||||
|
|
||||||
buildApp : String → List Raw → Raw
|
buildApp : String → List Raw → Raw
|
||||||
buildApp nm nms = foldl (\ t u => RApp emptyFC t u Explicit) (rvar nm) $ nms
|
buildApp nm nms = foldl (\ t u => RApp fc t u Explicit) (rvar nm) $ nms
|
||||||
|
|
||||||
equate : (Raw × Raw) → Raw
|
equate : (Raw × Raw) → Raw
|
||||||
equate (a,b) = buildApp "_==_" (a :: b :: Nil)
|
equate (a,b) = buildApp "_==_" (a :: b :: Nil)
|
||||||
@@ -118,7 +118,7 @@ deriveShow fc name = do
|
|||||||
let names = getExplictNames Lin ty
|
let names = getExplictNames Lin ty
|
||||||
anames <- map rvar <$> traverse freshName names
|
anames <- map rvar <$> traverse freshName names
|
||||||
let left = buildApp "show" $ buildApp nm anames :: Nil
|
let left = buildApp "show" $ buildApp nm anames :: Nil
|
||||||
let shows = map (\ nm => RApp emptyFC (rvar "show") nm Explicit) anames
|
let shows = map (\ nm => RApp fc (rvar "show") nm Explicit) anames
|
||||||
let right = case anames of
|
let right = case anames of
|
||||||
Nil => lstring nm
|
Nil => lstring nm
|
||||||
_ =>
|
_ =>
|
||||||
|
|||||||
Reference in New Issue
Block a user