Skip to content

gh-136251: Improvements to WASM demo REPL #136252

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open

Conversation

adqm
Copy link

@adqm adqm commented Jul 3, 2025

I'm including a couple of fixes for the WASM demo, which for me made the demo "just work" out of the box for me with a build from following the instructions on this page:

  • Exported HEAPU32 at build time since python.worker.mjs expects it to be there (for determining the version number)
  • Updated the HTML to properly load xterm.js

I also made a few changes to try to improve the usability of the web REPL, also included here:

  • Reset things when starting a new process (without this change, running the same program multiple times would not work, requiring a refresh)
  • Added support for arrow key navigation (and home/end) in the REPL (including history scrollback)
  • Added support for TAB and CTRL+C, trying to mimic the behavior of the regular of those inputs from the Python REPL
  • Replaced the textarea with Ace code editor.
  • Moved the demo to index.html instead of python.html so that the URL shown in the terminal when running server.py takes you to the demo (without needing to append /python.html)

I also put up a demo here that shows the result of a fresh Emscripten build with these changes.

There's definitely still room for improvement here (for example, #124621 suggests updating the demo to use PyREPL), but I'm sharing these changes in case they're useful in the meantime.

Related Issue: #136251

@python-cla-bot
Copy link

python-cla-bot bot commented Jul 3, 2025

All commit authors signed the Contributor License Agreement.

CLA signed

@bedevere-app
Copy link

bedevere-app bot commented Jul 3, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@adqm adqm requested a review from brettcannon as a code owner July 3, 2025 17:52
@bedevere-app
Copy link

bedevere-app bot commented Jul 3, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@bedevere-app
Copy link

bedevere-app bot commented Jul 3, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@bedevere-app
Copy link

bedevere-app bot commented Jul 3, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

Copy link
Member

@sobolevn sobolevn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a full review, just saw some style problems :)

@brettcannon brettcannon removed their request for review July 3, 2025 21:01
@bedevere-app
Copy link

bedevere-app bot commented Jul 3, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@adqm
Copy link
Author

adqm commented Jul 3, 2025

thanks, @sobolevn! i just ran prettier on that file; it looks like it caught those style issues and quite a few more.

@bedevere-app
Copy link

bedevere-app bot commented Jul 3, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@merwok
Copy link
Member

merwok commented Jul 8, 2025

The demo does not work on Firefox!

@adqm
Copy link
Author

adqm commented Jul 8, 2025

I just now tested on both Firefox 140.0.4 and 128.11.0esr, and it seems to be working for me, both the demo I linked above and a completely-fresh local build.

What version of Firefox are you running? And can you provide any more specifics about the way in which the demo is not working for you?

@merwok
Copy link
Member

merwok commented Jul 9, 2025

128.11.0esr here (debian) with advanced third-party tracking protection, ublock, privacy badger…

ACE code editor works, but nothing happens when I try to run code. The js console shows:

ReferenceError: SharedArrayBuffer is not defined [python.worker.mjs:5:5](https://hz.mit.edu/wasm_repl_demo/python.worker.mjs)

@adqm
Copy link
Author

adqm commented Jul 9, 2025

128.11.0esr here (debian) with advanced third-party tracking protection, ublock, privacy badger…

That's remarkably similar to my setup, so I'm surprised that it isn't working...but I guess depending on what you mean by "advanced third-party tracking protection," it's possible that you're ending up with SharedArrayBuffer disabled (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements). From a little poking around online, it does seem like that restriction on SharedArrayBuffer is specific to Firefox.

Maybe it's worth adding an error message if we notice that SharedArrayBuffer is disabled, rather than failing silently. But given that error message, I don't think this is related to these changes (i.e., I would expect the demo as it existed before my changes to be broken for you as well).

@merwok
Copy link
Member

merwok commented Jul 9, 2025

On the page, window.crossOriginIsolated is false and WorkerGlobalContext undefined

@adqm
Copy link
Author

adqm commented Jul 9, 2025

Right. I guess what I'm thinking currently is that this is likely not an issue with the demo not playing nicely with Firefox per se, but maybe with your specific configuration. For example, I'm running on Debian with "Strict" privacy mode, ublock origin, privacy badger, canvas blocker, etc., but the demo is working for me on multiple machines. I'm wondering what the difference could be...do you maybe have dom.postMessage.sharedArrayBuffer.withCOOP_COEP set to false in your about:config? Setting that to false and then restarting Firefox caused the demo to fail for me with that same error message.

@hoodmane hoodmane self-requested a review July 9, 2025 16:13
@hoodmane
Copy link
Contributor

hoodmane commented Jul 9, 2025

Did you use server.py from the wasm_example directory to serve it? It sets COOP and COEP which should make window.crossOriginIsolated true.

@@ -2334,7 +2334,7 @@ AS_CASE([$ac_sys_system],

dnl Include file system support
AS_VAR_APPEND([LINKFORSHARED], [" -sFORCE_FILESYSTEM -lidbfs.js -lnodefs.js -lproxyfs.js -lworkerfs.js"])
AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_RUNTIME_METHODS=FS,callMain,ENV"])
AS_VAR_APPEND([LINKFORSHARED], [" -sEXPORTED_RUNTIME_METHODS=FS,callMain,ENV,HEAPU32"])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you provide more information? I made this change since python.worker.mjs is currently trying to look in HEAPU32 to find Python's version info but it wasn't accessible (in my original builds, I just manually edited python.worker.mjs to hard-code the version number to make things work).

I'm guessing from "Oops," though, that this isn't the right way to fix this? First time messing with Emscripten/WASM at all, so if you don't mind, more context would be appreciated.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hoodmane The "oops" comment is ambiguous to me as well - just to confirm, this is an "oops, HEAPU32 should definitely be included, how did I miss that?", rather than or "oops, this shouldn't be included"?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry for the unclear communication. Change is correct.

this is an "oops, HEAPU32 should definitely be included, how did I miss that?"

Exactly.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the confusion; I definitely initially interpreted it the other way 😅 But glad to know I wasn't making a stupid mistake!

@merwok
Copy link
Member

merwok commented Jul 9, 2025

I used the published demo linked in the PR description, not local server.
I have the coep option set to true 🙁

Let’s ignore my issue for now then…

@adqm
Copy link
Author

adqm commented Jul 9, 2025

🫤 hmm...i'm definitely still a little bothered that it isn't working for you (and really curious what the issue is!). hopefully we'll be able to get some more datapoints. and regardless, thanks for the testing and code review so far!

@hoodmane
Copy link
Contributor

@merwok was it working for you before this change?

@adqm
Copy link
Author

adqm commented Jul 11, 2025

@merwok, if it helps, here is a build from before I made my changes: https://hz.mit.edu/wasm_repl_demo_old/python.html. That one only has two changes from the main branch, required to make the demo work at all: closing the <script> tag for loading xterm.js, and hard-coding the version number in python.worker.js instead of trying to figure it out by looking in Module.HEAPU32.

I'm pretty confident that I didn't change anything here that would affect Firefox's ability to load the page, but certainly worth checking. That said, I would also be interested to know whether a local build works for you if you're able to give that a try, in case there's something weird about how my machine is serving things (though I do think I'm sending the right headers).

If it's desirable, I can also add some kind of error message to the demo in the case where SharedArrayBuffer is not available.

@hoodmane
Copy link
Contributor

hoodmane commented Jul 11, 2025

I'm pretty confident that I didn't change anything here that would affect Firefox's ability to load the page

I agree.

I can also add some kind of error message to the demo in the case where SharedArrayBuffer is not available.

Please do. Let's add a link to this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements

Comment on lines +252 to +254
this.xterm.write(
"\x1b[" + (this.cursorPosition + 4) + "D",
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native console also writes out KeyboardInterrupt when you press CTRL+C, why not do that here too?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can definitely add that. I had thought about it initially but felt like it was awkward for me just to print that when Python wasn't actually ever seeing the CTRL+C. But I think you're right that it would be good to mimic what people see at the normal REPL. I can make that change.

writeLine(line) {
this.xterm.write(line.slice(0, -1));
this.xterm.write("\r\n");
return line;
}

handleCursorInsert(data) {
this.input += data;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's handleCursorInsert() do?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's responsible for handling the case where we inputted a printable character (when a keypress doesn't get caught by one of the special handlers, it falls down to this function).

this.input = this.input.slice(0, -1);
this.xterm.write("\x1B[D");
this.xterm.write("\x1B[P");
const trailing = this.input.slice(this.cursorPosition);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this change do?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is part of the backspace handler (though there's similar code for adding a character, and for the delete key). Now that we have the ability to use the arrow keys to move around within a line, we need something like this to make sure that if we backspace/delete/insert in the middle of a line we can still see all of the characters that come after the one we just deleted.

@@ -269,6 +462,16 @@
}
return new Promise((resolve, reject) => {
this.resolveInput = (value) => {
if (value.replace(/\s/g, "").length != 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally it would be nice to save the history when refreshing. Maybe add a "TODO"? (Not to imply that anyone will ever do it.)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's definitely easy to change things so that the history persists if you do multiple iterations of "Start REPL" followed by "Stop". I actually kind of went out of my way to clear the history between REPL sessions.

Saving history across reloads also probably wouldn't be too terribly hard if we wanted that; we could shove the history into sessionStorage so that it would persist through a regular refresh but get cleared on closing the tab or (I believe) on a hard reload of the page. Happy to give that a shot if you think it's worthwhile.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think saving the history is nice... particularly combined with reverse search! But it's up to you if you want to bother.

Copy link
Contributor

@hoodmane hoodmane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried it out and it works great. Thanks! Left some minor comments/questions.

@adqm
Copy link
Author

adqm commented Jul 11, 2025

Great; thanks for taking a look! I'll make some of those changes and ping here again when it's ready for another look.

@merwok
Copy link
Member

merwok commented Jul 11, 2025

That’s useful, thanks! the older demo (that you published) has the same issue for me.

For running locally, I have a 3.13 build that’s a few months old, but have never done the wasm/emscripten build, and probably won’t have the time to look into it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy