This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| Add Tab-Completion To Your Console Submitted by

This is one of those things which is either wanky or makes a game/app look professional. The idea is to complete a command for the user when they press tab, a la tcsh, bash & friends.
To do this, I store all commands and console variables in a single stl map (StateManager is the class which looks after console commands and variables, but not the drawing of the console):

            typedef void (StateManager::*action)(const string &) throw();
            typedef struct {
                    action act;		// what to do when we get this command
                    string help;		// help/description string for this command
            } cmd_desc;
            typedef map<string, cmd_desc cmd_map;
            typedef map<string, Variable * var_map;

    	cmd_map commands;
    	var_map variables;

For variables, act points to a member method which looks up the variable name in another map and does stuff to it. The parameter to action is the complete command line.
To have the command completion, you need to find the set of possible commands and variables that start with what is already on the command line and then find the longest string that they have in common at their beginning. The following is called with the command so far when the user presses tab and returns a string that should be appended to the command line:

    string StateManager::tabComplete(const string &s)
    {
            cmd_map::iterator ci=commands.begin();
            vector<string possibles;		// possible matching commands
            istrstream ss(s.c_str());		// parse command line at spaces
            string cmd, arg, thisone, lcd;
            int len, nlen, plen;

            ss  cmd;
            if(ss  arg)			// there is more than just a command
                    return "";		// filename completion omitted for brevity

            len=cmd.length();		// how much to go on
            while(ci != commands.end()){
                    thisone=ci-first.substr(0, len);

                    if(thisone  cmd)       // passed the possibles
                            break;		// due ordering of map traversal

                    if(thisone == cmd)
                            possibles.push_back(ci-first);

                    ++ci;
            }

            if(possibles.empty())		// nothing matching
                    return "";

            arg=possibles[0];
            lcd=arg.substr(len, arg.length());
            plen=lcd.length();

            if(possibles.size() == 1)	// one match, append space & return it
                    return lcd+" ";

            for(size_t i=1;i<possibles.size();i++){
                    nlen=matching_chars(lcd, possibles[i].substr(len, possibles[i].length()));
                    if(nlen < plen){
                            plen=nlen;
                            lcd=lcd.substr(0, plen);
                    }

                    arg+=" "+possibles[i];
            }

            if(!lcd.length())		// nothing in common =
                    console-writeLine(arg);// any of them are possible, print them all out

            return lcd;			// common prefix to all possibilities
    }

    // yes, this is probably reinventing the wheel
    int matching_chars(const string &a, const string &b) throw()
    {
            int ml=min(a.length(), b.length());

            for(int i=0;i<ml;i++)
                    if(a[i] != b[i])
                            return i;

            return ml;
    }

If you want this code, take the algorithm. The code is from my engine which is under the LGPL so you might not want to just copy & paste.
If you want it a little simpler, be like Quake and just fill in the first command that matches. But I find that much more annoying than the tcsh-style behaviour - it always fills in something you don't expect.
William Brodie-Tyrrell

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.