also show scheme code in web playground
This commit is contained in:
@@ -154,6 +154,36 @@ const newtLanguage2: StreamLanguage<State> = StreamLanguage.define({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export function scheme() {
|
||||||
|
return new LanguageSupport(schemeLanguage);
|
||||||
|
}
|
||||||
|
|
||||||
|
const schemeLanguage: StreamLanguage<State> = StreamLanguage.define({
|
||||||
|
startState: () => null,
|
||||||
|
token(stream, st) {
|
||||||
|
const keywords = ["define", "let", "case", "cond", "import", "include", "lambda", "else"];
|
||||||
|
if (stream.eatSpace()) return null;
|
||||||
|
if (stream.match("--")) {
|
||||||
|
stream.skipToEnd();
|
||||||
|
return "comment";
|
||||||
|
}
|
||||||
|
if (stream.match(/[0-9A-Za-z!%&*+./:<=>?@^_~-]+/)) {
|
||||||
|
let word = stream.current();
|
||||||
|
if (keywords.includes(word)) return "keyword";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// unhandled
|
||||||
|
stream.next();
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
languageData: {
|
||||||
|
commentTokens: {
|
||||||
|
line: ";;",
|
||||||
|
},
|
||||||
|
wordChars: "!%&*+-./:<=>?@^_~",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
function newt() {
|
function newt() {
|
||||||
return new LanguageSupport(newtLanguage2);
|
return new LanguageSupport(newtLanguage2);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export interface API {
|
|||||||
hoverInfo(fileName: string, row: number, col: number): HoverResult | boolean | null;
|
hoverInfo(fileName: string, row: number, col: number): HoverResult | boolean | null;
|
||||||
codeActionInfo(fileName: string, row: number, col: number): CodeAction[] | null;
|
codeActionInfo(fileName: string, row: number, col: number): CodeAction[] | null;
|
||||||
// we need to add this to the LSP build
|
// we need to add this to the LSP build
|
||||||
compile(fileName: string): string;
|
compile(fileName: string, language: 'javascript'|'scheme'): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Message<K extends keyof API> {
|
export interface Message<K extends keyof API> {
|
||||||
@@ -116,4 +116,3 @@ export class IPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class IPCClient {}
|
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ import {
|
|||||||
TopData,
|
TopData,
|
||||||
Marker,
|
Marker,
|
||||||
} from "./types.ts";
|
} from "./types.ts";
|
||||||
import { CMEditor } from "./cmeditor.ts";
|
import { CMEditor, scheme } 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, Position } 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";
|
||||||
import { javascript } from "@codemirror/lang-javascript";
|
import { javascript } from "@codemirror/lang-javascript";
|
||||||
import { oneDark } from "@codemirror/theme-one-dark";
|
import { oneDark } from "@codemirror/theme-one-dark";
|
||||||
@@ -82,11 +82,23 @@ if (!state.javascript.value) {
|
|||||||
const fileName = state.currentFile.value;
|
const fileName = state.currentFile.value;
|
||||||
// maybe send fileName, src?
|
// maybe send fileName, src?
|
||||||
await ipc.sendMessage("updateFile", [fileName, src]);
|
await ipc.sendMessage("updateFile", [fileName, src]);
|
||||||
let js = await ipc.sendMessage("compile", [fileName]);
|
let js = await ipc.sendMessage("compile", [fileName, "javascript"]);
|
||||||
state.javascript.value = bundle(js);
|
state.javascript.value = bundle(js);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function refreshScheme() {
|
||||||
|
if (!state.scheme.value) {
|
||||||
|
let src = state.editor.value!.getValue();
|
||||||
|
console.log("SEND TO", iframe.contentWindow);
|
||||||
|
const fileName = state.currentFile.value;
|
||||||
|
// maybe send fileName, src?
|
||||||
|
await ipc.sendMessage("updateFile", [fileName, src]);
|
||||||
|
let scheme = await ipc.sendMessage("compile", [fileName, "scheme"]);
|
||||||
|
state.scheme.value = bundle(scheme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function runOutput() {
|
async function runOutput() {
|
||||||
await refreshJS()
|
await refreshJS()
|
||||||
const src = state.javascript.value;
|
const src = state.javascript.value;
|
||||||
@@ -153,15 +165,23 @@ function getSavedCode() {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RESULTS = "Output";
|
||||||
|
const JAVASCRIPT = "JS";
|
||||||
|
const SCHEME = "Scheme";
|
||||||
|
const CONSOLE = "Console";
|
||||||
|
const HELP = "Help";
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
output: signal(""),
|
output: signal(""),
|
||||||
toast: signal(""),
|
toast: signal(""),
|
||||||
javascript: signal(""),
|
javascript: signal(""),
|
||||||
|
scheme: signal(""),
|
||||||
messages: signal<string[]>([]),
|
messages: signal<string[]>([]),
|
||||||
editor: signal<AbstractEditor | null>(null),
|
editor: signal<AbstractEditor | null>(null),
|
||||||
dark: signal(false),
|
dark: signal(false),
|
||||||
files: signal<string[]>(["Tour.newt"]),
|
files: signal<string[]>(["Tour.newt"]),
|
||||||
currentFile: signal<string>(localStorage.currentFile ?? "Tour.newt"),
|
currentFile: signal<string>(localStorage.currentFile ?? "Tour.newt"),
|
||||||
|
selected: signal(localStorage.tab ?? RESULTS),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Monitor dark mode state (TODO - let user override system setting)
|
// Monitor dark mode state (TODO - let user override system setting)
|
||||||
@@ -264,7 +284,12 @@ const language: EditorDelegate = {
|
|||||||
}
|
}
|
||||||
setOutput(res.output)
|
setOutput(res.output)
|
||||||
// less flashy version
|
// less flashy version
|
||||||
ipc.sendMessage("compile", [fileName]).then(js => state.javascript.value = bundle(js));
|
if (state.selected.value === JAVASCRIPT)
|
||||||
|
ipc.sendMessage("compile", [fileName, "javascript"]).then(js => state.javascript.value = bundle(js));
|
||||||
|
if (state.selected.value === SCHEME)
|
||||||
|
ipc.sendMessage("compile", [fileName, "scheme"]).then(scheme=> state.scheme.value = scheme);
|
||||||
|
// UI will update
|
||||||
|
state.scheme.value = "";
|
||||||
return diags;
|
return diags;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("ERR", e);
|
console.log("ERR", e);
|
||||||
@@ -287,26 +312,26 @@ function Editor({ initialValue }: EditorProps) {
|
|||||||
return h("div", { id: "editor", ref });
|
return h("div", { id: "editor", ref });
|
||||||
}
|
}
|
||||||
|
|
||||||
// for extra credit, we could have a read-only monaco
|
interface ViewerProps {
|
||||||
function JavaScript() {
|
language: 'javascript' | 'scheme'
|
||||||
const text = state.javascript.value;
|
}
|
||||||
|
function SourceViewer({language}: ViewerProps) {
|
||||||
|
const text = state[language].value;
|
||||||
|
|
||||||
// return h("div", { id: "javascript" }, text);
|
// return h("div", { id: "javascript" }, text);
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
const editorView = useRef<EditorView>(null);
|
const editorView = useRef<EditorView>(null);
|
||||||
const themeRef = useRef<Compartment>(null);
|
const themeRef = useRef<Compartment>(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('JSEFFECT')
|
|
||||||
const container = ref.current!;
|
const container = ref.current!;
|
||||||
themeRef.current = new Compartment();
|
themeRef.current = new Compartment();
|
||||||
|
|
||||||
const editor = new EditorView({
|
const editor = new EditorView({
|
||||||
doc: text,
|
doc: text,
|
||||||
parent: container,
|
parent: container,
|
||||||
extensions: [
|
extensions: [
|
||||||
basicSetup,
|
basicSetup,
|
||||||
themeRef.current.of(state.dark.value ? oneDark : EditorView.baseTheme({})),
|
themeRef.current.of(state.dark.value ? oneDark : EditorView.baseTheme({})),
|
||||||
javascript(),
|
language == 'javascript' ? javascript() : scheme(),
|
||||||
EditorState.readOnly.of(true),
|
EditorState.readOnly.of(true),
|
||||||
EditorView.editable.of(false),
|
EditorView.editable.of(false),
|
||||||
],
|
],
|
||||||
@@ -347,16 +372,11 @@ function Console() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const RESULTS = "Output";
|
|
||||||
const JAVASCRIPT = "JS";
|
|
||||||
const CONSOLE = "Console";
|
|
||||||
const HELP = "Help";
|
|
||||||
|
|
||||||
function Tabs() {
|
function Tabs() {
|
||||||
const [selected, setSelected] = useState(localStorage.tab ?? RESULTS);
|
const selected = state.selected.value
|
||||||
const Tab = (label: string) => {
|
const Tab = (label: string) => {
|
||||||
let onClick = () => {
|
let onClick = () => {
|
||||||
setSelected(label);
|
state.selected.value = label;
|
||||||
localStorage.tab = label;
|
localStorage.tab = label;
|
||||||
};
|
};
|
||||||
let className = "tab";
|
let className = "tab";
|
||||||
@@ -365,20 +385,24 @@ function Tabs() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state.messages.value.length) setSelected(CONSOLE);
|
if (state.messages.value.length) state.selected.value = CONSOLE;
|
||||||
}, [state.messages.value]);
|
}, [state.messages.value]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selected === JAVASCRIPT && !state.javascript.value) refreshJS();
|
if (selected === JAVASCRIPT && !state.javascript.value) refreshJS();
|
||||||
}, [selected, state.javascript.value]);
|
if (selected === SCHEME && !state.scheme.value) refreshScheme();
|
||||||
|
}, [selected, state.javascript.value, state.scheme.value]);
|
||||||
|
|
||||||
let body;
|
let body;
|
||||||
switch (selected) {
|
switch (selected) {
|
||||||
case RESULTS:
|
case RESULTS:
|
||||||
body = h(Result, {});
|
body = h(Result, {});
|
||||||
break;
|
break;
|
||||||
|
case SCHEME:
|
||||||
|
body = h(SourceViewer, {language: 'scheme'});
|
||||||
|
break;
|
||||||
case JAVASCRIPT:
|
case JAVASCRIPT:
|
||||||
body = h(JavaScript, {});
|
body = h(SourceViewer, {language:'javascript'});
|
||||||
break;
|
break;
|
||||||
case CONSOLE:
|
case CONSOLE:
|
||||||
body = h(Console, {});
|
body = h(Console, {});
|
||||||
@@ -398,6 +422,7 @@ function Tabs() {
|
|||||||
{ className: "tabBar" },
|
{ className: "tabBar" },
|
||||||
Tab(RESULTS),
|
Tab(RESULTS),
|
||||||
Tab(JAVASCRIPT),
|
Tab(JAVASCRIPT),
|
||||||
|
Tab(SCHEME),
|
||||||
Tab(CONSOLE),
|
Tab(CONSOLE),
|
||||||
Tab(HELP),
|
Tab(HELP),
|
||||||
),
|
),
|
||||||
|
|||||||
1
playground/src/newt.d.ts
vendored
1
playground/src/newt.d.ts
vendored
@@ -5,3 +5,4 @@ export function LSP_checkFile(name: string): Diagnostic[];
|
|||||||
export function LSP_hoverInfo(name: string, row: number, col: number): HoverResult | boolean | null;
|
export function LSP_hoverInfo(name: string, row: number, col: number): HoverResult | boolean | null;
|
||||||
export function LSP_codeActionInfo(name: string, row: number, col: number): CodeAction[] | null;
|
export function LSP_codeActionInfo(name: string, row: number, col: number): CodeAction[] | null;
|
||||||
export function LSP_compileJS(name: string): string;
|
export function LSP_compileJS(name: string): string;
|
||||||
|
export function LSP_compileToScheme(name: string): string;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
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 { LSP_checkFile, LSP_codeActionInfo, LSP_compileJS, LSP_hoverInfo, LSP_updateFile } from './newt';
|
import { LSP_checkFile, LSP_codeActionInfo, LSP_compileJS, LSP_compileToScheme, LSP_hoverInfo, LSP_updateFile } from './newt';
|
||||||
|
|
||||||
const LOG = console.log
|
const LOG = console.log
|
||||||
|
|
||||||
@@ -25,7 +25,10 @@ const api: API = {
|
|||||||
},
|
},
|
||||||
hoverInfo: LSP_hoverInfo,
|
hoverInfo: LSP_hoverInfo,
|
||||||
codeActionInfo: LSP_codeActionInfo,
|
codeActionInfo: LSP_codeActionInfo,
|
||||||
compile: LSP_compileJS,
|
compile: (fn, lang) => {
|
||||||
|
if (lang == 'scheme') return LSP_compileToScheme(fn);
|
||||||
|
return LSP_compileJS(fn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleMessage = async function <K extends keyof API>(ev: { data: Message<K> }) {
|
const handleMessage = async function <K extends keyof API>(ev: { data: Message<K> }) {
|
||||||
|
|||||||
19
src/LSP.newt
19
src/LSP.newt
@@ -17,6 +17,7 @@ import Lib.ProcessDecl
|
|||||||
import Lib.Prettier
|
import Lib.Prettier
|
||||||
import Lib.Error
|
import Lib.Error
|
||||||
import Lib.CompileJS
|
import Lib.CompileJS
|
||||||
|
import Lib.CompileScheme
|
||||||
|
|
||||||
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`
|
||||||
@@ -278,7 +279,6 @@ compileJS fn = unsafePerformIO $ do
|
|||||||
when (st.baseDir /= base) $ \ _ => resetState base
|
when (st.baseDir /= base) $ \ _ => resetState base
|
||||||
repo <- lspFileSource
|
repo <- lspFileSource
|
||||||
(Right (top, src)) <- (do
|
(Right (top, src)) <- (do
|
||||||
putStrLn "woo"
|
|
||||||
mod <- processModule emptyFC repo Nil modName
|
mod <- processModule emptyFC repo Nil modName
|
||||||
docs <- compile
|
docs <- compile
|
||||||
let src = unlines $
|
let src = unlines $
|
||||||
@@ -290,4 +290,19 @@ compileJS fn = unsafePerformIO $ do
|
|||||||
modifyIORef state [ topContext := top ]
|
modifyIORef state [ topContext := top ]
|
||||||
pure $ js_castStr src
|
pure $ js_castStr src
|
||||||
|
|
||||||
#export updateFile checkFile hoverInfo codeActionInfo compileJS docSymbols
|
compileToScheme : String → JSObject
|
||||||
|
compileToScheme fn = unsafePerformIO $ do
|
||||||
|
let (base, modName) = decomposeName fn
|
||||||
|
st <- readIORef state
|
||||||
|
when (st.baseDir /= base) $ \ _ => resetState base
|
||||||
|
repo <- lspFileSource
|
||||||
|
(Right (top, src)) <- (do
|
||||||
|
mod <- processModule emptyFC repo Nil modName
|
||||||
|
docs <- compileScheme
|
||||||
|
let src = unlines 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 docSymbols compileToScheme
|
||||||
|
|||||||
Reference in New Issue
Block a user