0

I am creating a Pyodide Ace-editor Python code runner in which anything that is typed within ace pyodide will run. It works pretty well, however I am having an incredible amount of difficulty trying to put keyinterrupts in my current implementation as I use a text area to show output instead of Pyodide.console: https://pyodide.org/en/stable/usage/api/python-api/console.html. I want to effectivley redirect everything that I was outputting into textarea into pyodide console so I would be able to have keyinterrupts (atleast I believe it supports it). How would I be able to do it? Here is my code:

runner.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Pyodide in Action</title>
    <link rel="stylesheet" href="runner_style.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.4/ace.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.4/ext-static_highlight.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.4/ext-modelist.js"></script>
    <script src="https://unpkg.com/file-saver"></script>
    <script src="https://cdn.jsdelivr.net/pyodide/v0.23.2/full/pyodide.js"></script>
</head>
<body>
    <div class="container">
        <div class="one">
            <div id="editor" style="width: 900px;height:200px;"></div>
        </div>
    </div>
    <textarea readonly rows=10 cols=30 id=output style="margin: 0px; width: 900px; height: 180px; font-size: 16px;">Loading and compiling...</textarea><br>
    <div class="buttonContainer">
        <button id="runButton">Run</button>
        <button id="clearButton">Clear</button>
    </div>
    <script type="text/javascript" src="runner.js"></script>
</body>
</html>

runner.js:

var editor = ace.edit("editor");
var output_pane;

function setParams() {
    const queryString = new URLSearchParams(location.search);
    const initCode = queryString.get('initCode');

    if (initCode) {
        const decodedCode = decodeURIComponent(initCode);
        editor.setValue(decodedCode);
    }
}

loadPyodide().then((pyodide) => {
    // pyodide is now ready to use...
    globalThis.pyodide = pyodide;
    appendOutput('Python ready.\n');
});

// Override console.warn so that anything logged will go to textarea
console.warn = function(message) {
    console.log(message);
};
  
function appendOutput(msg) {
    // used to add program output to the textarea
    output_pane.value = output_pane.value + '\n' + msg;
    output_pane.scrollTop = output_pane.scrollHeight;
}

function configEditor(){
    // configure the ace editor to make it usable
    editor = ace.edit("editor");
    editor.setTheme("ace/theme/xcode");
    editor.session.setMode("ace/mode/python");
    editor.setShowPrintMargin(false);
    editor.setBehavioursEnabled(true);
    editor.setFontSize(13);
    editor.setAnimatedScroll(true);
    editor.setAutoScrollEditorIntoView(true);
    setParams();
}

function openCode(filePathToUse) {
    getCode(filePathToUse)
      .then(code => {
        var modelist = ace.require("ace/ext/modelist");
        var modeName = modelist.getModeForPath(filePathToUse).mode;
        editor.session.setMode(modeName);
        editor.session.setValue(code);
    })
      .catch(error => {
        console.error('Error occurred while opening the code:', error);
    });
}

async function runCode(code_to_run) {
    // Run the code thats within the editor so students can test
    console.logs = [];

    let promise = new Promise((resolve, reject) => {
        window.pyodide.runPython(code_to_run)
        resolve(true)
    }).catch(err => {
        console.log(err);
        appendOutput(console.logs.join('\n')); 
    });

    let result = await promise;
    if (result) { 
        appendOutput(console.logs.join('\n')); 
    }
}

//make a function getCode that takes in a file path and returns the code in that file as a string to use in ace
async function getCode(codeToGet) {
    try {
      const response = await fetch(codeToGet);
      const data = await response.text();
      return data;
    } catch (error) {
      console.error('Error occurred while opening the code:', error);
    }
}

document.addEventListener('DOMContentLoaded', (event) => {
    output_pane = document.getElementById("output");

    // Add event listeners for running the code the user types
    document.getElementById("runButton").addEventListener('click', function () {
        runCode(editor.getValue());
    });

    // Add event listeners for the clear button
    document.getElementById("clearButton").addEventListener('click', function () {
        output_pane.value = '';
    });

    // Capture the output from Pyodide and add it to an array
    console.stdlog = console.log.bind(console);
    console.logs = [];
    console.log = function(){
        console.logs.push(Array.from(arguments));
        console.stdlog.apply(console, arguments);
    }
    configEditor(); 
});

my css file if you want to completely replicate it:

#editor { 
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    width: 1225px;
    height: 200px;
}

.container {
    width: 80%;
    height: 200px;
    margin: auto;
    padding: 10px;
}
.one {
    width: 50%;
    height: 100px;
    float: left;
}
.two {
    margin-left: 50%;
    height: 500px;
}

.buttonContainer {
    width: 100%;
    text-align: left;
    display: inline
}

textarea {
    margin: 0px; 
    width: 750px; 
    height: 200px; 
    padding: 10px; /* Add padding inside the textarea */
    font-family: Arial, sans-serif; /* Set the font-family */
    font-size: 15px; /* Set the font-size */
    background-color: #fff; /* Set the background color */
    border: 1px solid #ccc; /* Set the border */
    border-radius: 4px; /* Add some border-radius */
    resize: vertical; /* Allow vertical resizing only */
    outline: none; /* Remove the default focus outline */
    transition: border-color 0.3s; /* Add transition effect to border color */
}

textarea:focus {
    border-color: #007bff;
}

#runButton, #clearButton {
    border-radius: 4px; /* Adjust the value to change the roundness of the corners */
    padding: 10px 20px;
    background-color: #ffffff;
    color: black;
    font-size: 15px;
    border: solid;
    cursor: pointer;
    display: inline-block;
    margin-right: 5px;
    margin-bottom: 5px;
}

#runButton:hover, #clearButton:hover {
    background-color: #ddd;
    color: black;
    transition: background-color 0.2s, color 0.2s;
}

I tried to follow Pyodides documentation on how console works to try to replicate the look of this example: https://pyodide.org/en/stable/console.html, except just have my code outputted there but there seems to be sparse documentation on how to do so.

Cr3jus
  • 1
  • 1

0 Answers0