github.com/coyove/nj@v0.0.0-20221110084952-c7f8db1065c3/playground.html (about)

     1  <!doctype html>
     2  
     3  <title>Playground</title>
     4  <meta charset="utf-8"/>
     5  <meta name="viewport" content="width=device-width, initial-scale=1.0">
     6  
     7  <style>
     8      * {
     9          box-sizing: border-box;
    10          font-size: 14px;
    11      }
    12      html, body {
    13          height: 100%;
    14          margin: 0;
    15      }
    16      #code {
    17          height: 100%;
    18          width: 100%;
    19          border: none;
    20          background-color: transparent;
    21          resize: none;
    22          font-family: Lucida Console, Monaco, Monospace;
    23      }
    24      .CodeMirror {
    25          height: 100% !important;
    26          background-color: #ffd !important;
    27          font-family: Lucida Console, Monaco, Monospace !important;
    28      }
    29      #input {
    30          position:absolute;
    31          left:0;
    32          top:32px;
    33          width:100%;
    34          bottom:33%;
    35      }
    36      #output {
    37          position: absolute;
    38          width: 100%;
    39          top: 67%;
    40          bottom: 0;
    41          overflow-y: scroll;
    42      }
    43      #output div {
    44          white-space: pre-wrap;
    45          word-break: break-all;
    46          padding: 0.2em 0.5em;
    47      }
    48      #output div.title {
    49          font-size: 90%;
    50          background: #eee;
    51      }
    52      #output div.content {
    53          font-family: Lucida Console, Monaco, Monospace;
    54          padding: 0.5em;
    55      }
    56  </style>
    57  
    58  <body>
    59    <div style="position:relative;height:100%">
    60      <div style="line-height: 32px;height:32px;padding:0 0.5em">
    61  	<button onclick="run()">Run (F9)</button>
    62      <select id='output_fields'>
    63          <option value="all">Return all</option>
    64          <option value="stdout">Stdout only</option>
    65          <option value="result">Results only</option>
    66      </select>
    67  	<span style="float:right">
    68          <select id='cm_cdn' onchange="localStorage.setItem('cdn',this.value);location.reload()">
    69              <option value="-">Plain editor</option>
    70              <option value="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.0">CodeMirror (cloudflare)</option>
    71              <option value="https://cdn.bootcdn.net/ajax/libs/codemirror/5.65.0">CodeMirror (bootcdn)</option>
    72          </select>
    73  	</span>
    74      </div>
    75      <div id="input">
    76  	<div style="border:solid 1px #aaa;border-width:1px 0 1px 0;height:100%;background: #ffd;">
    77  	    <textarea id="code">__CODE__</textarea>
    78  	</div>
    79      </div>
    80      <div id="output"></div>
    81    </div>
    82  </body>
    83  
    84  <script>
    85      var output = document.getElementById("output"), editor = document.getElementById('code');
    86      async function loadEditor(textarea, prefix) {
    87          prefix = prefix || localStorage.getItem('cdn') || "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.0"
    88          document.getElementById('cm_cdn').value = prefix;
    89          if (prefix == "-") {
    90              loadPlainEditor(editor);
    91              return;
    92          }
    93  
    94          if (window.EDITOR) return;
    95          var createScript = function(src, f) {
    96              return new Promise(function(resolve) {
    97                  var s = document.createElement("script")
    98                  s.onload = resolve; s.src = src;
    99                  document.body.appendChild(s);
   100              })
   101          }, createCSS = function(src, f) {
   102              return new Promise(function(resolve) {
   103                  var s = document.createElement("link")
   104                  s.onload = resolve; s.href = src; s.rel = 'stylesheet'; s.type = 'text/css'; s.media = 'all';
   105                  document.body.appendChild(s);
   106              })
   107          };
   108  
   109          await createScript(prefix + "/codemirror.min.js");
   110          await createScript(prefix + "/mode/lua/lua.min.js");
   111          await createScript(prefix + "/addon/hint/show-hint.min.js");
   112          await createCSS(prefix + "/codemirror.min.css");
   113          await createCSS(prefix + "/addon/hint/show-hint.min.css");
   114  
   115          const controlKeys = [
   116              8, 9, 13, 16, 17, 18, 19, 20, 27, 33, 34, 35, 36, 37, 38, 39, 40, 45, 46, 91, 92, 93, 107, 109, 110, 111, 112,
   117              113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 144, 145, 186, 187, 188, 189, 190, 191, 192, 220, 222,
   118          ];
   119          const keywords = [
   120              "and", "or", "local", "break", "continue", "else", "function", "lambda", "if", "elseif",
   121              "then", "end", "not", "return", "for", "while", "repeat", "until", "do", "in", "goto", "is",
   122          ]
   123          const names = [__NAMES__];
   124          CodeMirror.hint.lua = function(cm) {
   125              const cursor = cm.getCursor();
   126              const token = cm.getTokenAt(cursor);
   127              const word = (token.string.match(/\w+$/) || [token.string])[0];
   128              const candidates = names.concat(word == token.string ? keywords : []);
   129              const res = {from: cursor, to: cursor, list: []};
   130              for (const i in candidates) {
   131                  const raw = candidates[i];
   132                  const data = raw.replace(/\(.+\)\./, '');
   133                  if (data.startsWith(word))
   134                      res.list.push({text: data, displayText: raw})
   135              }
   136              if (token.string.length <= 1 || !word || keywords.includes(token.string)) {
   137                  res.list = [];
   138              } else {
   139                  CodeMirror.on(res, "pick", function(obj) {
   140                      const doc = window.EDITOR.getDoc(), w = obj.text;
   141                      window.EDITOR.execCommand("delWordBefore");
   142                      doc.replaceRange(keywords.includes(w) ? (w + ' ') : w, doc.getCursor());
   143                  });
   144              }
   145              return res;
   146          };
   147          window.EDITOR = CodeMirror.fromTextArea(textarea, {
   148              mode: 'lua',
   149              lineNumbers: true,
   150              smartIndent: true,
   151              indentUnit: 4,
   152              extraKeys: { "F9": run },
   153              hintOptions: { completeSingle: false },
   154          });
   155          window.EDITOR.on("keyup", function(editor, event) {
   156              var keyCode = parseInt(event.keyCode || event.which);
   157              var cursor = editor.getDoc().getCursor();
   158              var token = editor.getTokenAt(cursor);
   159              var word = editor.findWordAt(cursor); 
   160              var currentWord = editor.getRange(word.anchor, word.head);
   161  
   162              if (!editor.state.completionActive && !controlKeys.includes(keyCode) && token.type != 'number' && token.type != 'string') {
   163                  editor.showHint();
   164                  return;
   165              }
   166          });
   167      }
   168      loadEditor(code).then(function() {});
   169  
   170      function loadPlainEditor(editor) {
   171          editor.addEventListener('keydown', function(e) {
   172              var start = this.selectionStart, end = this.selectionEnd;
   173              if (e.key == 'Tab') {
   174                  e.preventDefault();
   175                  this.value = this.value.substring(0, start) + "\t" + this.value.substring(end);
   176                  this.selectionStart = this.selectionEnd = start + 1;
   177              }
   178              if (e.key == 'F9') {
   179                  e.preventDefault();
   180                  run();
   181              }
   182              if (e.key == 'Enter') {
   183                  var v = this.value.substring(0, start);
   184                  var idx = v.lastIndexOf('\n');
   185                  if (idx) {
   186                      v = v.substring(idx + 1)
   187                      var spaces = '';
   188                      for (var i = 0; i < v.length; i++) {
   189                          var c = v.charAt(i);
   190                          if (c == ' ' || c == '\t') 
   191                              spaces += c;
   192                          else
   193                              break;
   194                      }
   195                      if (spaces) {
   196                          e.preventDefault()
   197                          this.value = this.value.substring(0, start) + "\n" + spaces + this.value.substring(end);
   198                          this.selectionStart = this.selectionEnd = start + 1 + spaces.length;
   199                      }
   200                  }
   201              }
   202          });
   203      }
   204  
   205      function div(html, title) {
   206          var el = document.createElement("div");
   207          el.className = title ? 'title' : 'content';
   208          el.innerText = html;
   209          return el;
   210      }
   211  
   212      function run() {
   213          const outf = document.getElementById('output_fields').value;
   214          const code = encodeURIComponent(window.EDITOR ? window.EDITOR.getValue() : editor.value);
   215          localStorage.setItem('output', outf);
   216          fetch('?output=' + outf + '&code=' + code)
   217          .then(response => response.json())
   218          .then(function(data) {
   219              var el = output;
   220              el.innerHTML = '';
   221  
   222              if (data.error) {
   223                  el.appendChild(div("Error", true))
   224                  el.appendChild(div(data.error))
   225              } else if (data.result) {
   226                  el.appendChild(div("Results", true))
   227                  v = data.result;
   228                  el.appendChild(div(typeof v === 'object' ? JSON.stringify(v) : v));
   229              }
   230              if (data.stdout) {
   231                  el.appendChild(div("Stdout", true));
   232                  el.appendChild(div(data.stdout));
   233                  el.appendChild(div("Elapsed", true))
   234                  el.appendChild(div(data.elapsed + 's'));
   235              }
   236              if (data.opcode) {
   237                  el.appendChild(div("Compiled", true));
   238                  el.appendChild(div(data.opcode));
   239              }
   240              if (data.survey) {
   241                  el.appendChild(div("Survey", true));
   242                  el.appendChild(div(JSON.stringify(data.survey)));
   243              }
   244          });
   245      }
   246  
   247      document.getElementById('output_fields').value = localStorage.getItem('output') || 'all';
   248  </script>