Developers' Forum

Set "data-stdin" for "ace-interactive-code" via text field

Set "data-stdin" for "ace-interactive-code" via text field

by Andreas Haja -
Number of replies: 7

Hello and thanks a lot for the ace_inline editor. I believe that this is an awesome tool to present code to students. 

I am wondering wether the "data-stdin" property of "ace-interactive-code" elements could possibly be set via text field input. This would enable students to change the standard input text on the fly and observe how program behavior changes.

I have been trying several approaches to achieve this, but so far without success. 

Any ideas how this might work?

Best wishes, Andreas.

In reply to Andreas Haja

Re: Set "data-stdin" for "ace-interactive-code" via text field

by Richard Lobb -

I'm not quite sure what you're hoping to achieve but the short answer is probably that it can't be done. Programs that read from stdin are usually expected to behave interactively, with the task pausing until the user types something, then resuming. Users also expect to see the keyboard input echoed to standard output.

CodeRunner's 'run-in-sandbox' AJAX service, which is what the Ace-inline-filter is using, simply sends a complete job to the Jobe server which runs it and returns the results. There's no interactivity possible here. You can supply a text string to be used in lieu of keyboard input but Jobe just writes this to a file and runs the job with stdin redirected to that file. Input is not echoed to standard output so if there are, say, two successive reads from stdin with prompt strings Prompt A and Prompt B, the student will just see the output Prompt A Prompt B all on one line with no apparent input taking place. Unless they're carefully trained on what to expect, they will find this very confusing.

However, if you do have suitably-trained-up students you can possibly let them enter the standard input, say via a JavaScript dialogue box or, with a bit more effort, from an extra text field adjacent to the Ace code panel. The trick is to make use of the code-mapper attribute of the <pre> element, supplying it with a JavaScript function that asks the user for the standard input to be used in the run and then prefixing the code in some way that forces the entered string to become the standard input. In Python you can do that by tweaking the sys.stdin attribute.

It seems I can't demonstrate that within a forum posting page because the page gets sanitised, removing all the scripts and unknown HTML attributes. But here's the HTML, which you should be able to paste into more forgiving contexts on your server (e.g. description questions).

<script>
    function hackme(codeIn) {
        let s = prompt("stdin (use \\n for newline)?", "");
        s = s.replace('\\n', '\n');
        let codeOut = `import sys
from io import StringIO
stdin_data = u'''${s}
'''
sys.stdin = StringIO(stdin_data)
` + codeIn;
        return codeOut;
    };
    window.hackme = hackme;
</script>
<pre class="ace-interactive-code" data-code-mapper="hackme">name = input("What is your name? ")
age = int(input("How old are you? "))
print(f"Hi {name}. Next year you will be {age + 1}")
</pre>

In the case of Python you can improve things by prefixing the code with an alternative implementation of the input function that does echo stdin to stdout but you may not even by using Python and I doubt this is a good way to proceed anyway so I won't give the code.

If we want students to experiment with different input test data in a program we simply define a variable and tell the students to edit it. For example

your_name = "Angus"  # Experiment by changing this

In reply to Richard Lobb

Re: Set "data-stdin" for "ace-interactive-code" via text field

by Andreas Haja -
Hi Richard.

Thanks a lot for your super-quick answer. For a Python script, your solution works just great. However, I would like to provide a user-defined input string to a C++ program, so I'd really like to use the 'data-stdin' attribute and set it either via a text field or a Javascript popup. When I try to modify the pre-element via '.setAttribute("data-stdin", some_value_from_textfield) though, the change is not reflected in the ACE editor.

Might it be possible for you to point me into the right direction here?

Thanks again for your answer and best wishes from Germany!
In reply to Andreas Haja

Re: Set "data-stdin" for "ace-interactive-code" via text field

by Richard Lobb -
Ok, so you really want to do this ... 
 
I'm afraid you can't dynamically update the attributes of the element. The Ace-inline filter processes the HTML as soon as the page loads, identifies each of the visible element of class 'ace-interactive-code', fires up an Ace editor to display it, constructs the JavaScript to handle clicks on the Try it! button, and hides the <PRE> element. At this point the stdin and all other attributes are locked into the code. I can see that you might have expected to be able to change the attributes of the now-hidden PRE element but if I were to make all those attributes dynamic I'd have a lot more work to do managing things like font size and other Ace editor configuration parameters.

The only solution I've been able to come up with is to use the data-code-mapper function to dynamically load the required stdin from a textarea (or you could use a prompt dialogue box if you preferred) and to build a whole new C++ program that has that stdin string as well as the original program embedded within it as strings. It writes those two strings to files and then uses the system function to compile and run. 

Here's a working prototype though you'll undoubtedly need to polish it. And there may well be serious flaws I haven't considered - let me know.

Copy and paste the following into a suitably friendly Moodle page, viewed in HTML mode:

<h3>A C++ Try it! box with a text field for stdin</h3>
<div>
    <b>Enter your stdin here</b><br>
    <textarea id="stdin-text" rows="4" cols="60">Angus
10
</textarea>
    <pre class="ace-interactive-code" id="interactive-code" data-lang="cpp" data-code-mapper="hackme3">#include &lt;iostream&gt;
#include &lt;string&gt;

using namespace std;

int main() {
    string name;
    int age;
    cout &lt;&lt; "What's your name? ";
    cin &gt;&gt; name;
    cout &lt;&lt; "How old are you? ";
    cin &gt;&gt; age;
    cout &lt;&lt; "Hi " &lt;&lt; name &lt;&lt; ", next year you'll be " &lt;&lt; age + 1 &lt;&lt; endl;
}
    
</pre>
</div>

<script>
    function hackme3(codeIn) {
        let ta = document.getElementById('stdin-text');
        let stdin = ta.value;
        let codeOut = `#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int main() {
     fstream stdin_file;
     stdin_file.open("stdin.txt", fstream::out);
     stdin_file << R"__AARGH__(${stdin})__AARGH__" << endl;
     stdin_file.close();
     fstream prog_file;
     prog_file.open("prog.cpp", fstream::out);
     prog_file << R"__AARGH__(${codeIn})__AARGH__" << endl;
     prog_file.close();
     if (system("g++ prog.cpp -o prog") == 0) {
         system("./prog < stdin.txt");
     }
}
`;
        return codeOut;
    };
    window.hackme3 = hackme3;
</script>

I agree it looks like a rather complex solution to what might have seemed like an easy problem, but it's the best I can come up with. And I'm still a little baffled as to why you want to do this to your poor students.  :-) [Edit: silly joke. Having a textarea for setting stdin can actually be very useful with non-interactive programs and I intend changing the plugin to make this much easier. Watch this space - Richard]

In reply to Richard Lobb

Re: Set "data-stdin" for "ace-interactive-code" via text field

by Andreas Haja -
Hi Richard.

Thanks so much for this piece of code and for the time you spent on my problem. The code does exactly what I was looking for!

All the best and have a great day!
Andreas
In reply to Andreas Haja

Re: Set "data-stdin" for "ace-interactive-code" via text field

by Richard Lobb -
Hi Andreas.

Good to know it has proved useful. I had fun solving the problem but it was way harder than it should have been. And I've definitely warmed to the idea of having a textarea to define stdin - it could be very useful for non-interactive applications, e.g. in an algorithms course. I intend to make this sort of thing much easier. Sorry about the silly joke about your "poor students" (see edited version).

As highlighted by your question, the current data-stdin and data-files attributes aren't very useful. So my current plan for when I have a bit more time is to deprecate them both and add instead data-stdin-id and data-file-ids, which will specify the IDs of textarea elements to act as the sources of the text (dynamically of course).

“All problems in computer science can be solved by another level of indirection." - David Wheeler.

Thanks for leading me to what I hope is a significant improvement.

Richard
In reply to Richard Lobb

Re: Set "data-stdin" for "ace-interactive-code" via text field

by Andreas Haja -

Hello Richard. 

I see it exactly as you do: this extension would be a very interesting tool for an algorithm course or even for a beginners course, where the reaction of a program to different inputs could be checked very easily. 

One of the main advantages from my point of view is that students can run the code 1:1 on their own machines without having to make any changes in terms of terminal input/output. 

I'm looking forward to the extension you mentioned. 

Many greetings, Andreas

In reply to Andreas Haja

Re: Set "data-stdin" for "ace-interactive-code" via text field

by Richard Lobb -
Hi again Andreas

The extension is now available. Plus some hooks for uploading files (either actual files or pseudo-files/named strings). And min-lines/max-lines to limit size of Ace editor window. All these features are documented in the demo page.

Hope it all works. Please let me know if not.

Richard