Ptty terminal emulator

Ptty jQuery Plugin

Because command lines are cool.

About

Ptty /ˈpɪti/ is a web based terminal emulator plugin for jQuery. It was originally based on Wterm by Venkatakirshnan Ganesh but has been modified to include a large set of new features.

The list of features includes (but is not limited to) a password prompt, and a JSON response schema to send commands to the terminal and execute custom callbacks.

Demo

Ptty comes with three preset commands registered.

There is also a full screen Demo. Try it out!

Or... You can also stick around here and use these buttons to execute commands while you read the docs.

Type help -a in the box to your right and you will see all the available commands, their descriptions and their usage. The rest of the available commands in this demo are explained in the Usage section.

Oh, and you can also use the tab key and the up and down arrows to autocomplete commands and navigate through history.

Download

CSS Themes

Ptty comes ready made to be themed like any modern terminal. This is the basic (default) theme:

/* boring theme */
.cmd_terminal_theme_boring,
.cmd_terminal_theme_boring input { 
    background-color: #0a0a0a; color: #ddd; letter-spacing: 1px; 
}
.cmd_terminal_theme_boring .cmd_terminal_active { font-weight: bold; }
.cmd_terminal_theme_boring .cmd_terminal_ps span::after { content: ">"; }
.cmd_terminal_theme_boring .cmd_terminal_sub span::after { content: "\0000a0>"; }

But there is no need to be so bland, try these alternatives! (Or look at their css)

To make your own theme, just copy the template above and replace the theme name "boring" with your theme name, remember to add the theme option with your theme name when invoking Ptty.

Usage

The good part about this is that its dead simple. Take a look at the options list under these examples for a quick start.

Basic usage:

$(document).ready(function(){
    $('#terminal').Ptty();
});

Usage with options:

$(document).ready(function(){
    $('#terminal').Ptty({
        // Default ajax URL (can be relative or absolute).
        url    : 'ajax/',

        // Set the PS to an empty string and change the 
        // defaults to use a custom css theme.
        ps     : '',
        theme  : 'boring',
        welcome: 'Welcome to the matrix.'
    });
});

Options

Ptty comes with several options that make it special.

  • url
    • Type: str
    • Default: current URL
    • Description: The standard url that should be used to make requests. Defaults to same file.
  • method
    • Type: str
    • Default: POST
    • Description: The HTTP Method that must be used for Ajax Requests
  • param
    • Type: str
    • Default: cmd
    • Description: The GET/POST parameter that should be used to make requests
  • tty_class
    • Type: str
    • Default: cmd_terminal
    • Description: Class of the the primary terminal container (the Ptty.css files uses this class, be warned.)
  • theme
    • Type: str
    • Default: boring
    • Description: The theme that is applied by default
  • width
    • Type: str
    • Default: 100%
    • Description: Set the width of the terminal container
  • height
    • Type: str
    • Default: 100%
    • Description: Set the height of the terminal container
  • welcome
    • Type: str
    • Default: Ptty v.[version number]
    • Description: Message to be shown when the terminal is first started
  • placeholder
    • Type: str
    • Default:
    • Description: The placeholder to echo in place of password input (see response format).
  • not_found
    • Type: str
    • Default: CMD: Command Not Found
    • Description: When command is not found: "CMD" will be replaced with the command.
  • error_prefix
    • Type: str
    • Default: An Error Occurred:
    • Description: Prefix for error messages
  • autocomplete
    • Type: bool
    • Default: true
    • Description: Is Autocomplete feature Enabled
  • history
    • Type: bool
    • Default: true
    • Description: Is Command History Enabled
  • history_max
    • Type: int
    • Default: 800
    • Description: Number of entries to be stored in history
  • charset
    • Type: str
    • Default: UTF-8
    • Description: The character set to be used on the "accept-charset" form attribute
  • enctype
    • Type: str
    • Default: multipart/form-data
    • Description: The value of the "enctype" form attribute
  • autofocus
    • Type: bool
    • Default: true
    • Description: When true the terminal will focus on load

Adding Commands

