-
-
Notifications
You must be signed in to change notification settings - Fork 570
Advanced jQuery Terminal Tutorial
- Interpreter
- Canceling Ajax Requests
- Displaying the content on the terminal
- Events
- Authentication
- Webpack and Babel
- Shortcuts
- Saving State
- Mobile Web Terminal and Responsive Text
- Scrolling
- Extensions
- CSS Style
- Strings
NOTE: There is a task to create a proper tutorial that will show you step-by-step how to create a Terminal Based Resume. It's tracked in #801 the plan is to pack all advanced features + more ideas into one big article.
The interpreter is the first argument of jQuery plugin invocation:
$('body').terminal(<interpreter>, { <options> });
The interpreter can be created in few different ways, the first argument is overloaded and allow passing function, object (including nested object), string, or Array of function object and strings.
The function is a more low-level, but versatile version of the interpreter. It accepts the whole command as a string. It's useful if you want to parse the command yourself. You can use some interpreter like SQL or JavaScript that passes the whole expression to that interpreter. You can also parse the commands with tools provided by jQuery Terminal like:
$.terminal.parse_command
$.terminal.split_command
Those two functions are very similar except the second one that converts arguments into values.
parse_command
will convert numbers like strings into numbers and regex like strings into
regular expression objects. Both functions remove quotes from strings.
The function return object:
{
"name": "command",
"args": [<arguments>],
"args_quotes": [<Array of quote characters from string>],
"rest": "<arguments as string>",
}
There are also functions for converting arguments into an array:
$.terminal.parse_arguments
$.terminal.split_arguments
Both pairs of functions handle spaces inside strings, escaped spaces and escaped quotes, So they return proper parsed output like bash would do it.
Example:
$('body').terminal(function(command) {
var cmd = $.terminal.parse_command(command);
if (cmd.name === 'add') {
this.echo(cmd.args.reduce((a, b) => a + b));
}
});
when called with: add 1 2 3 4 5
it will return 15
.
More about parsing in Parsing commands.
You can use string as an interpreter (also in Array and Object) the string need to be a URL
that points to a valid JSON-RPC service. If the service provide system.describe
(defined
in 1.1 draft of JSON-RPC)
you can use auto-completion without any extra work. If you don't want to implement non-standard
system.describe
, you can provide a normal method (with the same name) that returns
standard JSON-RPC response, but then you will need to use the option that tells jQuery Terminal
where he can find the definition of procedures that are provided by the JSON-RPC service.
To do that you can use:
{
describe: "result.procs"
}
if the JSON-RPC method system.describe
return object {procs: ...}
as described by JSON-RPC 1.1.
If you don't want to use auto-discovery you can use the option:
{
ignoreSystemDescribe: true
}
NOTE: There is an issue #619 to support Open-RPC.
The object can have functions that will be executed when a command with a specific name is invoked, it can be another object that creates a nested interpreter (for example MySQL command, that accept SQL commands) or it can be a string that creates a nested interpreter from JSON-RPC service.
By default when using objects the arguments are parsed, so a number like strings are real numbers, regular expressions are regexes and true/false are real values. To disable this behavior use option:
processArguments: false
.
var stack = [];
$('body').terminal({
stack: {
push: function(arg) {
stack.push(arg);
},
pop: function() {
return stack.pop();
}
},
sudo: function(command, ...args) {
switch(command) {
case 'ls':
list_directory(...args);
break;
case 'rm':
remove_file(...args);
break;
case 'mv':
move_file(...args);
break;
default:
this.error('Sudo what?');
}
},
rpc: "service.py"
}, {
checkArity: false
});
This example creates three commands
-
sudo
that allows executing a command with arguments, variadic functions require to add optioncheckArity
that is set to true by default and don't allow to execute functions with more than the required number of arguments. -
stack
that creates simple nested command, when you type stack it will change the prompt tostack>
and allow executing two commandspush
andpop
that is an interface to stack data structure created from Array. -
rpc
command will change the prompt torpc>
and allow to execute commands that are provided by the given URL here it expects that in the same directory as the HTML file there isservice.py
that is a server-side script that is the implementation of JSON-RPC.
With an array, there is always created single object, created by merging explicit object
or string that point to JSON-RPC service that have system.describe
, that allows creating
object-based on procedures in that request. Besides objects created from Array,
there can only be a single function that is executed as a fallback if no commands
were found. Also if JSON-RPC doesn't support system.describe
method it's handled like
a single function.
If an object is created from at least one object (or JSON-RPC service that provide system.describe
)
then you can use automatic completion by adding the option
{
completion: true
}
Details can be found in Tab-completion page.
Since early stage the library canceled AJAX requests (using CTRL+D shortcut) when using jQuery $.ajax
or $.get
, but since modern way is to use fetch API, in version 2.43.0 the library added Abort signals API.
There are two new methods that return signals cancelable by CTRL+D or with terminal::abort()
terminal::timeout()
terminal::signal()
Here is an example how to use timeout signal, that you can cancel before the timeout with CTRL+D:
$('body').terminal(async () => {
const signal = this.timeout(500);
const res = await fetch('./api?command=' + encodeURIComponent(command), { signal });
const json = await res.json();
this.echo(json.result);
});
When signal is aborted, you will get a red message displayed:
[Command] Signal timed out
If you want to hide this error message, you can use settings: errorOnAbort: false
. As with other strings you can also change it, there are two new strings:
abortError: 'Abort with CTRL+D'
timeoutError: 'Signal timed out'
With terminal::abort()
you can also provide your own reason to cancel the requests:
term.abort("I want to cancel");
If you do any expensive processing, you can also cancel it with signals. For this, you need to implement your code that utilize signals:
function myCoolPromiseAPI(/* …, */ { signal }) {
return new Promise((resolve, reject) => {
// If the signal is already aborted, immediately throw in order to reject the promise.
if (signal.aborted) {
reject(signal.reason);
}
// Perform the main purpose of the API
// Call resolve(result) when done.
// Watch for 'abort' signals
signal.addEventListener("abort", () => {
// Stop the main operation
// Reject the promise with the abort reason.
reject(signal.reason);
});
});
}
The above example is taken from MDN.
You can use this code similar to fetch:
$('body').terminal(async () => {
const signal = this.signal();
const response = await myCoolPromiseAPI(/* …, */ { signal });
this.echo(response);
});
The main function for displaying the content of the terminal is the echo
method. It has a lot of advanced functions.
- Display of Columns if you echo an array of strings.
- Echo of Promises.
-
renderHandler
and any objects see Demo React and Canvas inside jQuery Terminal - Formatting and Syntax Highlighting.
- Buffer.
- Chinese and Japanese character support.
- Invoking Commands and terminal methods from Server.
- Typing Animation
- Animation new in 2.28.0
- Custom Animation
- Forms new in 2.28.0
TODO:
- Using ASCII libraries awesome-ascii
- ASCII examples: ASCII Image Upload
- Using Web Worker for ANSI ART rendering (see example bookmarklet)
- Drawing ANSI Art
- Preprocess ANSI with executable
- Async processing (Promise like objects)
Library for Web-Based Terminal in JavaScript, (jQuery Terminal: git repo)
Copyright (c) 2011-2023 Jakub T. Jankiewicz