AjaxPatterns
This is the original book draft version for the Live Command-Line Ajax pattern, offered for historical purposes and as an anti-spam measure.
You're probably better off visiting the Live Wiki Version for Live Command-Line instead, where you can make changes and see what others have written.

Live Command-Line

Assistive, CLI, Command-Line, Grammar, Supportive

Goal Story

Frank is using an advanced query tool to run a report on current output. He begins entering an SQL-like query: "list all ". At this point, a suggestion list appears with all the things that can be listed, and he chooses "products". Continuing on, the query is now "list all products where " and a new list appears: "creationTime", "quality", and so on. He chooses creationTime. then enters the rest manually, preferring to ignore further suggestions. The query ends up as "list all products where creationTime is today and quality is faulty". There's a tick next to the query to indicate it's valid.

Problem

How can a command-line interface be supported?

Forces

  • Users can only say so much with point-and-click interfaces. The command-line is more expressive and remains the tool of choice for expert users.

  • URLs and search fields are becoming general-purpose command-lines.

Solution

In command-line interfaces, monitor the command being composed and dynamically modify the interface to support the interaction. The interface changes according to data, business logic, and application logic. When the command-line is to be executed on the server, as is often the case, the browser usually delegates to the server to evaluate the partial command.

The command-line is the quintessential expert interface and it's worth bearing in mind that most users are "perpetual intermediates". That is, they learn enough to get by, and generally learn new things only as and when required. So, while a powerful command-line may be a superior choice in the long-run, most users simply don't have the time to spend learning it in advance.

The problem arises with traditional command lines because they present the user with a blank slate. Everything the user types must be based on prior, upfront, learning, and the only feedback occurs after the command-line has been executed. That's not only inefficient for learning, but downright dangerous for sufficiently powerful commands. The model is: human enters command, computer executes command.

The solution is to be more interactive: with a smarter, more proactive, command-line, the construction of a command - its quick evolution from nothingness to an executable string - becomes something of a human-computer collaboration. Examples include:

  • Indicate if the command is valid before submitting it. If it's not valid, prevent it from executing and inform the user what's wrong and how it can be rectified.

  • Offer to fix invalid commands.

  • Offer “Suggestion”s to help complete part of the command.

  • Help the user predict what will happen when the command is executed. For a query, this means hinting at the result, such as estimating number of matches (see “Guesstimate”).

  • Provide graphical widgets to help the user construct the command. For example, build up a mathematical expression using a calculator-like interface to introduce numbers and functions. The query is still represented as plain-text, but the text need not be entered by hand.

  • Provide graphical widgets to help the user refactor the command. For example, you could provide a "delete this" button next to each condition in a query.

  • Provide visualisation tools to render the query in other formats. For example, certain numerical queries might be visualised graphically.

The benefits apply to novices and experts alike. In supporting novices, the technique has sometimes been referred to as a "training wheels" approach. Like training wheels on a bike, you get a feel for the more powerful interface while still being productive.

Often, the command goes to the server, so it usually makes sense for the server to advise on partial commands. A basic procedure is this:

  1. Use “Submission Throttling” to periodically upload the partial command string as an “XMLHttpRequest Call”.

  2. The server then processes the command and returns supporting information.

  3. The browser updates the user interface accordingly.

As an Ajax feature, this pattern is largely speculative: I'm not aware of any production-level Ajax Apps, but the command-line interface is growing at the same time as Ajax; it's inevitable these things will collide, and as the discussion here suggests, there are plenty of synergies. One source of inspiration here is the evolution of IDEs over the past five years, particularly in the Java space. Environments like Eclipse and IntelliJ Idea internally represent source files as data structures, leading to features such as ongoing error detection, offers to fix errors, suggestions, powerful refactorings, alternative displays. All of this happens without ever having to compile the source code. As another source of inspiration, there was a recent experiment on training wheels for the command-line. Students learned about the Unix command line from either a book or a GUI "training wheels" interface, similar to a Live Command-Line. The training wheels interface was found to be more productive and a more pleasant experience too.

Decisions

Where will the partial command be analysed - browser or server?

It's possible to perform some kinds of analysis in the browser. For example, the browser can check the query against a constant regular expression. So should you try to support analysis in the browser or delegate to the server?

There are several advantages to analysing the command server-side:

  • The analysis can take into account server-side data, external services, and server-side hardware resources.

  • In most cases, the command will ultimately be processed there, so this allows related logic to be kept in the same place.

  • Since the command is just a text string, it's in a convenient form for uploading and server-side processing. As well, it's easier to keep earlier results in a “Browser-Side Cache”, because the command constitutes a key for the cache.

The downsides are:

  • Extra load on the server.

  • Extra bandwidth required to download richer responses.

  • Extra lag between user typing and browser responding.

How much information will the server provide?

Producing more information for partial commands will consume more server resources as well as taking a bit longer to download. You'll need to trade off supportive information against resources. For example:

  • In supporting validation, you can often rule out many errors with a simple regular expression. But more complex errors, relating to the existence of business objects for example, will get past that filter. Do you try to catch those too? Doing so would improve usability at the expense of resources.

  • In hinting at the command's result, there's a spectrum of precision. For a query, you can say "there might be results", "there are results", "there are 4123 results". In an extreme case, you can offer a “Live Search” and actually show the results.

Real-World Examples

I'm not aware of an all-encompassing Live Command Line demo. However, the examples in “Live Search” and “Suggestion” are special cases of Live Command Lines. There are also some Javascript terminal emulators around, though they don't provide Live Command Lines - see Web Shell and JS/UNIX Unix Shell. Also, see the Try Ruby! tutorial for an impressive web interface to the interactive Ruby programming environment.

YubNub

