Using JS-Interpreter makes this easier. Great.
The first step is to look up what variables exist. Obtaining a list from JS-Interpreter is not a great idea since the JavaScript runtime has lots and lots of global variables that are of no interest to the user. Rather than trying to filter that list down, it's more sensible to just ask Blockly for a list of variable names.
You've already found Blockly.getMainWorkspace().getAllVariableNames(). That's a great start, however, it returns the variable names as typed by the user, not the variable names as used in JavaScript. 95% of the time they are the same, but there are cases where the variable needs to be quietly renamed. For example if the user creates a variable named 'foo bar', that's not a legal JS variable name, so it gets renamed behind the scenes to 'foo_bar'. Thus each variable name needs to have its JS equivalent name looked up. This code should do it:
const varMap = {};
for (const name of Blockly.getMainWorkspace().getAllVariableNames()) {
varMap[name] = Blockly.JavaScript.getVariableName(name);
}
Call this code after the JS code has been generated, it won't work before generation. Now we have a map that looks something like this:
{
'foo bar': 'foo_bar',
'typeof': 'typeof2',
'♥': '_E2_99_A5',
}
[Calling Blockly.JavaScript.getVariableName results in some whining in the console about deprecation, I'll let someone else chime in on the right way to squelch that. Either way, it works.]
You can then iterate through this map using the keys to create the UI for your onscreen variable list. And you can also iterate through this map using the values to obtain the current variable contents from JS-Interpreter:
for (const name in varMap) {
const jsName = varMap[name];
const varContents = myInterpreter.getValueFromScope(jsName, myInterpreter.globalScope).toString();
[print `varContents` in your onscreen table for `name`]
}
Just run this loop after each JS-Interpreter step, or ten times a second, or however you wish to update your display.
Hope this helps!