Function to execute after an error in a script occurs, but only for scripts that are not "user input". Typical use is to do "show terminal" on the Layout, so the user can see the error there.
Function to execute after an error in a script occurs, but only for scripts that are not "user input". Typical use is to do "show terminal" on the Layout, so the user can see the error there.
Private Optional afterFunction to execute after a script is executed.
Function to execute after a script is executed.
Private Optional changechange event handler, saved for removing listener.
change event handler, saved for removing listener.
Private errorHolds the error message from last eval()
Private evalNumber of simultaneous calls to eval() for detecting recursion
Private hasWhether the alertOnce function has happened.
Private histindex of item last recalled from session history array; or -1 otherwise.
Private history_session history of scripts entered.
Private keykeydown event handler, saved for removing listener.
keydown event handler, saved for removing listener.
Private prompt_The prompt to show before each user-input command.
Private regexs_Set of regular expressions to apply to each script to replace short names
with full expanded name. For example, DoubleRect is the short name that
expands to myphysicslab.lab.util.DoubleRect.
Private resultContains results of last script. Can be referred to in Terminal as result.
Private resultContains saved results when eval is being called recursively.
Private term_terminal input, usually a text input field.
Private term_terminal output, usually a textarea
The variables available to the user. Names separated by | symbol.
Private verbose_Whether to print the expanded or unexpanded script. Seeing the expanded script is useful for debugging, or for understanding how Terminal works.
An object that scripts can store properties into.
See The z Object.
Note that an app might specify it's own z object, which would shorten the
long name to be app.z.foo instead of app.terminal.z.foo.
Adds a regular expression rule for transforming scripts before they are executed.
One usage is to prepend the namespace to fully qualify a short name.
For example, to transform DoubleRect into myphysicslab.lab.util.DoubleRect
terminal.addRegex('DoubleRect', `myphysicslab.lab.util.');
Another usage is to make properties of an object available as a single short name.
For example to transform rod or bob into app.rod or app.bob
terminal.addRegex('rod|bob', 'app.');
The regular expression rule is added to the end of the list of regex's to execute,
unless opt_prepend is true.
set of names separated by | symbol
the string to prepend to each occurence of the names
Optional opt_addToVars: booleanif true, then the set of names is added to the
set of defined names returned by vars; default is true
Optional opt_prepend: booleanif true, then the regex rule is added to the front
of the list of regex's to execute; default is false
whether the regex rule was added (returns false if the regex rule
already exists)
Adds a regular expression rule for transforming scripts before they are executed.
the RegExp to find
the replacement expression
Optional opt_prepend: booleanif true, then the regex rule is added to the front
of the list of regex's to execute; default is false
whether the regex rule was added (returns false if the regex rule
already exists)
Adds to the set of defined names returned by vars
string to add to white list
Shows an alert with the given message, but only the first time it is called. This prevents infinite loop of alerts. An example where that can happen is if an error occurs during a blur or focus event, which can then repeat after the user dismisses the alert which causes further blur/focus events.
the message to show
Executes the given script and returns the result.
When output is true: updates the result variable, prints the result in the
output text area, scrolls the output so the most recent text is visible, clears the
input text area, remembers the script in the session history.
When output is false: the result variable is updated for
successive scripts (separated by a semicolon) in the same script line, but after the
script is finished executing the result variable is unchanged. The output text area
and session history array are unchanged.
The output=false option allows for evaluating scripts that
define a variable, for example in
FunctionVariable.
The FunctionVariable script can be executed frequently without modifying the result
seen by the user in Terminal.
The script is split into pieces separated by top-level semicolons (top-level means they
are not enclosed by braces). Each fragment is first offered to the Parser installed
with setParser. If the Parser does not recognize the fragment, then
the fragment is expanded expand before being executed
using JavaScript eval.
Error handling: when showAlert is false we avoid throwing an error and only
print the error to the output text area where the user will presumably see it. When
showAlert is true we show an alert with the error message.
eval() never throws an error because the error message would be lost in that
process. Because of CORS policy (Cross-origin Resource Sharing) browsers only report
the message "Script error." Therefore we instead show an alert to the user here
with the error text. This can happen for example on start-up if a script in the
HTML file is being eval'd.
In unit tests, you can pass showAlert = false and examine the
resulting error with getError.
a fragment of JavaScript to be executed
whether to print the result to the output text area and
add the script to session history; default is true
whether to show an alert with error message when an error
occurs in the script; default is true
the result of executing the script
Returns the given Javascript script expanded by the various regular expression
rules which were registered with addRegex. The expanded script has
short names like DoubleRect expanded to have full path name like
lab$util$DoubleRect. Doesn't expand words inside of quoted strings
or regular expressions.
a Javascript script to be executed
the script expanded by registered regular expressions
Returns the error message from the last eval call, or empty string if no error occurred.
Called when a key has been pressed. Implements the meta-K command to clear
the output area, and the up/down arrow keys to scroll through
session history.
the event that caused this callback to fire
Private hasReturns true if the given regexPair is already on the list of regex's to execute.
the regexPair of interest
true if q is already on the list of regex's to execute.
Private inputParses and executes the query portion of the current URL (the portion of the URL after a question mark) as a script. See URL Query Script.
Before executing the query script, this calls Parser.saveStart to save the current settings.
returns true if there was a URL query script
Private replaceRemoves the var or let at front of a script (if any) and adds regexp which
mimics that JavaScript var statement. This helps make Terminal scripts more
JavaScript-like, by hiding usage of the z object. For example, if the script is
var foo = 3;
this will return just foo = 3; and add a regexp that replaces foo by z.foo.
a Javascript script to be executed
the script with the var removed
Sets the function to execute after evaluating the user input. Typically used to update a display such as a SimView or DisplayGraph.
Optional afterEvalFn: (() => void)function to execute after evaluating
the user input; can be undefined to turn off this feature
Specifies whether to show the expanded command in the Terminal output text area. In verbose mode, the command is echoed a second time to show how it appears after expansion. The terminal prompt symbol is doubled to distinguish the expanded version.
true means show expanded names in the Terminal output
Private splitFinds the section of text up to first top-level semicolon (top-level means not enclosed in curly braces). Ignores semicolons in quotes or regular expression. Note however that top-level double-slash comments end at a new-line not semicolon.
The text to be split up.
array with two elements: array[0] = the section up to and including the first top-level semicolon; array[1] = the remaining text.
Returns names of the variables that have been defined using addRegex. This is used as a "help" command for the user to know what variables are available.
names of defined variables, in alphabetic order
Static encodeURIComponentThis is a more stringent version of
encodeURIComponent
which adheres to RFC 3986 which reserves
characters !'()*. Some websites (such as reddit) will not accept a user supplied URL
that contains those characters.
the string to encode
the encoded string
Static stdAdds the standard set of regular expression rules to the given Terminal instance.
These regular expression rules replace short names with the full
expression that is valid JavaScript for referring to the object. This defines short
names for many classes and also utility functions like prettyPrint, methodsOf,
println and propertiesOf.
the Terminal instance to which the regexp's will be added
Static versionGenerated using TypeDoc
Executes scripts and provides a command line user interface with separate text fields for input and output. Executes EasyScript or JavaScript. Allows use of "short names" to replace full namespace pathnames of classes.
After the script is executed the result is converted to text and displayed in the output text field. The output is not displayed if the result is
undefinedor the script ends with a semicolon.See also Customizing myPhysicsLab Software.
Getting Help
Type
helpin the Terminal input text area and press return to see the help message. Several useful Terminal commands are shown.Perhaps the most useful command is
varswhich shows the list of variables that are available.Summary: How Scripts Are Processed
Scripts entered into Terminal are transformed in these ways:
Scripts are split at semi-colons into separate lines. Each line is executed separately. (Semi-colons within braces are ignored).
EasyScript parser handles lines that it recognizes.
varat start of a line becomes azvariable property. For examplevar foobecomesapp.z.foo.Short-names are transformed to long-names. Example:
DoubleRectbecomeslab$util$DoubleRect. Also existing variables are transformed, for examplefoobecomesapp.z.foo.Javascript's
evalfunction executes the resulting line.Turning on verbose mode with
terminal.setVerbose(true)shows these transformations as they happen.Two Types of Scripts
Terminal can execute two types of scripts:
JavaScript. The code is transformed so that short-names can be used.
EasyScript: a very simple scripting language for setting Parameter values. See EasyScriptParser for syntax details.
These two types of script can be intermixed in a single script as long as they are separated by a semicolon. For example, here are both types of scripts in one line which could be entered in PendulumApp.
The first three commands are EasyScript commands that set Parameter values; the last is a JavaScript command.
In most applications EasyScriptParser is available in the variable
easyScript, which you can use to execute EasyScript from within JavaScript. Here are examples that can be entered (as individual lines) in PendulumApp.Long Names
To make class names accessible for scripting in Terminal, we create a global variable for each class. For example
is the global variable for the DoubleRect class. This naming scheme is used to avoid potential conflicts with other global variables.
Short Names
To allow for shorter scripts, we define a variety of regular expressions in Terminal which convert short names to their proper long expanded form. This allows typing for example:
which is automatically converted to
Applications will typically also make their key objects available with short-names. So instead of
app.simyou can just typesim.You can see this short-name to long-name conversion by using setVerbose:
In verbose mode, the command is echoed a second time to show how it appears after expansion. The terminal prompt symbol
>>is doubled to distinguish the expanded version.Short-names are implemented by defining a set of regular expression replacement rules which are applied to the Terminal input string before it is executed.
Regular expression rules are registered with Terminal using addRegex. Then whenever a command is evaluated it is first expanded to the long form using expand.
stdRegex defines a standard set of regular expressions for expanding myPhysicsLab class names (like
DoubleRect) and for expanding a few function shortcuts likemethodsOf,propertiesOfandprettyPrint. An application can add more shortcuts via addRegex.Variables and the 'z' Object
Scripts are executed with indirect eval under strict mode. Each script line is
eval'd separately, and a new scope is created for eacheval(). Any variables created only exist during thateval(), then they disappear.To allow making variables that persist between lines and commands, the app provides an object named
zwhere properties can be added. A script likevar a = 1; ais translated to define a property on thezobject, instead of a new global variable. It looks something like this:This
zobject is itself a property of the application object usually calledapp;zis initially an object with no properties. We define a short name regular expression so that referring tozis replaced byapp.zwhen a script line is executed. Using setVerbose you would see the following:Declaring a Variable
To hide the usage of the
zobject, Terminal interprets thevar,letandconstkeywords in a special way.When Terminal sees the
varorletkeywords at the start of a command, it changes the script to use thezobject and defines a new short-name. For example the commandis translated to
and thereafter every reference to
foowill be changed toapp.z.fooin later commands. You can see this at work by using setVerbose:Line Splitting Affects How Scripts Are Processed
A script is executed by splitting it up into lines of code that are separated by semi-colons.
Each execution of a line (via indirect
eval) has it's own temporary scope where any created variables, functions, or classes go. That scope disappears as soon as the execution finishes.Only lines that are at the "top level" are split by semi-colons; any semi-colons within braces or parenthesis (or inside of strings) are ignored. Braces turn off line splitting.
For example: this script creates a class and does a test within braces, but the class and variable disappear after execution. The value
7is printed if you paste this entire script into Terminal input, butaandmyClassare no longer defined.To make things within braces persistent, assign them to something defined beforehand.
To make a class (or function) persistent, assign it to a variable.
The Result Variable
The result of the last Terminal script is stored in a variable named
result. Here is an example Terminal session:Note that eval has an argument called
outputwhich if set tofalsepreventsresultfrom being updated. Whenoutput==false, thenresultis is defined for commands in the same string, but that version ofresultis temporary and independent of the permanentresultvariable.The terminal Variable
Some features (such as the
resultvariable) require that the nameterminalis defined and resolves to the Terminal object.In most applications this is accomplished by using addRegex something like this:
where
appis the global variable containing the application. The purpose of the regex is to replace the wordterminalwithapp.terminalwhich is a valid JavaScript reference.(In unit tests of Terminal, we temporarily define a global variable named
terminal.)Cautions About Newline Character
When you paste a script into the Terminal text input field, be aware that newlines are replaced by spaces. For a multi-line script this can cause errors. To prevent problems:
Use explicit semicolons instead of relying on JavaScript's policy about optional semicolons.
Use slash-star style comments instead of double-slash style comments (which are terminated by a newline).
If for some reason you really need a newline in the script, use
\u000Aor\x0A. These are replaced with the newline character before the script is evaluated.Put the multi-line script in a start-up HTML page. You can then call
Terminal.eval()directly on a string that you create, and that string can include newline characters.The tab character also cannot be input directly to the Terminal input field, because the browser interprets that to mean "move to the next field". You can use
\u0009or\x09which are replaced by a tab character before the script is evaluated.URL Query Script
A Terminal script can be embedded into a URL query string which will be executed when the page is loaded. This provides a convenient way to remember or share a customized simulation with someone else.
The script follows a question mark in the URL, so it is called a 'query script' or 'query URL'. Here is an example:
The URL Query Script is executed at startup by calling parseURL. Most myPhysicsLab applications do this.
Some websites will only accept user-supplied URLs that follow the strict guidelines of URL percent-encoding. Therefore we must substitute in the URL:
%20for space%22for"%3Cfor<%3Efor>%5Cfor\See this character encoding chart to learn which other characters must be percent-encoded. You can use {@link encodeURIComponent} which is a more stringent version of doing the character encoding; it percent-encodes other symbols such as:
%27for'%28for(%29for)%3Bfor;Here is an example of a URL query script using JavaScript in an application:
Try this link which contains the above code; you should also see the code in the Terminal output area.
Here is an interactive tool for trying out URL Encode/Decode. Note however that tool replaces a space with a
+which instead should be replaced by%20.Many websites and programming tools require that the URL be fully encoded with the more stringent version.
Session History
The session history feature recalls previous input lines; these are accessed using the up/down arrow keys. Command-K clears the output area.