Skip to content

Output logs in playground #865

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6dd763d
wip: running custom code
diogomqbm May 28, 2021
e7ae99d
feat: running code 🥳
diogomqbm May 28, 2021
d8f94fb
Merge branch 'master' of github.com:rescript-association/rescript-lan…
diogomqbm Aug 7, 2021
f8130b5
feat: bundling stdlib
diogomqbm Aug 7, 2021
68e141a
fix: fixing ci
diogomqbm Aug 7, 2021
4610bf3
feat: better ux
diogomqbm Aug 11, 2021
17c002f
chore: removing useless deps
diogomqbm Aug 11, 2021
6c9709c
chore: removing useless file
diogomqbm Aug 11, 2021
108b6f6
chore: better method name
diogomqbm Aug 11, 2021
c0ec898
fix: adjusting iframe height
diogomqbm Aug 11, 2021
26a44b0
Merge branch 'master' of github.com:rescript-association/rescript-lan…
diogomqbm Sep 25, 2021
f9fb41a
fix: safelly checking for import and exports
diogomqbm Sep 25, 2021
72a856f
refactor: better naming
diogomqbm Sep 25, 2021
4a8de4d
chore: adjusting code style
diogomqbm Aug 12, 2022
8341fbe
refactor: moving logic to RenderOutputManager
diogomqbm Aug 12, 2022
e78ad7a
Merge branch 'master' into playgroud-output-result-rebase-aspeddro
aspeddro Jul 26, 2023
8bdb556
remove .mjs files
aspeddro Jul 26, 2023
c8ad064
Merge branch 'master' into playgroud-output-result-rebase-aspeddro
aspeddro Dec 31, 2023
866f237
add log
aspeddro Dec 31, 2023
0edfffb
update
aspeddro Dec 31, 2023
ad9aefa
Merge branch 'master' into playgroud-output-result-rebase-aspeddro
aspeddro Feb 25, 2024
124c474
update
aspeddro Feb 27, 2024
bf2572f
WIP output console log
tsnobip May 23, 2024
35c3982
Merge remote-tracking branch 'upstream/master' into HEAD
tsnobip May 23, 2024
d3f8cae
complete console and react output
tsnobip May 23, 2024
72e8419
polish log output
tsnobip May 23, 2024
3c5d224
explicitly add acorn as a dependency
tsnobip May 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,350 changes: 2,210 additions & 140 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
"@rescript/core": "^1.3.0",
"@rescript/react": "^0.12.0-alpha.3",
"@rescript/tools": "^0.5.0",
"acorn": "^8.11.3",
"codemirror": "^5.54.0",
"docson": "^2.1.0",
"escodegen": "^2.1.0",
"eslint-config-next": "^13.1.1",
"fuse.js": "^6.4.3",
"gentype": "^3.44.0",
Expand Down Expand Up @@ -71,4 +73,4 @@
"simple-functional-loader": "^1.2.1",
"tailwindcss": "^3.3.3"
}
}
}
63 changes: 63 additions & 0 deletions src/ConsolePanel.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
type logLevel = [
| #log
| #warn
| #error
]

@react.component
let make = (~compilerState, ~runOutput) => {
let (logs, setLogs) = React.useState(_ => [])

React.useEffect(() => {
let cb = e => {
let data = e["data"]
switch data["type"] {
| #...logLevel as logLevel =>
let args: array<string> = data["args"]
setLogs(previous => previous->Belt.Array.concat([(logLevel, args)]))
| _ => ()
}
}
Webapi.Window.addEventListener("message", cb)
Some(() => Webapi.Window.removeEventListener("message", cb))
}, [])

React.useEffect(() => {
if runOutput {
switch compilerState {
| CompilerManagerHook.Ready({result: Comp(Success({js_code}))}) =>
setLogs(_ => [])
let ast = AcornParse.parse(js_code)
let transpiled = AcornParse.removeImportsAndExports(ast)
EvalIFrame.sendOutput(transpiled)
| _ => ()
}
}
None
}, (compilerState, runOutput))

<div>
{switch logs {
| [] => React.null
| logs =>
let content =
logs
->Belt.Array.mapWithIndex((i, (logLevel, log)) => {
let log = Js.Array2.joinWith(log, " ")
<pre
key={RescriptCore.Int.toString(i)}
className={switch logLevel {
| #log => ""
| #warn => "text-orange"
| #error => "text-fire"
}}>
{React.string(log)}
</pre>
})
->React.array

<div className="whitespace-pre-wrap p-4 block"> content </div>
}}
<EvalIFrame />
</div>
}
135 changes: 107 additions & 28 deletions src/Playground.res
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ open CompilerManagerHook
module Api = RescriptCompilerApi

