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
undefined
or the script ends with a semicolon.See also Customizing myPhysicsLab Software.
Getting Help
Type
help
in 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
vars
which 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.
var
at start of a line becomes az
variable property. For examplevar foo
becomesapp.z.foo
.Short-names are transformed to long-names. Example:
DoubleRect
becomeslab$util$DoubleRect
. Also existing variables are transformed, for examplefoo
becomesapp.z.foo
.Javascript's
eval
function 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.sim
you 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
,propertiesOf
andprettyPrint
. 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
z
where properties can be added. A script likevar a = 1; a
is translated to define a property on thez
object, instead of a new global variable. It looks something like this:This
z
object is itself a property of the application object usually calledapp
;z
is initially an object with no properties. We define a short name regular expression so that referring toz
is replaced byapp.z
when a script line is executed. Using setVerbose you would see the following:Declaring a Variable
To hide the usage of the
z
object, Terminal interprets thevar
,let
andconst
keywords in a special way.When Terminal sees the
var
orlet
keywords at the start of a command, it changes the script to use thez
object and defines a new short-name. For example the commandis translated to
and thereafter every reference to
foo
will be changed toapp.z.foo
in 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
7
is printed if you paste this entire script into Terminal input, buta
andmyClass
are 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
output
which if set tofalse
preventsresult
from being updated. Whenoutput==false
, thenresult
is is defined for commands in the same string, but that version ofresult
is temporary and independent of the permanentresult
variable.The terminal Variable
Some features (such as the
result
variable) require that the nameterminal
is defined and resolves to the Terminal object.In most applications this is accomplished by using addRegex something like this:
where
app
is the global variable containing the application. The purpose of the regex is to replace the wordterminal
withapp.terminal
which 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
\u000A
or\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
\u0009
or\x09
which 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:
%20
for space%22
for"
%3C
for<
%3E
for>
%5C
for\
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:
%27
for'
%28
for(
%29
for)
%3B
for;
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.