Commands can be added easy enough using the $.register_command() method. It has 4 parameters:

  • command name
    • The name with which to invoke the command through the command line.
  • command description
    • A short note about what the command does.
  • command usage
    • How to use the command, options, etc...
  • command dispatch
    • This parameter can be a method, object or string. And is explained in the examples bellow.

To add a command that makes an AJAX request you could do the following:

$.register_command(
    'ip', 
    'Gets your remote IP address.', 
    'ip [-v6]',
    ''
);

This particular example will call this same file ( index.php ) with a POST request containing the input string because the last parameter is set to an empty string.

Here is an example of the fourth parameter of $.register_command() using a URL. It can be relative or absolute.

$.register_command(
    'fortune', 
    'Prints a random fortune cookie', 
    'fortune [-joke | -wisdom]',
    'ajax/fortune.php'
);

You can also add commands directly in JavaScript, like this one that calls a function that returns the date:

$.register_command(
    'date', 
    'Shows the time and date.', 
    'date or date [ _d_/_m_/_y_ _h_:_i_:_s_ ]', 
    function(args){
        return {
            type : 'print',
            out  : cmd_date(args)
        }
    }
);

If you would like to register many commands (for example from an API), its as easy as looping through an object with the names and URLs for the commands like this:

var kitty_api = [{
        cmd_name        : 'ktyput',
        cmd_description : 'Saves a kitten pic to API', 
        cmd_usage       : 'kittyput [URL to image]',
        cmd_url         : 'kittyapi.php?put'
    },
    {
        cmd_name        : 'ktyget',
        cmd_description : 'Gets a kitty pic from API. Try a number from 01 to 10.', 
        cmd_usage       : 'kittyget [01 to 10]',
        cmd_url         : 'kittyapi.php?get'
    },
    {
        cmd_name        : 'ktydel',
        cmd_description : 'Deletes a kitty :-(.', 
        cmd_usage       : 'kittydel [01 to 10]',
        cmd_url         : 'kittyapi.php?del'
    },
    {
        cmd_name        : 'ktyreset',
        cmd_description : 'Brings the original kittys back from heaven.', 
        cmd_usage       : 'kittyreset [no options]',
        cmd_url         : 'kittyapi.php?reset'
}];

for (var i = kitty_api.length - 1; i >= 0; i--) {
    $.register_command(
        kitty_api[i].cmd_name,
        kitty_api[i].cmd_description, 
        kitty_api[i].cmd_usage,
        kitty_api[i].cmd_url
    );
};

But wait, there is more...

Introducing Subroutines

Subroutines run under the current Ptty instance and signal exit and start flags. To register a subroutine you must declare an object with four properties on the 4th parameter.

$.register_command(
    'game', 
    'Plays rock-paper-scissors.', 
    'game [no options]', 
    {
        ps : 'game',

        start_hook : function(){ 
            return {
                type : 'print', 
                out : cmd_game(false, 'start')
            }; 
        },

        exit_hook : function(){ 
            return {
                type : 'print',
                out : cmd_game(false, 'end')
            }; 
        },

        dispatch_method : function(args){
            return {
                type : 'print',
                out : cmd_game(args, false)
            };
        }
    }
);

See the cmd_game() function here.

Here is a brief description of the subroutine properties:

  • ps
    • Will set the PS1 of the subroutine, there is also a CSS class named .cmd_terminal_sub that you can use to further personalize your subroutine using a theme.
  • start_hook
    • This method / request is made when the subroutine is first called.
  • exit_hook
    • The exit hook is called when the subroutine exits using the quit or exit commands. It is not called if the exit is declared in the response.
  • dispatch_method
    • This method or request is used every time the user enters a command in the subroutine.

Just one last example to demonstrate most of Ptty's features. In this case we use a subroutine with an AJAX call:

$.register_command(
    'tutorial', 
    'A program that asks a lot of questions.', 
    'tutorial [no options]', 
    {
        ps              : '~ttrl',
        start_hook      : 'tutorial.php?start',
        exit_hook       : 'tutorial.php?end',
        dispatch_method : 'tutorial.php'
    }
);

Take your time and play with it in the Demo terminal, the tutorial command will show you what can be done with very little effort and loading a bite sized request to speed everything up.

Response Format

As you might have noticed all the above functions return objects. This is a required format so Ptty knows what to do with your response. A typical command will return an object with a out property for the output like this:

$.register_command(
    'echo', 
    'Output to the command line', 
    'echo [text to output]', 
    function(args){
        args.shift();
        return {out : args.join(' ')};
});

The properties are used to define the behavior of the terminal.

The response of a command must be a Javascript Object and can include the following properties:

  • out
    • This value must be a string with the data to output on the command line.
  • quiet
    • Don't echo user input to the command line.
    • Values:
      • password
        • Use this value to echo placeholders instead of the password.
      • blank
        • Leaves the output blank.
      • clear
        • Wipes out the entire command line.
      • output
        • Will not register the command executed. But will display whatever was passed in the out property.
  • query
    • What command or options to submit with the current command.
  • clean
    • An important option that clears name, ps, or query properties on demmand.
  • token
    • Used when doing information transactions, tokens when used well can give extra security to your interface.
  • exit
    • Exits a subroutine without user interaction (i.e. the user gets kicked out).
  • callback
    • A pre-defined callback can be called by adding callbacks with the $.register_callback() method (see adding callbacks for more information).
  • type
    • There are several callback types (passed as strings) that you can use to interact with Ptty.
    • Values:
      • print
        • Will output a the out response property and exit to the current routine or subroutine. If no type is specified print will be used.
      • prompt
        • This will generate a token and send it to the server under the cmd_token parameter. You can also specify a custom token by using the token response property.
      • password
        • Will replace the command input for a password field. This callback type should be used in combination with the quiet property.
      • upload
        • Attempts to open the file selector input.

          If this type is used you can also add the following properties to the base response format:

          • upload_to, if set Ptty will upload to the designated URI. If it is not set the upload will be made to the main ajax URL or the subroutine URL. The upload is always done via POST method.

          These will have effect on the input file tag used for file selections.

          • upload_multiple if set the multiple files will be allowed.
          • upload_accept is the value of the accept attribute.

Manipulating Ptty seems harder than it really is, but for the sake of clarity here are some more examples of objects that tell Ptty what to do:

Here is a modified version to test responses directtly from the command line:

$.register_command(
    'response',
    'Useful for testing Ptty response methods.', 
    'response [response object]', 
    function(args){
        args.shift();
        return JSON.parse(args.join(' '));
});

A response to ask a user what his name is and append it to an echo command:

{
    "type" : "print",
    "out" : "Whats your name?",
    "query" : "echo hello ",
    "clean" : "query"
}

Note the usage of "query" : "echo thanks " to concatenate the input after the next command and "clean" : "query", to empty the query command which is sticky and will persist until cleared.

Another example, a response to ask for a password:

{
    "type" : "password",
    "ps" : "Secret",
    "query" : "echo your password is: ",
    "clean" : ["query","ps"]
}

Here the clean property is an array containing ["query","ps"], the properties to clean. Just like the previous example, this is required so the command options do not perpetuate on the next command you enter.

Now lets check out the upload feature.

{
    "type" : "upload"
    "upload_accept" : "image/*"
    "custom_field" : "custom_value"
}

As you can see the upload posted your selected file. And the other parameters to this same file. You can use the upload_to property to choose where to upload.

Please note that uploading files can have serious security implications.

Adding Callbefores

One of the problems with early versions of Ptty was processing the user input on client side before sending it over to the server through the built in AJAX functionality. A workaround to this problem is called a callbefore because it is the opposite of a callback.

Like callbacks, all callbefores must be registered to a registered command to work, and should always return a string to continue or false to stop the command from being processed.

Here is a fake registration validation command we will use to test this feature:

$.register_command(
    'register', 
    'A fake registration command.', 
    'register [-u username -e email -p password]',
    ''
);

$.register_callbefore(
    'register',
    function(cmd){
        var err = false,
        cmd_opts = ['-u','-e','-p'],
        args = $.tokenize(cmd, cmd_opts);

        // replace password
        if(typeof args['-p'] !== 'undefined'){
            var stars = '*'.repeat(args['-p'].length),
            safe = cmd.replace(RegExp('\\s'+args['-p'], "g"), ' '+stars);
            $.set_command_option({ cmd_in : safe });
        }

        err = validate_registration(cmd_opts, args);
        if(err){
            // ouput errors
            $.set_command_option({ cmd_out : err });
            cmd = false;
        }

        return cmd;
    }
);

