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  }