@naanlang/naan 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/LICENSE.md +2 -2
  2. package/README.md +2 -2
  3. package/bin/index.js +7 -3
  4. package/dist/env_web.js +162 -48
  5. package/dist/naan.min.js +11 -11
  6. package/frameworks/browser/https_request.nlg +2 -2
  7. package/frameworks/browser/sworker.js +28 -26
  8. package/frameworks/browser/terminals.nlg +295 -737
  9. package/frameworks/browser/worker.nlg +295 -0
  10. package/frameworks/browser/workers.nlg +6 -6
  11. package/frameworks/browser/ws_client.nlg +15 -10
  12. package/frameworks/client/apiclient.nlg +211 -9
  13. package/frameworks/client/psm_client.nlg +10 -14
  14. package/frameworks/client/relaycon.nlg +87 -161
  15. package/frameworks/common/common.nlg +2 -0
  16. package/frameworks/common/events.nlg +101 -0
  17. package/frameworks/common/repltools.nlg +80 -1
  18. package/frameworks/node/apiserver.nlg +38 -246
  19. package/frameworks/node/filesystem.nlg +31 -6
  20. package/frameworks/node/http_request.nlg +34 -13
  21. package/frameworks/node/https_request.nlg +8 -3
  22. package/frameworks/node/node.nlg +3 -0
  23. package/frameworks/node/pty.nlg +346 -0
  24. package/frameworks/node/shell.nlg +26 -3
  25. package/frameworks/node/worker.nlg +504 -560
  26. package/frameworks/node/ws_client.nlg +2 -2
  27. package/frameworks/project/build.nlg +56 -14
  28. package/frameworks/project/projects.nlg +1 -1
  29. package/frameworks/running/debugcom.nlg +20 -3
  30. package/frameworks/running/debugnub.nlg +33 -11
  31. package/frameworks/running/executors.nlg +40 -285
  32. package/frameworks/running/instances.nlg +394 -0
  33. package/frameworks/running/remote_req.nlg +139 -0
  34. package/frameworks/running/remote_res.nlg +89 -0
  35. package/frameworks/running/sourcecode.nlg +3 -2
  36. package/frameworks/running/taskexec.nlg +16 -59
  37. package/frameworks/service/imp.nlg +751 -0
  38. package/frameworks/service/model.nlg +71 -0
  39. package/frameworks/service/nubnode.nlg +136 -0
  40. package/frameworks/service/nubweb.nlg +124 -0
  41. package/frameworks/service/service.nlg +28 -0
  42. package/frameworks/storage/file_manager.nlg +3 -2
  43. package/lib/browser/env_web.js +169 -55
  44. package/lib/browser/env_webworker.js +89 -31
  45. package/lib/core/naanlib.js +11 -11
  46. package/lib/env_node.js +186 -27
  47. package/lib/env_nodeworker.js +82 -44
  48. package/lib/node_server_init.nlg +149 -0
  49. package/lib/node_worker.js +36 -0
  50. package/lib/node_worker_init.nlg +43 -0
  51. package/package.json +1 -1
  52. package/plugins/openSearch/openSearch.nlg +3 -2
  53. package/plugins/openSearch/os_dynamo.nlg +3 -2
  54. package/plugins/serviceAws/aws_cloudwatchlogs.nlg +44 -2
  55. package/plugins/serviceAws/aws_dynamo.nlg +144 -63
  56. package/plugins/serviceAws/aws_utils.nlg +6 -11
  57. package/plugins/serviceAws/serviceAws.nlg +3 -2
  58. package/plugins/serviceNexara/speechrec.nlg +10 -6
  59. package/test/test_01_core.nlg +2 -2
  60. package/test/test_02_context.nlg +32 -9
  61. package/test/test_03_jsinterop.nlg +3 -3
  62. package/test/test_07_lingo.nlg +1 -1
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2017-2024 by Richard C. Zulch
9
+ * Copyright (c) 2017-2026 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -69,6 +69,7 @@ exports.NaanControllerWeb = function() {
69
69
 
70
70
  var naanlib = new exports.Naanlib();
71
71
  var dontSaveUntilWorking; // true when state loaded, must be reset to save state again
72
+ var dontSave; // true to avoid saving, i.e. in debugger
72
73
  var contSelf = this; // this is us, for access within nested functions
73
74
  exports.naancon = this; // access to this instance
74
75
  contSelf.anaan = naanlib.js.n;
@@ -93,8 +94,8 @@ exports.NaanControllerWeb = function() {
93
94
  function termTextOut(text, level) {
94
95
  if (!text)
95
96
  return;
96
- if (termlist.length === 0) {
97
- console.log(text); // make sure we can see early errors
97
+ if (termlist.length === 0) { // make sure we can see early errors
98
+ console.log(text.replace(/(?:\x1B[@-Z\\-_]|\x1B\[[0-?]*[ -/]*[@-~])/g, ''));
98
99
  if (!replqueue)
99
100
  replqueue = [];
100
101
  replqueue.push({text:text, level:level});
@@ -137,7 +138,7 @@ exports.NaanControllerWeb = function() {
137
138
 
138
139
 
139
140
  //==========================================================================
140
- // New Terminal Interface
141
+ // Direct Terminal Interface
141
142
  //--------------------------------------------------------------------------
142
143
 
143
144
  //
@@ -170,6 +171,7 @@ exports.NaanControllerWeb = function() {
170
171
  if (repdex < 0)
171
172
  termlist.push(terminal);
172
173
  takePending(); // output all pending terminal messages
174
+ this.ioctl_event("term-attach", terminal.guid);
173
175
  };
174
176
 
175
177
  //
@@ -184,6 +186,7 @@ exports.NaanControllerWeb = function() {
184
186
  termlist.splice(repdex, 1);
185
187
  if (termlist.length === 0)
186
188
  replstate = terminal.StateSave(); // save ultimate repl state
189
+ this.ioctl_event("term-detach", terminal.guid);
187
190
  };
188
191
 
189
192
  //
@@ -217,24 +220,6 @@ exports.NaanControllerWeb = function() {
217
220
  }, 1);
218
221
  };
219
222
 
220
- var replyHook;
221
- this.OnReplyHook = function OnReplyHook(proc) {
222
- replyHook = proc;
223
- return (proc);
224
- };
225
-
226
- this.ReplyMessage = function ReplyMessage(data) { // "remote" -> "local"
227
- if (replyHook)
228
- setTimeout(function() {
229
- replyHook(data);
230
- }, 1);
231
- termlist.forEach(function(term) {
232
- if (term.OnMessageOut)
233
- term.OnMessageOut(data);
234
- });
235
- return (data);
236
- };
237
-
238
223
  var nideListener;
239
224
  this.OnMessage = function OnMessage(proc) {
240
225
  nideListener = proc;
@@ -339,13 +324,14 @@ exports.NaanControllerWeb = function() {
339
324
  function ConsoleDebugTerminal() {
340
325
  var termSelf = this;
341
326
  //
342
- // OnMessageOut
327
+ // OnMessage
343
328
  //
344
329
  this.OnMessage = function OnMessage(msg) {
330
+ var text = msg.text.replace(/(?:\x1B[@-Z\\-_]|\x1B\[[0-?]*[ -/]*[@-~])/g, '');
345
331
  if (msg.id == "debugtext")
346
- console.log("dbug-" + msg.level + " " + msg.text);
332
+ console.log("dbug-" + msg.level + " " + text);
347
333
  else if (msg.id == "textout")
348
- console.log(msg.text);
334
+ console.log(text);
349
335
  };
350
336
  //
351
337
  // cmd
@@ -391,30 +377,37 @@ exports.NaanControllerWeb = function() {
391
377
  exports.debug = debug;
392
378
 
393
379
  //==========================================================================
394
- // Clone Debug Interface
380
+ // MessageTerminal
395
381
  //--------------------------------------------------------------------------
396
382
 
397
- function CloneDebugTerminal()
383
+ function MessageTerminal(windest, origin)
398
384
  {
399
385
  var termSelf = this;
400
386
  //
401
387
  // listen for messages
402
388
  //
403
389
  window.addEventListener("message", function (event) {
404
- if (event.origin !== window.origin)
390
+ if (origin && event.origin !== origin)
405
391
  return; // only talk with our peers
406
392
  var msg = event.data;
393
+ if (msg.scope != "naan-env-web")
394
+ return;
407
395
  if (msg.id == "interrupt")
408
396
  contSelf.Interrupt();
409
397
  else if (msg.id == "keyline")
410
398
  contSelf.Return(msg.text, termSelf); // keyboard text from terminal
411
- else if (msg.id == "start")
412
- contSelf.Attach(term); // opener is ready
399
+ else if (msg.id == "typed")
400
+ echoTyped(msg.text);
401
+ else if (msg.id == "attached")
402
+ contSelf.Attach(messageTerm); // start using the terminal
403
+ else if (msg.id == "detached")
404
+ contSelf.Detach(messageTerm); // done using the terminal
413
405
  else if (msg.id == "import")
414
406
  { // for workers
415
407
  }
416
408
  else if (msg.id == "targetin")
417
409
  {
410
+ console.log("env_web targetin");
418
411
  if (nideListener)
419
412
  nideListener(msg.data); // target received a message
420
413
  }
@@ -423,32 +416,24 @@ exports.NaanControllerWeb = function() {
423
416
  if (debugListener)
424
417
  debugListener(msg.data); // target received a message
425
418
  }
419
+ else if (msg.id == "ioctl-event")
420
+ contSelf.ioctl_event(msg.msg, msg.arg);
426
421
  });
427
422
 
428
423
  //
429
424
  // report messages back to opener
430
425
  //
431
426
  termSelf.OnMessage = function OnMessage(msg) {
432
- window.opener.postMessage(msg, window.origin);
427
+ msg.scope = "naan-env-web";
428
+ windest.postMessage(msg, origin);
433
429
  return (msg);
434
430
  };
435
431
 
436
- //
437
- // report messages back to opener
438
- //
439
- termSelf.OnMessageOut = function OnMessageOut(data) {
440
- var msg = { // target is sending debug data
441
- id: "targetout",
442
- data: data
443
- };
444
- return (termSelf.OnMessage(msg));
445
- };
446
-
447
432
  //
448
433
  // report debug messages back to opener
449
434
  //
450
435
  termSelf.OnDebugOut = function OnDebugOut(data) {
451
- var msg = { // target is sending debug data
436
+ var msg = { // target is sending debug data
452
437
  id: "debugout",
453
438
  data: data
454
439
  };
@@ -459,14 +444,129 @@ exports.NaanControllerWeb = function() {
459
444
  // report status back to opener
460
445
  //
461
446
  termSelf.OnStatus = function OnStatus(status) {
462
- var msg = { // target is sending debug data
447
+ var msg = { // target is sending debug data
463
448
  id: "status",
464
449
  status: status
465
450
  };
466
451
  return (termSelf.OnMessage(msg));
467
452
  };
453
+
454
+ //
455
+ // stub to ignore call
456
+ //
457
+ termSelf.StateSave = function StateSave() {
458
+ return (false);
459
+ };
460
+
461
+ //
462
+ // send ioctl back to terminal
463
+ //
464
+ termSelf.ioctl = function ioctl(op, arg) {
465
+ var msg = {
466
+ id: "ioctl",
467
+ op: op,
468
+ arg: arg
469
+ };
470
+ return (termSelf.OnMessage(msg));
471
+ };
472
+
473
+ listen_all.push(function(imsg, arg) {
474
+ var msg = { // target is sending ioctl event
475
+ id: "ioctl_event",
476
+ msg: imsg,
477
+ arg: arg
478
+ };
479
+ return (termSelf.OnMessage(msg));
480
+ });
468
481
  }
469
482
 
483
+ //==========================================================================
484
+ // ioctl terminal control
485
+ //--------------------------------------------------------------------------
486
+
487
+ var listen_all = [];
488
+ var listeners = { };
489
+ var ioctl_callback;
490
+
491
+ //
492
+ // ioctl_open
493
+ //
494
+ // A terminal controller is now open on our instance.
495
+ //
496
+
497
+ this.ioctl_open = function ioctl_open(callback) {
498
+ ioctl_callback = callback;
499
+ return (true);
500
+ };
501
+
502
+ //
503
+ // ioctl_close
504
+ //
505
+ // The terminal controller is no longer open on our instance.
506
+ //
507
+
508
+ this.ioctl_close = function ioctl_close() {
509
+ ioctl_callback = false;
510
+ return (true);
511
+ };
512
+
513
+ //
514
+ // ioctl_event
515
+ //
516
+ // Events incoming from terminal.
517
+ //
518
+
519
+ this.ioctl_event = function ioctl_event(msg, arg) {
520
+ listen_all.forEach(function(proc) {
521
+ proc(msg, arg);
522
+ });
523
+ if (listeners[msg])
524
+ listeners[msg].forEach(function(proc) {
525
+ proc(msg, arg);
526
+ });
527
+ };
528
+
529
+ //
530
+ // ioctl_add_listener
531
+ // ioctl_remove_listener
532
+ //
533
+ // Add a listener for a terminal event.
534
+ //
535
+
536
+ this.ioctl_add_listener = function ioctl_add_listener(msg, proc) {
537
+ if (typeof(msg) != "string" || typeof(proc) != "function")
538
+ return (false);
539
+ this.ioctl_remove_listener(msg, proc);
540
+ if (!listeners[msg])
541
+ listeners[msg] = [];
542
+ listeners[msg].push(proc);
543
+ return (true);
544
+ };
545
+
546
+ this.ioctl_remove_listener = function ioctl_remove_listener(msg, proc) {
547
+ if (typeof(msg) != "string" || typeof(proc) != "function")
548
+ return (false);
549
+ if (listeners[msg]) {
550
+ var index = listeners[msg].indexOf(proc);
551
+ if (index >= 0)
552
+ listeners[msg].splice(index, 1);
553
+ }
554
+ return (true);
555
+ };
556
+
557
+ //
558
+ // ioctl
559
+ //
560
+ // Control of terminals (and their controller.)
561
+ //
562
+
563
+ this.ioctl = function ioctl(op, arg) {
564
+ if (ioctl_callback)
565
+ ioctl_callback(op, arg);
566
+ messageTerm.ioctl(op, arg);
567
+ return (true);
568
+ };
569
+
470
570
  //==========================================================================
471
571
  // Host Environment
472
572
  //--------------------------------------------------------------------------
@@ -501,6 +601,16 @@ exports.NaanControllerWeb = function() {
501
601
  dontSaveUntilWorking = false;
502
602
  };
503
603
 
604
+ //
605
+ // Saving
606
+ //
607
+ // Turn state saving on or off; on by default.
608
+ //
609
+
610
+ this.Saving = function Saving(onOff) {
611
+ dontSave = !onOff;
612
+ };
613
+
504
614
  window.document.addEventListener("visibilitychange", function (e) {
505
615
  virtualVisibilityChange();
506
616
  if (window.document.visibilityState == "hidden") {
@@ -514,7 +624,7 @@ exports.NaanControllerWeb = function() {
514
624
  statedoc.curversion = kStateCurrentVersion;
515
625
  statedoc.firstver = kStateFirstVersion;
516
626
  statedoc.licensee = "MIT-License";
517
- statedoc.verstring = "1.5.0+1";
627
+ statedoc.verstring = "1.7.0+1";
518
628
  statedoc.date = new Date().toISOString();
519
629
  statedoc.prefs = prefs;
520
630
  statedoc.naan = naanlib.saveState(false); // true to optimize, which is a bit slower
@@ -532,7 +642,7 @@ exports.NaanControllerWeb = function() {
532
642
  || statedoc.firstver > kStateCurrentVersion
533
643
  || statedoc.curversion < kStateFirstVersion
534
644
  || statedoc.licensee != "MIT-License"
535
- || statedoc.verstring != "1.5.0+1"
645
+ || statedoc.verstring != "1.7.0+1"
536
646
  || !(naanstate = statedoc.naan))
537
647
  {
538
648
  localStorage.removeItem("NaanState_Hosted");
@@ -550,8 +660,12 @@ exports.NaanControllerWeb = function() {
550
660
  localStorage.removeItem("NaanState_Hosted");
551
661
  return (false);
552
662
  }
663
+ if (dontSave)
664
+ return (false); // not saving right now
553
665
  if ("nosave" in querystrings)
554
666
  return (false);
667
+ if (window.opener)
668
+ return (false); // don't save running under NaanIDE
555
669
  var statedoc = makeState();
556
670
  var statestr = JSON.stringify(statedoc);
557
671
  try {
@@ -591,7 +705,7 @@ exports.NaanControllerWeb = function() {
591
705
  op: "VsiteOpen",
592
706
  name: vsiteName,
593
707
  naancont: contSelf,
594
- title: vsiteName + " 1.5.0+1"
708
+ title: vsiteName + " 1.7.0+1"
595
709
  });
596
710
  }
597
711
  } catch (e) {
@@ -605,7 +719,7 @@ exports.NaanControllerWeb = function() {
605
719
  op: "VsiteClose",
606
720
  name: vsiteName,
607
721
  naancont: contSelf,
608
- title: vsiteName + " 1.5.0+1"
722
+ title: vsiteName + " 1.7.0+1"
609
723
  });
610
724
  termTextOut("\x1b[90m\x1b[3m".concat("\nwindow closed", "\x1b[0m\n"));
611
725
  }
@@ -621,7 +735,7 @@ exports.NaanControllerWeb = function() {
621
735
  op: "VsiteVisibilityChange",
622
736
  name: vsiteName,
623
737
  naancont: contSelf,
624
- title: vsiteName + " 1.5.0+1",
738
+ title: vsiteName + " 1.7.0+1",
625
739
  hidden: window.document.visibilityState == "hidden",
626
740
  window: window
627
741
  });
@@ -636,8 +750,8 @@ exports.NaanControllerWeb = function() {
636
750
  naanlib.banner();
637
751
  var hostpath = window.location.origin.concat(naanlib.js.r("path").dirname(window.location.pathname));
638
752
  naanlib.start({
639
- cmd: 'App.version = "1.5.0+1";;\r\n'
640
- + 'App.cache = "8a52678888a755df427e58396a70e4f9";;\r\n'
753
+ cmd: 'App.version = "1.7.0+1";;\r\n'
754
+ + 'App.cache = "1bae92ceb3cc5eb47f6dbe8e40ceeb9f";;\r\n'
641
755
  + 'Naan.module.requireQuery({ naanver: App.cache });;\r\n'
642
756
  + 'Naan.module.webparse("naan_init.nlg", "' + hostpath + '", { naanver: App.cache });;\r\n'
643
757
  });
@@ -655,11 +769,11 @@ exports.NaanControllerWeb = function() {
655
769
 
656
770
  if (window.opener) {
657
771
  virtualOpen();
658
- var term = new CloneDebugTerminal();
659
- term.OnMessage({
660
- id: "loaded"
661
- });
662
772
  }
773
+ var messageTerm = new MessageTerminal(window, window.origin);
774
+ messageTerm.OnMessage({
775
+ id: "loaded"
776
+ });
663
777
  };
664
778
 
665
779
  /*jshint sub:true */
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2019-2025 by Richard C. Zulch
9
+ * Copyright (c) 2019-2026 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -45,20 +45,27 @@ exports.NaanControllerWebWorker = function NaanControllerWebWorker() {
45
45
  var targSelf = this; // this is us, for access within nested functions
46
46
  targSelf.anaan = naanlib.js.n;
47
47
  naanlib.js.t = targSelf;
48
-
48
+ var workerMetadata = { };
49
+
49
50
  //
50
51
  // Communications
51
52
  //
52
53
 
54
+ targSelf.metadata = function metadata() { // our creation metadata
55
+ return (workerMetadata);
56
+ };
57
+
53
58
  naanlib.onText(function(text, level) {
54
59
  if (level)
55
60
  postMessage({
61
+ scope: "naan-env-web",
56
62
  id: "debugtext",
57
63
  text: text,
58
64
  level: level
59
65
  });
60
66
  else
61
67
  postMessage({
68
+ scope: "naan-env-web",
62
69
  id: "textout",
63
70
  text: text
64
71
  });
@@ -68,6 +75,7 @@ exports.NaanControllerWebWorker = function NaanControllerWebWorker() {
68
75
  var samples = naanlib.status(1);
69
76
  if (samples.length > 0)
70
77
  postMessage({ // periodic worker status
78
+ scope: "naan-env-web",
71
79
  id: "status",
72
80
  status: {
73
81
  sample: samples[0]
@@ -75,36 +83,15 @@ exports.NaanControllerWebWorker = function NaanControllerWebWorker() {
75
83
  });
76
84
  }, 1000);
77
85
 
78
- targSelf.ReplyMessage = function ReplyMessage(data) {
79
- postMessage({ // target is sending a message
80
- id: "targetout",
81
- data: data
82
- });
83
- return (data);
84
- };
85
-
86
86
  var targetListener;
87
87
  targSelf.OnMessage = function OnMessage(proc) {
88
88
  targetListener = proc;
89
89
  return (proc);
90
90
  };
91
91
 
92
- this.DispatchMessage = function DispatchMessage(data) {
93
- postMessage({ // target is sending a message
94
- id: "targetsend",
95
- data: data
96
- });
97
- return (data);
98
- };
99
-
100
- var targetReceiver;
101
- targSelf.OnReceive = function OnReceive(proc) {
102
- targetReceiver = proc;
103
- return (proc);
104
- };
105
-
106
92
  targSelf.ReplyDebugger = function ReplyDebugger(data) {
107
93
  postMessage({ // target is sending debug data
94
+ scope: "naan-env-web",
108
95
  id: "debugout",
109
96
  data: data
110
97
  });
@@ -119,6 +106,7 @@ exports.NaanControllerWebWorker = function NaanControllerWebWorker() {
119
106
 
120
107
  targSelf.Download = function Download(bits, name, options) {
121
108
  postMessage({ // tell browser host to download a file
109
+ scope: "naan-env-web",
122
110
  id: "download",
123
111
  bits: bits,
124
112
  name: name,
@@ -129,6 +117,7 @@ exports.NaanControllerWebWorker = function NaanControllerWebWorker() {
129
117
 
130
118
  targSelf.Terminate = function Terminate(result) {
131
119
  postMessage({ // terminate this worker from worker
120
+ scope: "naan-env-web",
132
121
  id: "termination",
133
122
  result: result
134
123
  });
@@ -136,16 +125,20 @@ exports.NaanControllerWebWorker = function NaanControllerWebWorker() {
136
125
  return (result);
137
126
  };
138
127
 
139
- onmessage = function(e) {
128
+ addEventListener("message", function(e) {
140
129
  var msg = e.data;
130
+ if (msg.scope != "naan-env-web")
131
+ return;
141
132
  if (msg.id == "interrupt")
142
133
  naanlib.escape();
143
134
  else if (msg.id == "keyline")
144
135
  naanlib.textLine(msg.text); // keyboard text from terminal
136
+ else if (msg.id == "typed")
137
+ echoTyped(msg.text);
145
138
  else if (msg.id == "start")
146
139
  { // start execution with optional state
147
140
  targSelf.workerID = msg.workerID;
148
- targSelf.workerGUID = msg.workerGUID;
141
+ workerMetadata = msg.metadata || { };
149
142
  naanlib.banner();
150
143
  naanlib.start({
151
144
  state: msg.state,
@@ -156,6 +149,7 @@ exports.NaanControllerWebWorker = function NaanControllerWebWorker() {
156
149
  importScripts(msg.script); // load any desired script
157
150
  else if (msg.id == "targetin")
158
151
  {
152
+ console.log("env_webworker targetin");
159
153
  if (targetListener)
160
154
  targetListener(msg.data); // target received a message
161
155
  }
@@ -164,18 +158,82 @@ exports.NaanControllerWebWorker = function NaanControllerWebWorker() {
164
158
  if (debugListener)
165
159
  debugListener(msg.data); // target received a message
166
160
  }
167
- else if (msg.id == "targetreceive")
168
- {
169
- if (targetReceiver)
170
- targetReceiver(msg.data);
161
+ else if (msg.id == "attached")
162
+ targSelf.ioctl_event("term-attach", msg.guid);
163
+ else if (msg.id == "detached")
164
+ targSelf.ioctl_event("term-detach", msg.guid);
165
+ else if (msg.id == "ioctl-event")
166
+ targSelf.ioctl_event(msg.msg, msg.arg);
167
+ });
168
+
169
+ //==========================================================================
170
+ // ioctl terminal control
171
+ //--------------------------------------------------------------------------
172
+
173
+ var listeners = { };
174
+
175
+ //
176
+ // ioctl_event
177
+ //
178
+ // Events incoming from terminal.
179
+ //
180
+
181
+ targSelf.ioctl_event = function ioctl_event(msg, arg) {
182
+ if (listeners[msg])
183
+ listeners[msg].forEach(function(proc) {
184
+ proc(msg, arg);
185
+ });
186
+ };
187
+
188
+ //
189
+ // ioctl_add_listener
190
+ // ioctl_remove_listener
191
+ //
192
+ // Add a listener for a terminal event.
193
+ //
194
+
195
+ targSelf.ioctl_add_listener = function ioctl_add_listener(msg, proc) {
196
+ if (typeof(msg) != "string" || typeof(proc) != "function")
197
+ return (false);
198
+ targSelf.ioctl_remove_listener(msg, proc);
199
+ if (!listeners[msg])
200
+ listeners[msg] = [];
201
+ listeners[msg].push(proc);
202
+ return (true);
203
+ };
204
+
205
+ targSelf.ioctl_remove_listener = function ioctl_remove_listener(msg, proc) {
206
+ if (typeof(msg) != "string" || typeof(proc) != "function")
207
+ return (false);
208
+ if (listeners[msg]) {
209
+ var index = listeners[msg].indexOf(proc);
210
+ if (index >= 0)
211
+ listeners[msg].splice(index, 1);
171
212
  }
213
+ return (true);
172
214
  };
173
-
215
+
216
+ //
217
+ // ioctl
218
+ //
219
+ // Control of terminals (and their controller.)
220
+ //
221
+
222
+ targSelf.ioctl = function ioctl(op, arg) {
223
+ postMessage({
224
+ scope: "naan-env-web",
225
+ id: "ioctl",
226
+ op: op,
227
+ arg: arg
228
+ });
229
+ };
230
+
174
231
  //
175
232
  // Initialization complete
176
233
  //
177
234
 
178
235
  postMessage({
236
+ scope: "naan-env-web",
179
237
  id: "loaded"
180
238
  });
181
239
  };