<commit_before>package blobl

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os/exec"
	"runtime"

	"github.com/Jeffail/benthos/v3/internal/bloblang"
	"github.com/Jeffail/benthos/v3/internal/bloblang/parser"
	"github.com/urfave/cli/v2"
)

// TODO: When we upgrade to Go 1.16 we can use the new embed stuff.
const bloblangEditorPage = `<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Bloblang Editor</title>
    <style>
      html, body {
        background-color: #202020;
        margin: 0;
        padding: 0;
        height: 100%;
        width: 100%;
      }
      .panel {
        position: absolute;
        margin: 0;
      }
      .panel > h2 {
        position: absolute;
        text-align: center;
        width: 100px;
        background-color: #33352e;
        color: white;
        font-family: monospace;
        border-bottom: solid #a6e22e 2px;
      }
      #input, #output, #mapping {
        background-color: #33352e;
        height: 100%;
        width: 100%;
        overflow: auto;
        box-sizing: border-box;
        margin: 0;
        padding: 10px;
        font-size: 12pt;
        font-family: monospace;
        color: #fff;
        border: solid #33352e 2px;
      }
      textarea {
        resize: none;
      }
    </style>
  </head>
  <body>
    <div class="panel" style="top:0;bottom:50%;left:0;right:50%;padding:0 5px 5px 0">
      <h2 style="left:50%;bottom:0;margin-left:-50px;">Input</h2>
      <textarea id="input">{"message":"hello world"}</textarea>
    </div>
    <div class="panel" style="top:0;bottom:50%;left:50%;right:0;padding:0 0 5px 5px">
      <h2 style="left:50%;bottom:0;margin-left:-50px;">Output</h2>
      <pre id="output"></pre>
    </div>
    <div class="panel" style="top:50%;bottom:0;left:0;right:0;padding: 5px 0 0 0">
      <h2 style="left:50%;bottom:0;margin-left:-50px;">Mapping</h2>
      <textarea id="mapping">root = this</textarea>
    </div>
  </body>
  <script>
    function execute() {
        const request = new Request(window.location.href + 'execute', {
            method: 'POST',
            body: JSON.stringify({
                mapping: mappingArea.value,
                input: inputArea.value,
            }),
        });
        fetch(request)
            .then(response => {
                if (response.status === 200) {
                    return response.json();
                } else {
                    throw new Error('Something went wrong on api server!');
                }
            })
            .then(response => {
                const red = "#f92672";
                let result = "No result";
                inputArea.style.borderColor = "#33352e";
                mappingArea.style.borderColor = "#33352e";
                outputArea.style.color = "white";
                if (response.result.length > 0) {
                    result = document.createTextNode(response.result);
                } else if (response.mapping_error.length > 0) {
                    inputArea.style.borderColor = red;
                    outputArea.style.color = red;
                    result = document.createTextNode(response.mapping_error);
                } else if (response.parse_error.length > 0) {
                    mappingArea.style.borderColor = red;
                    outputArea.style.color = red;
                    result = document.createTextNode(response.parse_error);
                }
                outputArea.innerHTML = "";
                outputArea.appendChild(result);
            }).catch(error => {
                console.error(error);
            });
    }

    const mappingArea = document.getElementById("mapping");
    const inputArea = document.getElementById("input");
    const outputArea = document.getElementById("output");
    const inputs = document.getElementsByTagName('textarea');
    for (let input of inputs) {
        input.addEventListener('keydown', function(e) {
            if (e.key == 'Tab') {
                e.preventDefault();
                var start = this.selectionStart;
                var end = this.selectionEnd;

                // set textarea value to: text before caret + tab + text after caret
                this.value = this.value.substring(0, start) +
                    "\t" + this.value.substring(end);

                // put caret at right position again
                this.selectionStart =
                this.selectionEnd = start + 1;
            }
        });
        input.addEventListener('input', function(e) {
            execute();
        })
    }
    execute();
  </script>
</html>`