type layout = Column | Row
type tab = JavaScript | Problems | Settings
type tab = JavaScript | Problems | Settings | Console
let breakingPoint = 1024

module DropdownSelect = {
Expand Down Expand Up @@ -1054,6 +1054,20 @@ module Settings = {
}

module ControlPanel = {
let codeFromResult = (result: FinalResult.t): string => {
open Api
switch result {
| FinalResult.Comp(comp) =>
switch comp {
| CompilationResult.Success({js_code}) => js_code
| UnexpectedError(_)
| Unknown(_, _)
| Fail(_) => "/* No JS code generated */"
}
| Nothing
| Conv(_) => "/* No JS code generated */"
}
}
module Button = {
@react.component
let make = (~children, ~onClick=?) =>
Expand Down Expand Up @@ -1134,8 +1148,11 @@ module ControlPanel = {
~state: CompilerManagerHook.state,
~dispatch: CompilerManagerHook.action => unit,
~editorCode: React.ref<string>,
~runOutput,
~toggleRunOutput,
) => {
let router = Next.Router.useRouter()

let children = switch state {
| Init => React.string("Initializing...")
| SwitchingCompiler(_ready, _version) => React.string("Switching Compiler...")
Expand Down Expand Up @@ -1168,12 +1185,14 @@ module ControlPanel = {
Next.Router.replace(router, url)
url
}
<>
<div className="mr-2">
<Button onClick=onFormatClick> {React.string("Format")} </Button>
</div>

<div className="flex flex-row gap-x-2">
<ToggleButton checked=runOutput onChange={_ => toggleRunOutput()}>
{React.string("Auto-run")}
</ToggleButton>
<Button onClick=onFormatClick> {React.string("Format")} </Button>
<ShareButton actionIndicatorKey createShareLink />
</>
</div>
| _ => React.null
}

Expand All @@ -1193,28 +1212,75 @@ let locMsgToCmError = (~kind: CodeMirror.Error.kind, locMsg: Api.LocMsg.t): Code
}
}

module OutputPanel = {
let codeFromResult = (result: FinalResult.t): string => {
open Api
switch result {
| FinalResult.Comp(comp) =>
switch comp {
| CompilationResult.Success({js_code}) => js_code
| UnexpectedError(_)
| Unknown(_, _)
| Fail(_) => "/* No JS code generated */"
}
| Nothing
| Conv(_) => "/* No JS code generated */"
}
}
// module RenderOutput = {
// @react.component
// let make = (~compilerState: CompilerManagerHook.state) => {
// React.useEffect(() => {
// let code = switch compilerState {
// | Ready(ready) =>
// switch ready.result {
// | Comp(Success(_)) => ControlPanel.codeFromResult(ready.result)->Some
// | _ => None
// }
// | _ => None
// }

// let _valid = switch code {
// | Some(code) =>
// switch RenderOutputManager.renderOutput(code) {
// | Ok(_) => true
// | Error(_) => false
// }
// | None => false
// }
// None
// }, [compilerState])

// <div className={""}>
// <iframe
// width="100%"
// id="iframe-eval"
// className="relative w-full text-gray-20"
// srcDoc=RenderOutputManager.Frame.srcdoc
// />
// </div>

// // switch code {
// // | Some(code) =>
// // switch RenderOutputManager.renderOutput(code) {
// // | Ok() =>
// // <iframe
// // width="100%"
// // id="iframe-eval"
// // className="relative w-full text-gray-20"
// // srcDoc=RenderOutputManager.Frame.srcdoc
// // />
// // | Error() =>
// // let code = `module App = {
// // @react.component
// // let make = () => {
// // <ModuleName />
// // }
// // }`
// // <div className={"whitespace-pre-wrap p-4 block"}>
// // <p className={"mb-2"}> {React.string("To render element create a module App")} </p>
// // <pre> {HighlightJs.renderHLJS(~code, ~darkmode=true, ~lang="rescript", ())} </pre>
// // </div>
// // }

// // | _ => React.null
// // }
// }
// }

module OutputPanel = {
@react.component
let make = (
~compilerDispatch,
~compilerState: CompilerManagerHook.state,
~editorCode: React.ref<string>,
~currentTab: tab,
~runOutput,
) => {
/*
We need the prevState to understand different
Expand All @@ -1232,17 +1298,18 @@ module OutputPanel = {
| (_, Ready({result: Nothing})) => None
| (Ready(prevReady), Ready(ready)) =>
switch (prevReady.result, ready.result) {
| (_, Comp(Success(_))) => codeFromResult(ready.result)->Some
| (_, Comp(Success(_))) => ControlPanel.codeFromResult(ready.result)->Some
| _ => None
}
| (_, Ready({result: Comp(Success(_)) as result})) => codeFromResult(result)->Some
| (_, Ready({result: Comp(Success(_)) as result})) =>
ControlPanel.codeFromResult(result)->Some
| (Ready({result: Comp(Success(_)) as result}), Compiling(_, _)) =>
codeFromResult(result)->Some
ControlPanel.codeFromResult(result)->Some
| _ => None
}
| None =>
switch compilerState {
| Ready(ready) => codeFromResult(ready.result)->Some
| Ready(ready) => ControlPanel.codeFromResult(ready.result)->Some
| _ => None
}
}
Expand Down Expand Up @@ -1322,7 +1389,12 @@ module OutputPanel = {

prevSelected.current = selected

let tabs = [(JavaScript, output), (Problems, errorPane), (Settings, settingsPane)]
let tabs = [
(Console, <ConsolePanel compilerState runOutput />),
(JavaScript, output),
(Problems, errorPane),
(Settings, settingsPane),
]

let body = Belt.Array.mapWithIndex(tabs, (i, (tab, content)) => {
let className = currentTab == tab ? "block h-inherit" : "hidden"
Expand Down Expand Up @@ -1700,10 +1772,12 @@ let make = (~versions: array<string>) => {
"flex-1 items-center p-4 border-t-4 border-transparent " ++ activeClass
}

let tabs = [JavaScript, Problems, Settings]
let tabs = [JavaScript, Console, Problems, Settings]

let headers = Belt.Array.mapWithIndex(tabs, (i, tab) => {
let title = switch tab {
// | RenderOutput => "Render Output"
| Console => "Console"
| JavaScript => "JavaScript"
| Problems => "Problems"
| Settings => "Settings"
Expand All @@ -1722,12 +1796,17 @@ let make = (~versions: array<string>) => {
</button>
})

let (runOutput, setRunOutput) = React.useState(() => false)
let toggleRunOutput = () => setRunOutput(prev => !prev)

<main className={"flex flex-col bg-gray-100 overflow-hidden"}>
<ControlPanel
actionIndicatorKey={Belt.Int.toString(actionCount)}
state=compilerState
dispatch=compilerDispatch
editorCode
runOutput
toggleRunOutput
/>
<div
className={`flex ${layout == Column ? "flex-col" : "flex-row"}`}
Expand Down Expand Up @@ -1782,7 +1861,7 @@ let make = (~versions: array<string>) => {
{React.array(headers)}
</div>
<div ref={ReactDOM.Ref.domRef(subPanelRef)} className="overflow-auto">
<OutputPanel currentTab compilerDispatch compilerState editorCode />
<OutputPanel currentTab compilerDispatch compilerState editorCode runOutput />
</div>
</div>
</div>
Expand Down
7 changes: 7 additions & 0 deletions src/bindings/AcornParse.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type t
@module("../ffi/acorn-parse.js") external parse: string => t = "parse"

@module("../ffi/acorn-parse.js") external hasEntryPoint: t => bool = "hasEntryPoint"

@module("../ffi/acorn-parse.js")
external removeImportsAndExports: t => string = "removeImportsAndExports"
10 changes: 10 additions & 0 deletions src/bindings/Webapi.res
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module Document = {
@val external document: Dom.element = "document"
@scope("document") @val external createElement: string => Dom.element = "createElement"
@scope("document") @val external createTextNode: string => Dom.element = "createTextNode"
}
Expand All @@ -17,6 +18,15 @@ module Element = {
@send external getBoundingClientRect: Dom.element => {..} = "getBoundingClientRect"
@send external addEventListener: (Dom.element, string, unit => unit) => unit = "addEventListener"

@send
external getElementById: (Dom.element, string) => Js.nullable<Dom.element> = "getElementById"

type contentWindow
@get external contentWindow: Dom.element => option<contentWindow> = "contentWindow"

@send
external postMessage: (contentWindow, string, ~targetOrigin: string=?) => unit = "postMessage"

module Style = {
@scope("style") @set external width: (Dom.element, string) => unit = "width"
@scope("style") @set external height: (Dom.element, string) => unit = "height"
Expand Down
Loading