YubNub isn't Ajaxian, but noteworthy as the first explicit exploration of the "search as command line" meme. Yubnub lets users submit commands, which are then mapped into external queries. For example, if you type in "sum 10 20", you get the sum of 10 and 20, if you type in "ajax form", you get search results from ajaxpatterns.org for "form".

Code Example [AjaxPatterns Assistive Search Demo]

The Assistive Search Demo was inspired by services such as Google Search, which are trending towards a general-purpose command line. It aims to illustrate the "training wheels" style of command-line support.

There's a typical search engine form - a free-range text input with a Submit button. In addition, there are a few images below, one for each category that can be searched. Thus, the user is alerted as to the capabilities of the search. As you type, the categories “Highlight” and un- “Highlight” to help predict what kind of results will be returned (Figure 1.63, “Assistive Search Demo”). All of this information comes from the server-side: the browser application doesn't know anything about the categories. It calls the server and startup to discover the categories and corresponding images. A timer monitors the command-line, continuing to ask the server which categories it matches. The browser then highlights those categories.

Figure 1.63. Assistive Search Demo

Assistive Search Demo

The startup sequence loads the categories and kicks off the command-line monitoring loop. The server is required to have a corresponding image for each category. If it says there's a category "phone" category, then there will be an image at Images/phone.gif. The images are all downloaded and placed alongside each other:

    window.onload = function() {
      initialiseCategories();
      requestValidCategoriesLoop();
      ...
      }
    }
    
    function initialiseCategories() {
      ajaxCaller.getPlainText("categories.php?queryType=getAllCategoriesCSV",
                              onAllCategoriesResponse);
    }
   
    function onAllCategoriesResponse(text, callingContext) {
        allCategoryNames = text.split(",");
        var categoriesFragment = document.createDocumentFragment();
        for (i=0; i<allCategoryNames.length; i++) {
          var categoryName = allCategoryNames[i];
          var categoryImage = document.createElement("img");
          categoryImage.id = categoryName;
          categoryImage.src = "Images/"+categoryName+".gif";
          categoriesFragment.appendChild(categoryImage);
        }
        document.getElementById("categories").appendChild(categoriesFragment);
    }

The key to the Live Command-Line is the monitoring loop. Whenever a change occurs, it asks the server to return a list of all matching categories:

    function requestValidCategoriesLoop() {
        if (query()!=latestServerQuery) {
          var vars = {
            queryType: "getValidCategories",
            queryText: escape(query())
          }
          ajaxCaller.get("categories.php", vars, onValidCategoriesResponse,
                         false, null);
          latestServerQuery = query();
        }
        setTimeout('requestValidCategoriesLoop();', THROTTLE_PERIOD);
    }

The server uses a bunch of heuristics to calculate the categories that are valid for this query. For instance, it decides if something belongs to the "people" category by looking up a collection of pronouns in the dictionary. A controller will ultimately return the categories as a comma-separated list, generated with the following PHP logic:

    function getValidCategories($queryText) {
      logInfo("Queried for '$queryText'\n");
   
      $cats = array();
      eregi(".+", $queryText) && array_push($cats, 'web');
      eregi("^[0-9\+][A-Z0-9 \-]*$", $queryText) && array_push($cats, 'phone');
      eregi("^[0-9\.\+\/\* -]+$",$queryText) && array_push($cats, 'calculator');
      isInTheNews($queryText) && array_push($cats, 'news');
      isInWordList($queryText, "./pronouns") && array_push($cats, 'people');
      isInWordList($queryText, "./words") && array_push($cats, 'dictionary');
   
      return $cats;
    }

Back in the browser, the category images are dynamically updated with a CSS class indicating whether or not they are valid, determined by checking if they were in the list. There's also an event handler to perform a search on a specific category, as long as its valid:

    function onValidCategoriesResponse(text) {
   
        var validCategoryNames = text.split(",");
   
        // Create a data structure to make it faster to determine if a named
        // category is valid. For each valid category, we add an associative array
        // key into the array, with the key being the category name itself.
        validCategoryHash = new Array();
        for (i=0; i<validCategoryNames.length; i++) {
            validCategoryHash[validCategoryNames[i]] = "exists";
        }
   
        // For all categories, show the category if it's in the valid category map
        for (i=0; i<allCategoryNames.length; i++) {
            var categoryName = allCategoryNames[i];
            var categoryImage = $(categoryName);
            if (validCategoryHash[categoryName]) {
              categoryImage.onclick = onCategoryClicked;
              categoryImage.className="valid";
              categoryImage.title =
                "Category '" + categoryName + "'" +" probably has results";
            } else {
              categoryImage.onclick = null;
              categoryImage.className="invalid";
              categoryImage.title =
                "Category '" + categoryName + "'" + " has no results";
            }
        }
    }

Alternatives

Point-And-Click

The command-line involves typing, while point-and-click is a simpler interface style based on showing available options and letting the user click on one of them.

Another means of issuing commands is with “Drag-And-Drop”, such as dragging an item into a trashcan to delete it.

Related Patterns

Instead of processing the command upon each keystroke, use “Submission Throttling” to analyse it on frequent intervals.

Feedback such as input validation and result prediction is usually shown in a “Status Area”.

Some parts of the command can be “Highlight”ed to point out errors, incomplete text, and so on. Also, aspects of the “Status Area” can be “Highlight”ed to help with prediction.

If it takes more than a second to process the command-line, consider showing a “Progress Indicator”.

Introduce a “Browser-Side Cache” to retain the server's analysis of partial command.

Consider creating a “Fat Client” which tries to handle as much of the analysis itself, thus reducing server calls.

“Live Search” is an extreme version of Live Command-Line applied to search, where the command is effectively executed while the user types.

Providing “Suggestion”s is one characteristic of Live Command-Lines.

Want To Know More?

Live Wiki Version for Live Command-Line