func openBrowserAt(url string) {
	switch runtime.GOOS {
	case "linux":<commit_msg>Use ace editor when possible<commit_after>package blobl

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os/exec"
	"runtime"

	"github.com/Jeffail/benthos/v3/internal/bloblang"
	"github.com/Jeffail/benthos/v3/internal/bloblang/parser"
	"github.com/urfave/cli/v2"
)

// TODO: When we upgrade to Go 1.16 we can use the new embed stuff.
const bloblangEditorPage = `<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Bloblang Editor</title>
    <style>
      html, body {
        background-color: #202020;
        margin: 0;
        padding: 0;
        height: 100%;
        width: 100%;
      }
      .panel {
        position: absolute;
        margin: 0;
      }
      .panel > h2 {
        position: absolute;
        text-align: center;
        width: 100px;
        background-color: #33352e;
        color: white;
        font-family: monospace;
        border-bottom: solid #a6e22e 2px;
      }
      #input, #output, #mapping {
        background-color: #33352e;
        height: 100%;
        width: 100%;
        overflow: auto;
        box-sizing: border-box;
        margin: 0;
        padding: 10px;
        font-size: 12pt;
        font-family: monospace;
        color: #fff;
        border: solid #33352e 2px;
      }
      #ace-mapping, #ace-input {
        font-size: 14pt;
        overflow: auto;
        box-sizing: border-box;
        margin: 0;
        padding: 0;
        height: 100%;
        width: 100%;
        border: solid #33352e 2px;
      }
      textarea {
        resize: none;
      }
    </style>
  </head>
  <body>
    <div class="panel" id="default-input-panel" style="top:0;bottom:50%;left:0;right:50%;padding:0 5px 5px 0">
      <h2 style="left:50%;bottom:0;margin-left:-50px;">Input</h2>
      <textarea id="input">{"message":"hello world"}</textarea>
    </div>
    <div class="panel" id="ace-input-panel" style="top:0;bottom:50%;left:0;right:50%;padding:0 5px 5px 0;display:none">
      <h2 style="left:50%;bottom:0;margin-left:-50px;z-index:100;background-color:#272822;">Input</h2>
      <div id="ace-input">{"message":"hello world"}</div>
    </div>
    <div class="panel" style="top:0;bottom:50%;left:50%;right:0;padding:0 0 5px 5px">
      <h2 style="left:50%;bottom:0;margin-left:-50px;">Output</h2>
      <pre id="output"></pre>
    </div>
    <div class="panel" id="default-mapping-panel" style="top:50%;bottom:0;left:0;right:0;padding: 5px 0 0 0">
      <h2 style="left:50%;bottom:0;margin-left:-50px;">Mapping</h2>
      <textarea id="mapping">root = this</textarea>
    </div>
    <div class="panel" id="ace-mapping-panel" style="top:50%;bottom:0;left:0;right:0;padding: 5px 0 0 0;display:none">
      <h2 style="left:50%;bottom:0;margin-left:-50px;z-index:100;background-color:#272822;">Mapping</h2>
      <div id="ace-mapping">root = this</div>
    </div>
  </body>
  <script>
    function execute() {
        const request = new Request(window.location.href + 'execute', {
            method: 'POST',
            body: JSON.stringify({
                mapping: getMapping(),
                input: getInput(),
            }),
        });
        fetch(request)
            .then(response => {
                if (response.status === 200) {
                    return response.json();
                } else {
                    throw new Error('Something went wrong on api server!');
                }
            })
            .then(response => {
                const red = "#f92672";
                let result = "No result";
                inputArea.style.borderColor = "#33352e";
                mappingArea.style.borderColor = "#33352e";
                outputArea.style.color = "white";
                if (response.result.length > 0) {
                    result = document.createTextNode(response.result);
                } else if (response.mapping_error.length > 0) {
                    inputArea.style.borderColor = red;
                    outputArea.style.color = red;
                    result = document.createTextNode(response.mapping_error);
                } else if (response.parse_error.length > 0) {
                    mappingArea.style.borderColor = red;
                    outputArea.style.color = red;
                    result = document.createTextNode(response.parse_error);
                }
                outputArea.innerHTML = "";
                outputArea.appendChild(result);
            }).catch(error => {
                console.error(error);
            });
    }

    var mappingArea = document.getElementById("mapping");
    var aceMappingEditor = null;
    function getMapping() {
      if (aceMappingEditor !== null) {
        return aceMappingEditor.getValue();
      }
      return mappingArea.value;
    }

    var inputArea = document.getElementById("input");
    var aceInputEditor = null;
    function getInput() {
      if (aceInputEditor !== null) {
        return aceInputEditor.getValue();
      }
      return inputArea.value;
    }

    const outputArea = document.getElementById("output");
    const inputs = document.getElementsByTagName('textarea');
    for (let input of inputs) {
        input.addEventListener('keydown', function(e) {
            if (e.key == 'Tab') {
                e.preventDefault();
                var start = this.selectionStart;
                var end = this.selectionEnd;

                // set textarea value to: text before caret + tab + text after caret
                this.value = this.value.substring(0, start) +
                    "\t" + this.value.substring(end);

                // put caret at right position again
                this.selectionStart = start + 1;
                this.selectionEnd = start + 1;
            }
        });
        input.addEventListener('input', function(e) {
            execute();
        })
    }
    execute();
  </script>

  <script src="https://pagecdn.io/lib/ace/1.4.12/ace.min.js" crossorigin="anonymous" integrity="<KEY>></script>
  <script src="https://pagecdn.io/lib/ace/1.4.12/theme-monokai.min.js" crossorigin="anonymous"></script>
  <script src="https://pagecdn.io/lib/ace/1.4.12/mode-coffee.min.js" crossorigin="anonymous"></script>
  <script src="https://pagecdn.io/lib/ace/1.4.12/mode-json.min.js" crossorigin="anonymous"></script>
  <script>
      aceMappingEditor = ace.edit("ace-mapping");
      aceMappingEditor.setTheme("ace/theme/monokai");
      aceMappingEditor.session.setUseWorker(false);
      aceMappingEditor.session.setMode("ace/mode/coffee");
      aceMappingEditor.on('change', execute);
      mappingArea = document.getElementById("ace-mapping");

      document.getElementById("default-mapping-panel").style.display = "none";
      document.getElementById("ace-mapping-panel").style.display = "initial";

      aceInputEditor = ace.edit("ace-input");
      aceInputEditor.setTheme("ace/theme/monokai");
      aceInputEditor.session.setUseWorker(false);
      aceInputEditor.session.setMode("ace/mode/json");
      aceInputEditor.on('change', execute);
      inputArea = document.getElementById("ace-input");

      document.getElementById("default-input-panel").style.display = "none";
      document.getElementById("ace-input-panel").style.display = "initial";
  </script>
</html>`

func openBrowserAt(url string) {
	switch runtime.GOOS {
	case "linux":
{'fraction_non_alphanumeric': 0.14183452638588315, 'fraction_numerical': 0.028633261195272184, 'mean_word_length': 2.0325593134780413, 'pattern_counts': {'":': 5, '<': 90, '<?xml version=': 0, '>': 104, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4122272', 'n_tokens_mistral': 3847, 'n_tokens_neox': 3513, 'n_words': 691}