As you can see, the command entered is tokenized using $.tokenize() and then the validation errors are sent using $.set_command_option() (more about these two here).

It then returns a string with the original command input. Or false if invalid data is detected.

Try running the command again (press the up arrow key), but this time delete a parameter (so to invalidate the registration). You should get an error message, and no AJAX post will be made. This is because the call before returned false.

Important: When a callbefore returns a string, it will post it using the cbf parameter. It will also use the cmd parameter as a cache of the original command. For instance, the posted content of the example above would look like:

cmd=register+-u+usr+-e+em@ai.ls+-p+******
cbf=register+-u+usr+-e+em@ai.ls+-p+secret

Adding Callbacks

Ptty can add custom callbacks just as easy as it adds commands, you will have to define the callback and load it, but after that they become available to any command using the callback property.

Callbacks are added using the $.register_callback() method. Here is an example redirect callback and modal dialog example.

$.register_callback('redirect', function(data){
        if(typeof data.url !== 'undefined' && window.confirm("Redirect?")) { 
              window.location = data.url;
        }
        
    }
});

$.register_callback('dialog', function(data){
    if(typeof data.html !== 'undefined'){
        $('.modal-content').html(data.html);
        $('.modal-wrap').show(500);
    }
});

To test them we are going to use our kitty API

As you can see the parameters of the command response are handed down in full to the callback, so all the properties mentioned above can be present.

The idea of using callbacks is to connect the user input with jQuery plugins like sliders, modal windows and other useful display tools.

Other Methods

You can reset all the commands recorded and add new ones too! It's as simple as calling:

$.flush_commands()

After you click on the button above all the commands should have been removed except for the basic three (help, history, and clear). You can check by typing help or pressing the tab key on the terminal to your right.

You can reload commands using the $.register_command() method again.

Click on the button above to get the commands back. This is useful if, for example a logged in user has different set of commands available than a guest user.

And to set an option of a command that has already been sent or to alter the options of a future command you can use the $.set_command_option() method.

$.set_command_option({ cmd_ps : 'Are you sure?', cmd_clean : 'ps' })

This method will override the input from a response and accepts the following options:

  • cmd_name
    • If set, edits the subroutine name.
  • cmd_class
    • Command class attribute value.
  • cmd_ps
    • The ps value, that precedes the command input.
  • cmd_in
    • The command input.
  • cmd_out
    • The output of the command.
  • cmd_quiet
    • Set to 'password', 'clear', 'output' or 'blank'
  • cmd_token
    • Set to a unique sting for secure transactions
  • cmd_query
    • Accumulates a string for a subroutine to use
  • cmd_clean
    • Clears the selected option

You might have noticed the cmd_quiet option uses the same values as the response.

You can also use $.get_command_option() that will return the value of a command options requested using an array:

var current_opts = $.get_command_option(['cmd_token', 'cmd_query']);
// So now current_opts = {cmd_token : "some value", cmd_query : "another value"};

Since Ptty 0.0.4 you can also use $.tokenize() that will attempt to tokenize a string in to its intended options, taking into account double quotes and single quotes.

var tokens = $.tokenize('command --desc "Hello world"', ['--desc']);
// Returns { --desc : "Hello world" }

Note: This is still an experimental function and may not behave as expected.

FAQ

Is Ptty on github?

Yes, Ptty is on github.

What public license type is Ptty under?

Ptty is licensed under the one and only Do What the Fuck You Want to Public License.

What does that mean?

It means you can copy the source, and do whatever you want to do with it.

Can I contact you about improvements, features, bugs, requests?

Yes of course. Please rise an issue and I'll answer as soon as possible.

Bugs

There are bugs, as it's an early release, please notify me if you find anything that does not work as expected.

    ______ _   _           
    | ___ \ | | |          
    | |_/ / |_| |_ _   _   
    |  __/| __| __| | | |  
    | |   | |_| |_| |_| |_ 
    \_|    \__|\__|\__, (_)
                    __/ |  
                   |___/   
                

( I think we are done here. )

Fork me on GitHub Fork me on GitHub