github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/main_js.go (about) 1 //go:build js 2 // +build js 3 4 package main 5 6 import ( 7 "syscall/js" 8 9 "github.com/lmorg/murex/app" 10 _ "github.com/lmorg/murex/builtins" 11 "github.com/lmorg/murex/builtins/pipes/term" 12 "github.com/lmorg/murex/config/defaults" 13 "github.com/lmorg/murex/lang" 14 "github.com/lmorg/murex/shell" 15 "github.com/lmorg/murex/utils/ansi" 16 "github.com/lmorg/murex/utils/readline" 17 ) 18 19 const interactive = true 20 21 func main() { 22 startMurex() 23 24 js.Global().Set("wasmShellExec", wasmShellExec()) 25 js.Global().Set("wasmShellStart", wasmShellStart()) 26 js.Global().Set("wasmKeyPress", wasmKeyPress()) 27 28 wait := make(chan bool) 29 <-wait 30 } 31 32 func startMurex() { 33 lang.InitEnv() 34 35 // default config 36 defaults.Config(lang.ShellProcess.Config, interactive) 37 38 // compiled profile 39 defaultProfile() 40 } 41 42 // wasmShellExec returns a Promise 43 func wasmShellExec() js.Func { 44 return js.FuncOf(func(this js.Value, args []js.Value) interface{} { 45 block := args[0].String() 46 47 // Handler for the Promise: this is a JS function 48 // It receives two arguments, which are JS functions themselves: resolve and reject 49 handler := js.FuncOf(func(this js.Value, args []js.Value) interface{} { 50 resolve := args[0] 51 reject := args[1] 52 53 // Now that we have a way to return the response to JS, spawn a goroutine 54 // This way, we don't block the event loop and avoid a deadlock 55 go func() { 56 fork := lang.ShellProcess.Fork(lang.F_PARENT_VARTABLE | lang.F_NEW_MODULE | lang.F_NO_STDIN) 57 fork.FileRef.Source.Module = app.ShellModule 58 fork.Stderr = term.NewErr(ansi.IsAllowed()) 59 var err error 60 lang.ShellExitNum, err = fork.Execute([]rune(block)) 61 if err != nil { 62 errorConstructor := js.Global().Get("Error") 63 errorObject := errorConstructor.New(err.Error()) 64 reject.Invoke(errorObject) 65 } 66 resolve.Invoke("wasmShellExec(): " + block) 67 }() 68 69 // The handler of a Promise doesn't return any value 70 return nil 71 }) 72 73 // Create and return the Promise object 74 promiseConstructor := js.Global().Get("Promise") 75 return promiseConstructor.New(handler) 76 }) 77 } 78 79 // wasmShellStart starts the interactive shell as a Promise 80 func wasmShellStart() js.Func { 81 return js.FuncOf(func(this js.Value, args []js.Value) interface{} { 82 83 handler := js.FuncOf(func(this js.Value, args []js.Value) interface{} { 84 resolve := args[0] 85 //reject := args[1] 86 87 go func() { 88 resolve.Invoke("Starting interactive shell....") 89 shell.Start() 90 }() 91 92 // The handler of a Promise doesn't return any value 93 return nil 94 }) 95 96 // Create and return the Promise object 97 promiseConstructor := js.Global().Get("Promise") 98 return promiseConstructor.New(handler) 99 }) 100 } 101 102 // wasmKeyPress starts the interactive shell as a Promise 103 func wasmKeyPress() js.Func { 104 return js.FuncOf(func(this js.Value, args []js.Value) interface{} { 105 stdin := args[0].String() 106 107 handler := js.FuncOf(func(this js.Value, args []js.Value) interface{} { 108 //resolve := args[0] 109 //reject := args[1] 110 111 go func() { 112 readline.Stdin <- stdin 113 }() 114 115 // The handler of a Promise doesn't return any value 116 return nil 117 }) 118 119 // Create and return the Promise object 120 promiseConstructor := js.Global().Get("Promise") 121 return promiseConstructor.New(handler) 122 }) 123 }