/*
 * HelpOps.cs --
 *
 * Copyright (c) 2007-2012 by Joe Mistachkin.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: $
 */

#if SHELL
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
#endif

using Eagle._Attributes;

#if SHELL
using Eagle._Components.Public;
using Eagle._Constants;
using Eagle._Containers.Private;
using Eagle._Containers.Public;
using Eagle._Interfaces.Public;
#endif

#if !CONSOLE && SHELL
using ConsoleColor = Eagle._Components.Public.ConsoleColor;
#endif

namespace Eagle._Components.Private
{
    [ObjectId("35ce3166-9f74-460f-aa62-5cb27798ef66")]
    internal static class HelpOps
    {
        #region Private Constants
        #region Help Formatting
#if SHELL
        private const int UsageWidth = 71; /* magic */

        private const string lengthPlaceholder = "X";
        private const int OptionsPerLine = 2; /* magic */

#if INTERACTIVE_COMMANDS
        private const int columnPadding = 2;

        private const int GroupsPerLine = 6; /* magic */
        private const int CommandsPerLine = 6; /* magic */

        private const string groupOnlyFormat = "{0}";
        private const string groupListFormat = "{0,X}{1}"; /* NOTE: 'X' is replaced by an integer. */
        private const string groupAndListFormat = "{0} -- {1}";

        private const string commandOnlyFormat = "{0}{1}";
        private const string commandListFormat = "{0,X}{1}"; /* NOTE: 'X' is replaced by an integer. */
        private const string commandWithArgumentsFormat = "{0}{1} {2}";
        private const string commandAndDescriptionFormat = "{0}{1} -- {2}";
        private const string commandWithArgumentsAndDescriptionFormat = "{0}{1} {2} -- {3}";
#endif

        private const string certificateSubjectPrefix = " - ";

        private const string bannerFormat = "{0} v{1} {2}{3} {4} ({5}){6}";
        private const string bannerTextFormat = " {0}";
        private const string bannerOfficialFormat = "{0}";
        private const string bannerReleaseFormat = "{0}";

        private const string versionUpdateFormat = "{2}, {3} @ {0}{1}";
        private const string versionSourceFormat = "[{0}] {1}";

        private const string defaultUri = "http://localhost/";
        private const string defaultSourceId = "0000000000000000000000000000000000000000";
        private const string defaultSourceTimeStamp = "0000-00-00 00:00:00 UTC";

        private const string optionFormat = "{0,X}"; /* NOTE: 'X' is replaced by an integer. */
#endif
        #endregion
        #endregion

        ///////////////////////////////////////////////////////////////////////////////////////////////

        #region Private Data
#if SHELL && INTERACTIVE_COMMANDS
        private static readonly object syncRoot = new object();
        private static StringListDictionary commandGroups = null;
        private static StringPairDictionary commandHelp = null;
#endif
        #endregion

        ///////////////////////////////////////////////////////////////////////////////////////////////

        #region Private Help Support Methods
#if SHELL && INTERACTIVE_COMMANDS
        private static string MaybeAdjustHelpItemTopic(
            string topic,
            ref string prefix
            )
        {
            if (!String.IsNullOrEmpty(topic))
            {
                foreach (string localPrefix in new string[] {
                    ShellOps.InteractiveSystemCommandPrefix,
                    ShellOps.InteractiveCommandPrefix })
                {
                    if (String.IsNullOrEmpty(localPrefix))
                        continue;

                    if (topic.StartsWith(localPrefix,
                            StringOps.SystemNoCaseStringComparisonType))
                    {
                        prefix = localPrefix;
                        return topic.Substring(localPrefix.Length);
                    }
                }
            }

            prefix = ShellOps.DefaultInteractiveCommandPrefix;
            return topic;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static string FormatHelpItem( /* CANNOT RETURN NULL */
            Interpreter interpreter,     /* in */
            StringListDictionary groups, /* in */
            StringPairDictionary help,   /* in */
            string topic,                /* in */
            bool summary                 /* in */
            )
        {
            if (topic == null)
                return "Invalid help topic.";

            if (groups != null)
            {
                StringList helpGroup;

                if (groups.TryGetValue(topic, out helpGroup) &&
                    (helpGroup != null))
                {
                    if (helpGroup.Count > 0)
                    {
                        return String.Format(groupAndListFormat, topic,
                            GenericOps<string>.ListToEnglish(helpGroup,
                                null, ", ", "and "));
                    }
                    else
                    {
                        return String.Format(groupOnlyFormat, topic);
                    }
                }
            }

            if (help != null)
            {
                string prefix = null;

                topic = MaybeAdjustHelpItemTopic(topic, ref prefix);

                IPair<string> helpItem;

                if (help.TryGetValue(topic, out helpItem))
                {
                    if (helpItem != null)
                    {
                        if ((helpItem.X != null) && (helpItem.Y != null))
                        {
                            if (summary)
                            {
                                return String.Format(
                                    commandWithArgumentsFormat, prefix, topic,
                                    helpItem.X);
                            }
                            else
                            {
                                return String.Format(
                                    commandWithArgumentsAndDescriptionFormat,
                                    prefix, topic, helpItem.X, helpItem.Y);
                            }
                        }
                        else if (helpItem.X != null)
                        {
                            if (summary)
                            {
                                return String.Format(
                                    commandWithArgumentsFormat, prefix, topic,
                                    helpItem.X);
                            }
                            else
                            {
                                return String.Format(
                                    commandAndDescriptionFormat, prefix, topic,
                                    helpItem.X);
                            }
                        }
                        else if (helpItem.Y != null)
                        {
                            if (summary)
                            {
                                return String.Format(
                                    commandOnlyFormat, prefix, topic);
                            }
                            else
                            {
                                return String.Format(
                                    commandAndDescriptionFormat, prefix, topic,
                                    helpItem.Y);
                            }
                        }
                        else
                        {
                            if (summary)
                            {
                                return String.Format(
                                    commandOnlyFormat, prefix, topic);
                            }
                            else
                            {
                                return String.Format(
                                    "No help is available for command {0}.",
                                    FormatOps.WrapOrNull(topic));
                            }
                        }
                    }
                    else
                    {
                        return String.Format(
                            "Invalid help item for command {0}.",
                            FormatOps.WrapOrNull(topic));
                    }
                }
                else
                {
                    IExecute execute = null;

                    if (interpreter.GetIExecuteViaResolvers(
                            interpreter.GetResolveEngineFlags(true),
                            topic, null, LookupFlags.HelpNoVerbose,
                            ref execute) == ReturnCode.Ok)
                    {
                        string syntax = GetSyntaxForIExecute(
                            execute, null);

                        if (syntax != null)
                            return syntax;
                    }
                }
            }
            else
            {
                return "No help available.";
            }

            //
            // NOTE: If no syntax help was available or the command was not
            //       found we simply return a suitable error message.
            //
            return String.Format(
                "There is no help topic {0}.", FormatOps.WrapOrNull(topic));
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        public static StringList GetInteractiveCommandNames(
            string pattern,
            bool noCase
            )
        {
            StringPairDictionary help = GetInteractiveCommandHelp(null);

            if (help != null)
            {
                StringList result = new StringList(); /* COPY */

                ReturnCode code;
                Result error = null;

                code = GenericOps<string>.FilterList(
                    new StringList(help.Keys), result, 0, Index.Invalid,
                    ToStringFlags.None, pattern, noCase, ref error);

                if (code == ReturnCode.Ok)
                    return result;
                else
                    DebugOps.Complain(code, error);
            }

            return null;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        public static StringPair GetInteractiveCommandHelpItem(
            string name
            )
        {
            if (name != null)
            {
                StringPairDictionary help = GetInteractiveCommandHelp(null);
                IPair<string> result;

                if ((help != null) &&
                    help.TryGetValue(name, out result) &&
                    (result != null))
                {
                    return new StringPair(result.X, result.Y); /* COPY */
                }
            }

            return null;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static StringListDictionary GetInteractiveCommandGroups(
            Interpreter interpreter
            )
        {
            StringListDictionary result = null;

            lock (syncRoot)
            {
                if (commandGroups == null)
                {
                    commandGroups = new StringListDictionary();

                    ///////////////////////////////////////////////////////////////////////////////////

                    #region Help Topic Group Names
                    commandGroups.Add("debugger", new StringList());
                    commandGroups.Add("engine", new StringList());
                    commandGroups.Add("flags", new StringList());

#if HISTORY
                    commandGroups.Add("history", new StringList());
#endif

                    commandGroups.Add("host", new StringList());
                    commandGroups.Add("info", new StringList());
                    commandGroups.Add("result", new StringList());
                    commandGroups.Add("shell", new StringList());
                    commandGroups.Add("state", new StringList());
                    commandGroups.Add("diagnostic", new StringList());
                    commandGroups.Add("trace", new StringList());
                    commandGroups.Add("view", new StringList());
                    #endregion

                    ///////////////////////////////////////////////////////////////////////////////////

                    #region Shell/Debugger Commands
#if DEBUGGER
                    commandGroups["debugger"].Add("break");
                    commandGroups["debugger"].Add("deval");
                    commandGroups["debugger"].Add("dsubst");
#endif

                    commandGroups["debugger"].Add("go");
                    commandGroups["debugger"].Add("halt");

#if DEBUGGER
                    commandGroups["debugger"].Add("reset");
                    commandGroups["debugger"].Add("resume");
                    commandGroups["debugger"].Add("run");
                    commandGroups["debugger"].Add("step");
                    commandGroups["debugger"].Add("suspend");
#endif
                    #endregion

                    ///////////////////////////////////////////////////////////////////////////////////

                    #region Engine Related Commands
#if CONSOLE
                    commandGroups["engine"].Add("cancel");
#endif

#if CALLBACK_QUEUE
                    commandGroups["engine"].Add("clearq");
#endif

                    commandGroups["engine"].Add("eval");
                    commandGroups["engine"].Add("fresc");
                    commandGroups["engine"].Add("fresh");
                    commandGroups["engine"].Add("queue");
                    commandGroups["engine"].Add("resc");
                    commandGroups["engine"].Add("resh");
                    #endregion

                    ///////////////////////////////////////////////////////////////////////////////////

                    #region Flag Introspection & Manipulation Commands
                    commandGroups["flags"].Add("ceflags");
                    commandGroups["flags"].Add("cflags");
                    commandGroups["flags"].Add("evflags");
                    commandGroups["flags"].Add("exflags");
                    commandGroups["flags"].Add("hflags");
                    commandGroups["flags"].Add("ieflags");
                    commandGroups["flags"].Add("ievflags");
                    commandGroups["flags"].Add("iexflags");
                    commandGroups["flags"].Add("iflags");
                    commandGroups["flags"].Add("isflags");
                    commandGroups["flags"].Add("leflags");
                    commandGroups["flags"].Add("levflags");
                    commandGroups["flags"].Add("lexflags");
                    commandGroups["flags"].Add("lhflags");
                    commandGroups["flags"].Add("lsflags");

#if NOTIFY || NOTIFY_OBJECT
                    commandGroups["flags"].Add("nflags");
                    commandGroups["flags"].Add("ntypes");
#endif

                    commandGroups["flags"].Add("pflags");
                    commandGroups["flags"].Add("prflags");
                    commandGroups["flags"].Add("scflags");
                    commandGroups["flags"].Add("seflags");
                    commandGroups["flags"].Add("sflags");
                    #endregion

                    ///////////////////////////////////////////////////////////////////////////////////

                    #region History Related Commands
#if HISTORY
                    commandGroups["history"].Add("histclear");
                    commandGroups["history"].Add("histfile");
                    commandGroups["history"].Add("histload");
                    commandGroups["history"].Add("histsave");
#endif
                    #endregion

                    ///////////////////////////////////////////////////////////////////////////////////

                    #region Interpreter Host Related Commands
                    commandGroups["host"].Add("canexit");
                    commandGroups["host"].Add("color");
                    commandGroups["host"].Add("exceptions");
                    commandGroups["host"].Add("hcancel");
                    commandGroups["host"].Add("hexit");
                    commandGroups["host"].Add("rehash");
                    commandGroups["host"].Add("style");
                    commandGroups["host"].Add("useattach");
                    #endregion

                    ///////////////////////////////////////////////////////////////////////////////////

                    #region General Information Commands
                    commandGroups["info"].Add("about");
                    commandGroups["info"].Add("check");
                    commandGroups["info"].Add("help");
                    commandGroups["info"].Add("usage");
                    commandGroups["info"].Add("version");
                    #endregion

                    ///////////////////////////////////////////////////////////////////////////////////

                    #region Result Introspection & Manipulation Commands
                    commandGroups["result"].Add("clearr");
                    commandGroups["result"].Add("copyr");
                    commandGroups["result"].Add("fresr");
                    commandGroups["result"].Add("lrinfo");
                    commandGroups["result"].Add("mover");
                    commandGroups["result"].Add("mrinfo");

#if PREVIOUS_RESULT
                    commandGroups["result"].Add("nextr");
#endif

                    commandGroups["result"].Add("nullr");
                    commandGroups["result"].Add("overr");

#if PREVIOUS_RESULT
                    commandGroups["result"].Add("prevr");
#endif

                    commandGroups["result"].Add("resr");
                    commandGroups["result"].Add("rinfo");
                    commandGroups["result"].Add("setr");
                    commandGroups["result"].Add("sresult");
                    #endregion

                    ///////////////////////////////////////////////////////////////////////////////////

                    #region Shell Control Commands
#if DEBUGGER
                    commandGroups["shell"].Add("again");
#endif

                    commandGroups["shell"].Add("cmd");
                    commandGroups["shell"].Add("done");
                    commandGroups["shell"].Add("exit");
                    commandGroups["shell"].Add("nop");

#if NATIVE && TCL
                    commandGroups["shell"].Add("tclinterp");
                    commandGroups["shell"].Add("tclsh");
#endif

                    commandGroups["shell"].Add("tclshrc");
                    #endregion

                    ///////////////////////////////////////////////////////////////////////////////////

                    #region Interpreter State Manipulation Commands
                    commandGroups["state"].Add("chans");
                    commandGroups["state"].Add("init");
                    commandGroups["state"].Add("purge");
                    commandGroups["state"].Add("relimit");
                    commandGroups["state"].Add("restc");
                    commandGroups["state"].Add("restv");
                    commandGroups["state"].Add("rlimit");
                    commandGroups["state"].Add("trustclr");
                    commandGroups["state"].Add("trustdir");
                    commandGroups["state"].Add("vout");
                    #endregion

                    ///////////////////////////////////////////////////////////////////////////////////

                    #region Diagnostic & Test Suite Commands
                    commandGroups["diagnostic"].Add("ptest");
                    commandGroups["diagnostic"].Add("test");
                    commandGroups["diagnostic"].Add("testdir");
                    commandGroups["diagnostic"].Add("testgc");
                    #endregion

                    ///////////////////////////////////////////////////////////////////////////////////

                    #region Trace Related Commands
                    commandGroups["trace"].Add("tcancel");
                    commandGroups["trace"].Add("tcode");
                    commandGroups["trace"].Add("tnewvalue");
                    commandGroups["trace"].Add("toldvalue");
                    #endregion

                    ///////////////////////////////////////////////////////////////////////////////////

                    #region Library State Introspection Commands
                    commandGroups["view"].Add("ainfo");
                    commandGroups["view"].Add("args");
                    commandGroups["view"].Add("cinfo");
                    commandGroups["view"].Add("complaint");
                    commandGroups["view"].Add("cuinfo");

#if DEBUGGER
                    commandGroups["view"].Add("dinfo");
#endif

                    commandGroups["view"].Add("dpath");
                    commandGroups["view"].Add("einfo");
                    commandGroups["view"].Add("eninfo");
                    commandGroups["view"].Add("finfo");
                    commandGroups["view"].Add("frinfo");
                    commandGroups["view"].Add("hinfo");

#if HISTORY
                    commandGroups["view"].Add("histinfo");
#endif

                    commandGroups["view"].Add("iinfo");
                    commandGroups["view"].Add("lfinfo");
                    commandGroups["view"].Add("oinfo");
                    commandGroups["view"].Add("show");
                    commandGroups["view"].Add("sinfo");
                    commandGroups["view"].Add("stack");
                    commandGroups["view"].Add("testinfo");
                    commandGroups["view"].Add("tinfo");
                    commandGroups["view"].Add("toinfo");
                    commandGroups["view"].Add("vinfo");
                    #endregion
                }

                ///////////////////////////////////////////////////////////////////////////////////////

                result = new StringListDictionary(commandGroups);

                ///////////////////////////////////////////////////////////////////////////////////////

                #region Extension Related Commands
                StringList names = null;

                GetInteractiveExtensionCommandNames(
                    interpreter, ShellOps.InteractiveCommandPrefix,
                    ref names);

                if ((names != null) && (names.Count > 0))
                    result.Add("extension", names);
                #endregion
            }

            return result;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static ArgumentList GetArguments(
            IProcedure procedure
            )
        {
            if (procedure == null)
                return null;

            return procedure.Arguments;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static string GetSyntax(
            ISyntax syntax,
            string @default
            )
        {
            if (syntax == null)
                return null;

            string result = syntax.Syntax;

            if (!String.IsNullOrEmpty(result))
                return result;

            return @default;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static string GetSyntaxForCommand(
            ICommand command,
            string @default
            )
        {
            string result = GetSyntax(command, null);

            if (!String.IsNullOrEmpty(result))
                return result;

            return @default;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static string GetSyntaxForProcedure(
            IProcedure procedure,
            string @default
            )
        {
            ArgumentList arguments = GetArguments(procedure);

            if ((arguments != null) && (arguments.Count > 0))
            {
                string result = arguments.ToRawString(
                    ToStringFlags.Decorated, Characters.Space.ToString());

                if (!String.IsNullOrEmpty(result))
                    return result;
            }

            ISyntax syntax = procedure as ISyntax;

            if (syntax != null)
                return GetSyntax(syntax, @default);

            return @default;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static string GetSyntaxForIExecute(
            IExecute execute,
            string @default
            )
        {
            ICommand command = execute as ICommand;

            if (command != null)
                return GetSyntaxForCommand(command, @default);

            IProcedure procedure = execute as IProcedure;

            if (procedure != null)
                return GetSyntaxForProcedure(procedure, @default);

            ISyntax syntax = execute as ISyntax;

            if (syntax != null)
                return GetSyntax(syntax, @default);

            Type type = execute != null ? execute.GetType() : null;

            if (type != null)
            {
                string result = FormatOps.TypeNameOrFullName(type);

                if (!String.IsNullOrEmpty(result))
                    return result;
            }

            return @default;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static string GetDescription(
            IIdentifier identifier,
            string @default
            )
        {
            if (identifier == null)
                return @default;

            string result = identifier.Description;

            if (!String.IsNullOrEmpty(result))
                return result;

            return @default;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static string GetDescriptionForCommand(
            ICommand command,
            string @default
            )
        {
            string result = GetDescription(command, null);

            if (!String.IsNullOrEmpty(result))
                return result;

            return @default;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static string GetDescriptionForProcedure(
            IProcedure procedure,
            string @default
            )
        {
            string result = GetDescription(procedure, null);

            if (!String.IsNullOrEmpty(result))
                return result;

            return @default;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static string GetDescriptionForIExecute(
            IExecute execute,
            string @default
            )
        {
            ICommand command = execute as ICommand;

            if (command != null)
                return GetDescriptionForCommand(command, @default);

            IProcedure procedure = execute as IProcedure;

            if (procedure != null)
                return GetDescriptionForProcedure(procedure, @default);

            IIdentifier identifier = execute as IIdentifier;

            if (identifier != null)
                return GetDescription(identifier, @default);

            return @default;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static void GetInteractiveExtensionCommandNames(
            Interpreter interpreter,
            string prefix,
            ref StringList names
            )
        {
            StringPairDictionary help = null;

            GetInteractiveExtensionCommandNamesOrHelp(interpreter,
                prefix, true, false, ref names, ref help);
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static void GetInteractiveExtensionCommandHelp(
            Interpreter interpreter,
            string prefix,
            ref StringPairDictionary help
            )
        {
            StringList names = null;

            GetInteractiveExtensionCommandNamesOrHelp(interpreter,
                prefix, false, true, ref names, ref help);
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static void GetInteractiveExtensionCommandNamesOrHelp(
            Interpreter interpreter,
            string prefix,
            bool getNames,
            bool getHelp,
            ref StringList names,
            ref StringPairDictionary help
            )
        {
            if (interpreter == null)
                return;

            string pattern = null;

            if (prefix != null)
                pattern = prefix + Characters.Asterisk;

            StringList[] localNames = {
                null, /* matching command names */
                null, /* matching procedure names */
                null, /* matching execute names */
                null, /* matching hidden command names */
                null, /* matching hidden procedure names */
                null  /* matching hidden execute names */
            };

            if (((interpreter.ListCommands(
                        CommandFlags.None, CommandFlags.None,
                        false, false, pattern, false, false,
                        ref localNames[0]) == ReturnCode.Ok) &&
                    (localNames[0] != null) && (localNames[0].Count > 0)) ||
                ((interpreter.ListProcedures(
                        ProcedureFlags.None, ProcedureFlags.None,
                        false, false, pattern, false, false,
                        ref localNames[1]) == ReturnCode.Ok) &&
                    (localNames[1] != null) && (localNames[1].Count > 0)) ||
                ((interpreter.ListIExecutes(
                        pattern, false, false,
                        ref localNames[2]) == ReturnCode.Ok) &&
                    (localNames[2] != null) && (localNames[2].Count > 0)) ||
                ((interpreter.ListHiddenCommands(
                        CommandFlags.None, CommandFlags.None,
                        false, false, pattern, false, false,
                        ref localNames[3]) == ReturnCode.Ok) &&
                    (localNames[3] != null) && (localNames[3].Count > 0)) ||
                ((interpreter.ListHiddenProcedures(
                        ProcedureFlags.None, ProcedureFlags.None,
                        false, false, pattern, false, false,
                        ref localNames[4]) == ReturnCode.Ok) &&
                    (localNames[4] != null) && (localNames[4].Count > 0)) ||
                ((interpreter.ListHiddenIExecutes(
                        pattern, false, false,
                        ref localNames[5]) == ReturnCode.Ok) &&
                    (localNames[5] != null) && (localNames[5].Count > 0)))
            {
                if (getNames && (names == null))
                    names = new StringList();

                if (getHelp && (help == null))
                    help = new StringPairDictionary();

                ///////////////////////////////////////////////////////////////////////////////////////

                if (localNames[0] != null)
                {
                    foreach (string name in localNames[0])
                    {
                        if (name == null)
                            continue;

                        string newName = (prefix != null) ?
                            name.Substring(prefix.Length) : name;

                        if (getNames)
                            names.Add(newName);

                        if (getHelp)
                        {
                            ICommand command = null;

                            if (interpreter.GetCommand(
                                    name, LookupFlags.Default,
                                    ref command) != ReturnCode.Ok)
                            {
                                continue;
                            }

                            help[newName] = new StringPair(GetSyntaxForCommand(
                                command, null), GetDescriptionForCommand(command,
                                    "Interactive extension command."));
                        }
                    }
                }

                ///////////////////////////////////////////////////////////////////////////////////////

                if (localNames[1] != null)
                {
                    foreach (string name in localNames[1])
                    {
                        if (name == null)
                            continue;

                        string newName = (prefix != null) ?
                            name.Substring(prefix.Length) : name;

                        if (getNames)
                            names.Add(newName);

                        if (getHelp)
                        {
                            IProcedure procedure = null;

                            if (interpreter.GetProcedure(
                                    name, LookupFlags.Default,
                                    ref procedure) != ReturnCode.Ok)
                            {
                                continue;
                            }

                            help[newName] = new StringPair(GetSyntaxForProcedure(
                                procedure, null), GetDescriptionForProcedure(procedure,
                                    "Interactive extension procedure."));
                        }
                    }
                }

                ///////////////////////////////////////////////////////////////////////////////////////

                if (localNames[2] != null)
                {
                    foreach (string name in localNames[2])
                    {
                        if (name == null)
                            continue;

                        string newName = (prefix != null) ?
                            name.Substring(prefix.Length) : name;

                        if (getNames)
                            names.Add(newName);

                        if (getHelp)
                        {
                            IExecute execute = null;

                            if (interpreter.GetIExecute(
                                    name, LookupFlags.Default,
                                    ref execute) != ReturnCode.Ok)
                            {
                                continue;
                            }

                            help[newName] = new StringPair(GetSyntaxForIExecute(
                                execute, null), GetDescriptionForIExecute(execute,
                                    "Interactive extension."));
                        }
                    }
                }

                ///////////////////////////////////////////////////////////////////////////////////////

                if (localNames[3] != null)
                {
                    foreach (string name in localNames[3])
                    {
                        if (name == null)
                            continue;

                        string newName = (prefix != null) ?
                            name.Substring(prefix.Length) : name;

                        if (getNames)
                            names.Add(newName);

                        if (getHelp)
                        {
                            ICommand command = null;

                            if (interpreter.GetHiddenCommand(
                                    name, LookupFlags.Default,
                                    ref command) != ReturnCode.Ok)
                            {
                                continue;
                            }

                            help[newName] = new StringPair(GetSyntaxForCommand(
                                command, null), GetDescriptionForCommand(command,
                                    "Interactive extension command (hidden)."));
                        }
                    }
                }

                ///////////////////////////////////////////////////////////////////////////////////////

                if (localNames[4] != null)
                {
                    foreach (string name in localNames[4])
                    {
                        if (name == null)
                            continue;

                        string newName = (prefix != null) ?
                            name.Substring(prefix.Length) : name;

                        if (getNames)
                            names.Add(newName);

                        if (getHelp)
                        {
                            IProcedure procedure = null;

                            if (interpreter.GetHiddenProcedure(
                                    name, LookupFlags.Default,
                                    ref procedure) != ReturnCode.Ok)
                            {
                                continue;
                            }

                            help[newName] = new StringPair(GetSyntaxForProcedure(
                                procedure, null), GetDescriptionForProcedure(procedure,
                                    "Interactive extension procedure (hidden)."));
                        }
                    }
                }

                ///////////////////////////////////////////////////////////////////////////////////////

                if (localNames[5] != null)
                {
                    foreach (string name in localNames[5])
                    {
                        if (name == null)
                            continue;

                        string newName = (prefix != null) ?
                            name.Substring(prefix.Length) : name;

                        if (getNames)
                            names.Add(newName);

                        if (getHelp)
                        {
                            IExecute execute = null;

                            if (interpreter.GetHiddenIExecute(
                                    name, LookupFlags.Default,
                                    ref execute) != ReturnCode.Ok)
                            {
                                continue;
                            }

                            help[newName] = new StringPair(GetSyntaxForIExecute(
                                execute, null), GetDescriptionForIExecute(execute,
                                    "Interactive extension (hidden)."));
                        }
                    }
                }
            }
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static StringPairDictionary GetInteractiveCommandHelp(
            Interpreter interpreter
            )
        {
            StringPairDictionary result = null;

            lock (syncRoot)
            {
                if (commandHelp == null)
                {
                    string flagHelp = String.Format(
                        "Where \"flags\" is a list of zero or more values, separated by spaces or " +
                        "commas, which may be prefixed by \"{0}\" (add), \"{1}\" (remove), \"{2}\" " +
                        "(set), or \"{3}\" (set, then add).  If no prefix is specified, \"{4}\" " +
                        "(set, then add) is assumed.  Available flags are: {5}.", EnumOps.AddFlagOperator,
                        EnumOps.RemoveFlagOperator, EnumOps.SetFlagOperator, EnumOps.SetAddFlagOperator,
                        EnumOps.DefaultFlagOperator, "{0}");

                    string createFlagsHelpItem = String.Format(flagHelp,
                        GenericOps<string>.ListToEnglish(
                            new StringSortedList(Enum.GetNames(typeof(CreateFlags))),
                            String.Empty, ", ", "and "));

                    string scriptFlagsHelpItem = String.Format(flagHelp,
                        GenericOps<string>.ListToEnglish(
                            new StringSortedList(Enum.GetNames(typeof(ScriptFlags))),
                            String.Empty, ", ", "and "));

                    string engineFlagsHelpItem = String.Format(flagHelp,
                        GenericOps<string>.ListToEnglish(
                            new StringSortedList(Enum.GetNames(typeof(EngineFlags))),
                            String.Empty, ", ", "and "));

                    string interpreterFlagsHelpItem = String.Format(flagHelp,
                        GenericOps<string>.ListToEnglish(
                            new StringSortedList(Enum.GetNames(typeof(InterpreterFlags))),
                            String.Empty, ", ", "and "));

                    string substitutionFlagsHelpItem = String.Format(flagHelp,
                        GenericOps<string>.ListToEnglish(
                            new StringSortedList(Enum.GetNames(typeof(SubstitutionFlags))),
                            String.Empty, ", ", "and "));

                    string eventFlagsHelpItem = String.Format(flagHelp,
                        GenericOps<string>.ListToEnglish(
                            new StringSortedList(Enum.GetNames(typeof(EventFlags))),
                            String.Empty, ", ", "and "));

                    string expressionFlagsHelpItem = String.Format(flagHelp,
                        GenericOps<string>.ListToEnglish(
                            new StringSortedList(Enum.GetNames(typeof(ExpressionFlags))),
                            String.Empty, ", ", "and "));

                    string headerFlagsHelpItem = String.Format(flagHelp,
                        GenericOps<string>.ListToEnglish(
                            new StringSortedList(Enum.GetNames(typeof(HeaderFlags))),
                            String.Empty, ", ", "and "));

                    string pluginFlagsHelpItem = String.Format(flagHelp,
                        GenericOps<string>.ListToEnglish(
                            new StringSortedList(Enum.GetNames(typeof(PluginFlags))),
                            String.Empty, ", ", "and "));

                    string procedureFlagsHelpItem = String.Format(flagHelp,
                        GenericOps<string>.ListToEnglish(
                            new StringSortedList(Enum.GetNames(typeof(ProcedureFlags))),
                            String.Empty, ", ", "and "));

#if NOTIFY || NOTIFY_OBJECT
                    string notifyTypesHelpItem = String.Format(flagHelp,
                        GenericOps<string>.ListToEnglish(
                            new StringSortedList(Enum.GetNames(typeof(NotifyType))),
                            String.Empty, ", ", "and "));

                    string notifyFlagsHelpItem = String.Format(flagHelp,
                        GenericOps<string>.ListToEnglish(
                            new StringSortedList(Enum.GetNames(typeof(NotifyFlags))),
                            String.Empty, ", ", "and "));
#endif

                    commandHelp = new StringPairDictionary();

                    commandHelp.Add("about",
                        new StringPair(null,
                            "Displays the version summary and licensing information."));

#if DEBUGGER
                    commandHelp.Add("again",
                        new StringPair(null,
                            "Processes the previous interactive input again."));
#endif

                    commandHelp.Add("ainfo",
                        new StringPair(null,
                            "Displays the argument information for this interactive debuggging session."));

                    commandHelp.Add("args",
                        new StringPair(null,
                            "Displays the command line arguments as they were passed to this interactive debuggging session."));

#if DEBUGGER
                    commandHelp.Add("break",
                        new StringPair(null,
                            "Enters a new interactive debugging session."));
#endif

#if CONSOLE
                    commandHelp.Add("cancel",
                        new StringPair(null,
                            "Initiates script cancellation for all interpreters."));
#endif

                    commandHelp.Add("canexit",
                        new StringPair(null,
                            "Toggles whether scripts are allowed to exit the application."));

                    commandHelp.Add("ceflags",
                        new StringPair("?flags?",
                            "Displays or sets the context engine flags for the interactive interpreter.  " + engineFlagsHelpItem));

                    commandHelp.Add("cflags",
                        new StringPair("?flags?",
                            "Displays or sets the creation flags for the interactive interpreter.  " + createFlagsHelpItem));

                    commandHelp.Add("chans",
                        new StringPair("?replace?", String.Format(
                            "Adds or replaces the standard channels \"{0}\", \"{1}\", and \"{2}\" for the interactive interpreter.",
                            StandardChannel.Input, StandardChannel.Output, StandardChannel.Error)));

                    commandHelp.Add("check",
                        new StringPair("?wantScripts? ?quiet? ?prompt? ?automatic? ?actionType? ?releaseType?", String.Format(
                            "Checks the distribution site \"{0}\" to see if this is the latest build of the script engine.  " +
                            "Optionally, it can either fetch the latest release file of the specified type " +
                            "(e.g. \"source\", \"setup\", or \"binary\") or launch the external updater and then exit.  " +
                            "Alternatively, checks for any update scripts applicable to the current build of the script engine.",
                            GlobalState.GetAssemblyUpdateBaseUri())));

                    commandHelp.Add("cinfo",
                        new StringPair(null,
                            "Displays the control information for the interactive interpreter, such as whether the " +
                            "script in progress is being canceled."));

#if CALLBACK_QUEUE
                    commandHelp.Add("clearq",
                        new StringPair(null,
                            "Clears the callback queue for the interactive interpreter."));
#endif

                    /* LOCAL RESULT */
                    commandHelp.Add("clearr",
                        new StringPair(null,
                            "Clears the local result.  The master result is untouched."));

                    commandHelp.Add("cmd",
                        new StringPair("?arg ...?",
                            "Executes the \"Command Processor\" (i.e. shell) configured for the operating system " +
                            "with the specified arguments."));

                    commandHelp.Add("color",
                        new StringPair(null,
                            "Toggles whether color is used on the console."));

                    commandHelp.Add("complaint",
                        new StringPair(null,
                            "Displays the previously stored complaint for the interactive interpreter."));

                    /* LOCAL/MASTER RESULT */
                    commandHelp.Add("copyr",
                        new StringPair(null,
                            "Copies the master result into the local result.  The master result is untouched."));

                    commandHelp.Add("cuinfo",
                        new StringPair(null,
                            "Displays the custom information for the host, if any."));

#if DEBUGGER
                    commandHelp.Add("deval",
                        new StringPair("arg ?arg ...?",
                            "Evaluates the specified arguments using the isolated debugger interpreter."));

                    commandHelp.Add("dinfo",
                        new StringPair(null,
                            "Displays the debugger information for this interactive debuggging session."));
#endif

                    commandHelp.Add("done",
                        new StringPair("?code? ?result?",
                            "Unconditionally exits this interactive debuggging session."));

                    commandHelp.Add("dpath",
                        new StringPair(null,
                            "Displays the path information for the interactive interpreter."));

#if DEBUGGER
                    commandHelp.Add("dsubst",
                        new StringPair("?-nobackslashes? ?-nocommands? ?-novariables? string",
                            "Substitutes the specified arguments using the isolated debugger interpreter."));
#endif

                    commandHelp.Add("einfo",
                        new StringPair(null,
                            "Displays the engine status information for the interactive interpreter."));

                    commandHelp.Add("eninfo",
                        new StringPair(null,
                            "Displays the entity summary information for the interactive interpreter."));

                    commandHelp.Add("eval",
                        new StringPair("arg ?arg ...?",
                            "Evaluates the specified arguments using the interactive interpreter."));

                    commandHelp.Add("evflags",
                        new StringPair("?flags?",
                            "Displays or sets the event flags for the interactive interpreter.  " + eventFlagsHelpItem));

                    commandHelp.Add("exceptions",
                        new StringPair(null,
                            "Toggles how exceptional return codes are formatted on the console."));

                    commandHelp.Add("exflags",
                        new StringPair("?flags?",
                            "Displays or sets the expression flags for the interactive interpreter.  " + expressionFlagsHelpItem));

                    commandHelp.Add("exit",
                        new StringPair(null,
                            "Exits the interactive interpreter immediately."));

                    commandHelp.Add("finfo",
                        new StringPair(null,
                            "Displays the flags for the interactive interpreter and the flags that were passed to this " +
                            "interactive debuggging session."));

                    commandHelp.Add("fresc",
                        new StringPair(null,
                            "Toggles whether script cancellation flags are forcibly reset before interactive input."));

                    commandHelp.Add("fresh",
                        new StringPair(null,
                            "Toggles whether the halt flag is forcibly reset before interactive input."));

                    /* LOCAL/MASTER RESULT */
                    commandHelp.Add("fresr",
                        new StringPair(null,
                            "Resets the master and local results in-place."));

                    commandHelp.Add("frinfo",
                        new StringPair("level ?all?",
                            "Displays detailed information about the specified call frame."));

                    commandHelp.Add("go",
                        new StringPair(null,
                            "When actively debugging, continues execution of the script in progress."));

                    commandHelp.Add("halt",
                        new StringPair(null,
                            "When actively debugging, halts execution of the script in progress and breaks out of all nested " +
                            "interactive debugging sessions immediately."));

                    commandHelp.Add("hcancel",
                        new StringPair(null,
                            "Queues an asynchronous event that causes the host to cancel pending evaluations."));

                    commandHelp.Add("help",
                        new StringPair("?topic? ?groups? ?commands?",
                            "Displays information on the specified help topic or a list of available help topics."));

                    commandHelp.Add("hexit",
                        new StringPair(null,
                            "Queues an asynchronous event that causes the host to exit (which may or may not terminate the entire application)."));

                    commandHelp.Add("hflags",
                        new StringPair("?flags?",
                            "Displays or sets the header display flags for the interactive interpreter.  " + headerFlagsHelpItem));

                    commandHelp.Add("hinfo",
                        new StringPair("?dimensions? ?formatting? ?colors? ?names?",
                            "Displays detailed information about the host for the interactive interpreter."));

#if HISTORY
                    commandHelp.Add("histclear",
                        new StringPair(null,
                            "Clears the command history for the interactive interpreter."));

                    commandHelp.Add("histfile",
                        new StringPair("?fileName?",
                            "Displays or sets the default file name to use when loading and saving the command history for the interactive interpreter."));

                    commandHelp.Add("histinfo",
                        new StringPair(null,
                            "Displays the command history for the interactive interpreter."));

                    commandHelp.Add("histload",
                        new StringPair("fileName",
                            "Loads the command history for the interactive interpreter."));

                    commandHelp.Add("histsave",
                        new StringPair("fileName",
                            "Saves the command history for the interactive interpreter."));
#endif

                    commandHelp.Add("ieflags",
                        new StringPair("?flags?",
                            "Displays or sets the interactive command engine flags for the interactive interpreter.  " + engineFlagsHelpItem));

                    commandHelp.Add("ievflags",
                        new StringPair("?flags?",
                            "Displays or sets the interactive command event flags for the interactive interpreter.  " + eventFlagsHelpItem));

                    commandHelp.Add("iexflags",
                        new StringPair("?flags?",
                            "Displays or sets the interactive command expression flags for the interactive interpreter.  " + expressionFlagsHelpItem));

                    commandHelp.Add("iflags",
                        new StringPair("?flags?",
                            "Displays or sets the instance flags for the interactive interpreter.  " + interpreterFlagsHelpItem));

                    commandHelp.Add("iinfo",
                        new StringPair(null,
                            "Displays information about the interactive interpreter."));

                    commandHelp.Add("init",
                        new StringPair("?shell? ?force?",
                            "Initializes the core or shell script library, optionally forcing it to reinitialize."));

                    commandHelp.Add("isflags",
                        new StringPair("?flags?",
                            "Displays or sets the interactive command substitution flags for the interactive interpreter.  " + substitutionFlagsHelpItem));

                    commandHelp.Add("leflags",
                        new StringPair("?flags?",
                            "Displays or sets the local engine flags for the interactive interpreter.  " + engineFlagsHelpItem));

                    commandHelp.Add("levflags",
                        new StringPair("?flags?",
                            "Displays or sets the local event flags for the interactive interpreter.  " + eventFlagsHelpItem));

                    commandHelp.Add("lexflags",
                        new StringPair("?flags?",
                            "Displays or sets the local expression flags for the interactive interpreter.  " + expressionFlagsHelpItem));

                    commandHelp.Add("lfinfo",
                        new StringPair(null,
                            "Displays the local flags and the flags for the interactive interpreter."));

                    commandHelp.Add("lhflags",
                        new StringPair("?flags?",
                            "Displays or sets the local header display flags for the interactive interpreter.  " + headerFlagsHelpItem));

                    /* LOCAL RESULT */
                    commandHelp.Add("lrinfo",
                        new StringPair(null,
                            "Displays detailed information about the local result, leaving it untouched.  " +
                            "The master result is untouched."));

                    commandHelp.Add("lsflags",
                        new StringPair("?flags?",
                            "Displays or sets the local substitution flags for the interactive interpreter.  " + substitutionFlagsHelpItem));

                    /* LOCAL/MASTER RESULT */
                    commandHelp.Add("mover",
                        new StringPair(null,
                            "Moves the local result into the master result.  The local result is reset."));

                    /* MASTER RESULT */
                    commandHelp.Add("mrinfo",
                        new StringPair("?previous?",
                            "Displays detailed information about the master result, leaving it untouched.  " +
                            "The local result is untouched."));

#if PREVIOUS_RESULT
                    /* LOCAL/PREVIOUS RESULT */
                    commandHelp.Add("nextr",
                        new StringPair(null,
                            "Sets the previous result for the interactive interpreter to the local result.  The master result is untouched."));
#endif

#if NOTIFY || NOTIFY_OBJECT
                    commandHelp.Add("nflags",
                        new StringPair("?flags?",
                            "Displays or sets the plugin notification flags for the interactive interpreter.  " + notifyFlagsHelpItem));
#endif

                    commandHelp.Add("nop",
                        new StringPair(null,
                            "Does nothing.  The local and master results are untouched."));

#if NOTIFY || NOTIFY_OBJECT
                    commandHelp.Add("ntypes",
                        new StringPair("?flags?",
                            "Displays or sets the plugin notification types for the interactive interpreter.  " + notifyTypesHelpItem));
#endif

                    /* LOCAL RESULT */
                    commandHelp.Add("nullr",
                        new StringPair(null,
                            "Sets the local result to null.  The master result is untouched."));

                    commandHelp.Add("oinfo",
                        new StringPair("name",
                            "Displays detailed information about the specified object."));

                    /* LOCAL RESULT */
                    commandHelp.Add("overr",
                        new StringPair("?options?",
                            "Sets the local result to the specified value.  The master result is untouched."));

                    commandHelp.Add("pflags",
                        new StringPair("?flags?",
                            "Displays or sets the plugin loader flags for the interactive interpreter.  " + pluginFlagsHelpItem));

#if PREVIOUS_RESULT
                    /* LOCAL/PREVIOUS RESULT */
                    commandHelp.Add("prevr",
                        new StringPair(null,
                            "Sets the local result to the previous result for the interactive interpreter.  The master result is untouched."));
#endif

                    commandHelp.Add("prflags",
                        new StringPair("?flags?",
                            "Displays or sets the procedure creation flags for the interactive interpreter.  " + procedureFlagsHelpItem));

                    commandHelp.Add("ptest",
                        new StringPair("?pattern? ?all?",
                            "Runs one or more plugin tests for the interactive interpreter."));

                    commandHelp.Add("purge",
                        new StringPair(null,
                            "Purges undefined variables in the current call frame for the interactive interpreter."));

                    commandHelp.Add("queue",
                        new StringPair(null,
                            "Enters queued input mode.  The next command or script entered will be queued for asynchronous evaluation."));

                    commandHelp.Add("rehash",
                        new StringPair("?profile? ?encoding?",
                            "Reloads the user-specific host profile."));

                    commandHelp.Add("relimit",
                        new StringPair("?limit?",
                            "Displays or sets the readiness limit for the interactive interpreter."));

                    commandHelp.Add("resc",
                        new StringPair(null,
                            "Resets the cancel and unwind flags for the interactive interpreter."));

#if DEBUGGER
                    commandHelp.Add("reset",
                        new StringPair(null,
                            "Resets the state of the debugger to its initial default, enabled and inactive."));
#endif

                    commandHelp.Add("resh",
                        new StringPair(null,
                            "Resets the halt flag for the interactive interpreter."));

                    /* LOCAL/MASTER RESULT */
                    commandHelp.Add("resr",
                        new StringPair(null,
                            "Resets the master and local results."));

                    commandHelp.Add("restc",
                        new StringPair("?strict?",
                            "Restores the core plugin for the interactive interpreter."));

                    commandHelp.Add("restv",
                        new StringPair(null,
                            "Restores the core variables for the interactive interpreter."));

#if DEBUGGER
                    commandHelp.Add("resume",
                        new StringPair(null,
                            "When actively debugging, restores the debugger to its previous state."));
#endif

                    /* LOCAL/MASTER RESULT */
                    commandHelp.Add("rinfo",
                        new StringPair(null,
                            "Displays the master and local results, leaving them untouched."));

                    commandHelp.Add("rlimit",
                        new StringPair("?limit?",
                            "Displays or sets the recursion limit for the interactive interpreter."));

#if DEBUGGER
                    commandHelp.Add("run",
                        new StringPair(null,
                            "When actively debugging, disables single-stepping and continues execution of the script in progress."));
#endif

                    commandHelp.Add("scflags",
                        new StringPair("?flags?",
                            "Displays or sets the script flags for the interactive interpreter.  " + scriptFlagsHelpItem));

                    commandHelp.Add("seflags",
                        new StringPair("?flags?",
                            "Displays or sets the shared engine flags for the interactive interpreter.  " + engineFlagsHelpItem));

                    /* LOCAL/MASTER RESULT */
                    commandHelp.Add("setr",
                        new StringPair(null,
                            "Copies the local result into the master result.  The local result is untouched."));

                    commandHelp.Add("sflags",
                        new StringPair("?flags?",
                            "Displays or sets the substitution flags for the interactive interpreter.  " + substitutionFlagsHelpItem));

                    /* LOCAL/MASTER RESULT */
                    commandHelp.Add("show",
                        new StringPair("?local? ?empty?",
                            "Displays the information that corresponds to the local header display flags."));

                    commandHelp.Add("sinfo",
                        new StringPair("?refresh?",
                            "Displays the native stack information for the interactive interpreter."));

                    /* LOCAL/MASTER RESULT */
                    commandHelp.Add("sresult",
                        new StringPair("?varName? ?master?",
                            "Stores the local or master result into the specified variable.  The local and master results are untouched."));

                    commandHelp.Add("stack",
                        new StringPair("?limit? ?all? ?info?",
                            "Displays the call stack for the interactive interpreter."));

#if DEBUGGER
                    commandHelp.Add("step",
                        new StringPair(null,
                            "Toggles whether single-stepping through scripts is enabled."));
#endif

                    commandHelp.Add("style",
                        new StringPair("?style?",
                            "Displays or sets the host output style for the debugger."));

#if DEBUGGER
                    commandHelp.Add("suspend",
                        new StringPair(null,
                            "When actively debugging, saves the debugger state and then temporarily suspends debugging."));
#endif

                    commandHelp.Add("tcancel",
                        new StringPair("?cancel?",
                            "Displays or sets the cancel flag within the variable trace information for this interactive debuggging session."));

#if NATIVE && TCL
                    commandHelp.Add("tclinterp",
                        new StringPair("?interp?",
                            "Displays or sets the the selected native Tcl interpreter for this interactive debuggging session, if available."));

                    commandHelp.Add("tclsh",
                        new StringPair(null,
                            "Toggles whether all scripts entered interactively are evaluated using the selected native Tcl interpreter, if available."));
#endif

                    commandHelp.Add("tclshrc",
                        new StringPair("?arg ...?", String.Format(
                            "Executes the \"Text Editor\" configured for the operating system to edit the \"{0}\" script file with the specified arguments.",
                            TclVars.RunCommandsFileName)));

                    commandHelp.Add("tcode",
                        new StringPair("?code?",
                            "Displays or sets the return code within the variable trace information for this interactive debuggging session."));

                    commandHelp.Add("test",
                        new StringPair("?pattern? ?all?",
                            "Runs one or more tests for the interactive interpreter."));

                    commandHelp.Add("testdir",
                        new StringPair("directory",
                            "Displays or sets the directory used when searching for test files matching a specific pattern."));

                    commandHelp.Add("testgc",
                        new StringPair("start", String.Format(
                             "Starts or stops the thread that collects garbage every {0} milliseconds.",
                             TestOps.gcSleepTime)));

                    commandHelp.Add("testinfo",
                        new StringPair(null,
                            "Displays the test suite information for the interactive interpreter."));

                    commandHelp.Add("tinfo",
                        new StringPair("?cached?",
                            "Displays the variable trace information for this interactive debuggging session or from the per-thread cache."));

                    commandHelp.Add("toinfo",
                        new StringPair(null,
                            "Displays the token information for this interactive debuggging session."));

                    commandHelp.Add("trustclr",
                        new StringPair(null,
                            "Clears the list of trusted directories for the interactive interpreter."));

                    commandHelp.Add("trustdir",
                        new StringPair("directory",
                            "Displays or adds to the list of trusted directories for the interactive interpreter."));

                    commandHelp.Add("toldvalue",
                        new StringPair("?value?",
                            "Displays or sets the old value within the variable trace information for this interactive debuggging session."));

                    commandHelp.Add("tnewvalue",
                        new StringPair("?value?",
                            "Displays or sets the new value within the variable trace information for this interactive debuggging session."));

                    commandHelp.Add("usage",
                        new StringPair("?banner? ?legalese? ?options? ?environment?",
                            "Displays the complete command line syntax for the default shell and describes all the environment variables that may be used with it."));

                    commandHelp.Add("useattach",
                        new StringPair(null,
                            "Toggles whether an attempt will be made by the host to use the existing console, if any."));

                    commandHelp.Add("version",
                        new StringPair("?banner? ?legalese? ?source? ?update? ?plugins? ?options?",
                            "Displays detailed version information."));

                    commandHelp.Add("vinfo",
                        new StringPair("name ?links? ?searches? ?elements?",
                            "Displays detailed information about the specified variable."));

                    commandHelp.Add("vout",
                        new StringPair("?channel? ?enabled?",
                            "Enables, disables, or displays queued virtual output for a channel."));
                }

                ///////////////////////////////////////////////////////////////////////////////////////

                result = new StringPairDictionary(commandHelp);

                ///////////////////////////////////////////////////////////////////////////////////////

                GetInteractiveExtensionCommandHelp(
                    interpreter, ShellOps.InteractiveCommandPrefix,
                    ref result);
            }

            return result;
        }
#endif

        ///////////////////////////////////////////////////////////////////////////////////////////////

#if SHELL
        private static bool HostTryWriteColor(
            IHost host,
            string value,
            bool newLine,
            ConsoleColor foregroundColor,
            ConsoleColor backgroundColor
            )
        {
            bool wrote = false;

            if (host != null)
            {
                try
                {
                    if (FlagOps.HasFlags(host.GetFlags(), HostFlags.AllColors, false))
                    {
                        if (newLine)
                            wrote = host.WriteLine(
                                value, foregroundColor, backgroundColor);
                        else
                            wrote = host.Write(
                                value, foregroundColor, backgroundColor);
                    }
                }
                catch
                {
                    // do nothing.
                }

                if (!wrote)
                    wrote = newLine ? host.WriteLine(value) : host.Write(value);
            }

            return wrote;
        }
#endif
        #endregion

        ///////////////////////////////////////////////////////////////////////////////////////////////

        #region Public Help Support Methods
#if SHELL
        public static bool WriteBanner(
            Interpreter interpreter,
            bool noRelease,
            bool noDescription,
            bool noOfficial,
            bool noTrusted
            )
        {
            if (interpreter != null)
            {
                IHost host = interpreter.Host;

                if (host != null)
                {
                    ConsoleColor bannerForegroundColor = _ConsoleColor.Default;
                    ConsoleColor bannerBackgroundColor = _ConsoleColor.Default;

                    interpreter.GetHostColors(
                        host, ColorName.Banner, ref bannerForegroundColor, ref bannerBackgroundColor);

                    Assembly assembly = GlobalState.GetAssembly();
                    string fileName = (assembly != null) ? assembly.Location : null;

                    string text = AttributeOps.GetAssemblyText(assembly);

                    string value = String.Format(bannerFormat,
                        GlobalState.GetPackageName(),
                        GlobalState.GetAssemblyVersion(),
                        AttributeOps.GetAssemblyTag(assembly),
                        !String.IsNullOrEmpty(text) ?
                            String.Format(bannerTextFormat, text) : String.Empty,
                        FormatOps.PackageDateTime(
                            AttributeOps.GetAssemblyDateTime(assembly)),
                        AttributeOps.GetAssemblyConfiguration(assembly),
                        RuntimeOps.GetCertificateSubject(fileName,
                            certificateSubjectPrefix, true));

                    if (!HostTryWriteColor(host, value, true, bannerForegroundColor, bannerBackgroundColor))
                        return false;

                    if (!noRelease)
                    {
                        string release = AttributeOps.GetAssemblyRelease(assembly);

                        if (!String.IsNullOrEmpty(release))
                        {
                            value = String.Format(bannerReleaseFormat, release);

                            if (!host.WriteLine())
                                return false;

                            if (!HostTryWriteColor(host, value, true, bannerForegroundColor, bannerBackgroundColor))
                                return false;
                        }
                    }

                    if (!noDescription)
                    {
                        value = String.Format(
                            Vars.PackageDescription, TclVars.VersionValue);

                        if (!host.WriteLine())
                            return false;

                        if (!HostTryWriteColor(host, value, true, bannerForegroundColor, bannerBackgroundColor))
                            return false;
                    }

                    if (!noOfficial)
                    {
                        ConsoleColor officialForegroundColor = _ConsoleColor.Default;
                        ConsoleColor officialBackgroundColor = _ConsoleColor.Default;

                        bool official = RuntimeOps.IsOfficial();

                        interpreter.GetHostColors(
                            host, official ? ColorName.Official : ColorName.Unofficial,
                            ref officialForegroundColor, ref officialBackgroundColor);

                        value = official ?
                            Vars.OfficialDescription : Vars.UnofficialDescription;

                        if (!host.WriteLine())
                            return false;

                        if (!HostTryWriteColor(host, value, true, officialForegroundColor, officialBackgroundColor))
                            return false;
                    }

                    if (!noTrusted)
                    {
                        ConsoleColor trustedForegroundColor = _ConsoleColor.Default;
                        ConsoleColor trustedBackgroundColor = _ConsoleColor.Default;

                        bool trusted = (RuntimeOps.GetFileTrusted(fileName) != null);

                        interpreter.GetHostColors(
                            host, trusted ? ColorName.Trusted : ColorName.Untrusted,
                            ref trustedForegroundColor, ref trustedBackgroundColor);

                        value = trusted ?
                            Vars.TrustedDescription : Vars.UntrustedDescription;

                        if (noOfficial && !host.WriteLine())
                            return false;

                        if (!HostTryWriteColor(host, value, true, trustedForegroundColor, trustedBackgroundColor))
                            return false;
                    }

                    return true;
                }
            }

            return false;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        public static bool WriteLegalese(
            Interpreter interpreter,
            bool summaryOnly
            )
        {
            if (interpreter != null)
            {
                IHost host = interpreter.Host;

                if (host != null)
                {
                    ConsoleColor foregroundColor = _ConsoleColor.Default;
                    ConsoleColor backgroundColor = _ConsoleColor.Default;

                    interpreter.GetHostColors(
                        host, ColorName.Legal, ref foregroundColor, ref backgroundColor);

                    Assembly assembly = GlobalState.GetAssembly();

                    string copyright = AttributeOps.GetAssemblyCopyright(
                        assembly, true);

                    bool wrote = false;

                    if (!String.IsNullOrEmpty(copyright))
                    {
                        if (HostTryWriteColor(host,
                                copyright, true, foregroundColor, backgroundColor))
                        {
                            wrote = true;
                        }
                        else
                        {
                            return false;
                        }
                    }

                    string license = AttributeOps.GetAssemblyLicense(assembly,
                        summaryOnly);

                    if (!String.IsNullOrEmpty(license))
                    {
                        if (wrote && !host.WriteLine())
                            return false;

                        if (HostTryWriteColor(host,
                                license, true, foregroundColor, backgroundColor))
                        {
                            wrote = true;
                        }
                        else
                        {
                            return false;
                        }
                    }

                    return true;
                }
            }

            return false;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        private static void WriteSectionHeader(
            IInteractiveHost interactiveHost,
            string text,
            int length
            )
        {
            if (interactiveHost != null)
            {
                if (!String.IsNullOrEmpty(text))
                {
                    interactiveHost.WriteLine(
                        String.Format("{0}{1}", Characters.HorizontalTab,
                        StringOps.StrRepeat(length, Characters.MinusSign)));

                    interactiveHost.WriteLine(
                        String.Format("{0}{1}", Characters.HorizontalTab,
                        StringOps.PadCenter(text, length, Characters.Space)));
                }

                interactiveHost.WriteLine(
                    String.Format("{0}{1}", Characters.HorizontalTab,
                    StringOps.StrRepeat(length, Characters.MinusSign)));
            }
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        public static ReturnCode WriteUsage(
            Interpreter interpreter,
            string error,
            bool showBanner,
            bool showLegalese,
            bool showOptions,
            bool showEnvironment,
            ref Result result
            )
        {
            try
            {
                if (interpreter != null)
                {
                    IInteractiveHost interactiveHost = interpreter.Host;

                    if (interactiveHost != null)
                    {
                        //
                        // NOTE: Did the caller specify an error message to
                        //       display?
                        //
                        bool showError = !String.IsNullOrEmpty(error);

                        //
                        // HACK: Honor the quiet mode for the interpreter.
                        //
                        if (showError && interpreter.ShouldBeQuiet())
                            showError = false;

                        //
                        // NOTE: If we are going to display the error message
                        //       do it now, before any other output.
                        //
                        if (showError)
                            interactiveHost.WriteResultLine(
                                ReturnCode.Error, error);

                        if (showBanner)
                        {
                            if (showError)
                                interactiveHost.WriteLine();

                            WriteBanner(interpreter, false, false, false, false);
                        }

                        if (showLegalese)
                        {
                            if (showError || showBanner)
                                interactiveHost.WriteLine();

                            WriteLegalese(interpreter, true);
                        }

                        bool showUsage = (showOptions || showEnvironment);
                        string executableFileName = Path.GetFileName(PathOps.GetExecutableName());

                        if (showUsage)
                        {
                            if (showError || showBanner || showLegalese)
                                interactiveHost.WriteLine();

                            WriteSectionHeader(interactiveHost, "Usage", UsageWidth);
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}{1} [options]",
                                Characters.HorizontalTab, executableFileName));
                        }

                        if (showOptions)
                        {
                            if (showError || showBanner || showLegalese || showUsage)
                                interactiveHost.WriteLine();

                            string argvFileName = ShellOps.GetArgumentsFileName(executableFileName);

                            WriteSectionHeader(interactiveHost, "Command Line Notes", UsageWidth);
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}The option names below are all case-insensitive.  All options, except\n" +
                                "{0}for \"-{1}\" and \"-{2}\" (see below), are processed in\n" +
                                "{0}the specified order.",
                                Characters.HorizontalTab, CommandLineOption.Library,
                                CommandLineOption.NoArgumentsFileName));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the file \"{1}\" exists in the executable directory,\n" +
                                "{0}its entire contents will be read and processed as though the file name\n" +
                                "{0}was specified via the \"-{2}\" option (see below) and then inserted\n" +
                                "{0}before any preexisting arguments, prior to further argument processing.",
                                Characters.HorizontalTab, argvFileName, CommandLineOption.Arguments));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If any unrecognized argument is encountered it will be passed to the\n" +
                                "{0}shell argument callback, if any; otherwise, an error will be generated.",
                                Characters.HorizontalTab));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If no arguments are supplied, or if at any time there are no arguments\n" +
                                "{0}remaining to be processed, the interactive loop will be entered (unless\n" +
                                "{0}it has been disabled).",
                                Characters.HorizontalTab));
                            interactiveHost.WriteLine();
                            WriteSectionHeader(interactiveHost, "Command Line Options", UsageWidth);
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <script> : Evaluates the specified script (whether or\n" +
                                "{0}                          not the script library has been initialized)\n" +
                                "{0}                          and then continues processing arguments.\n" +
                                "{0}                          Also see the \"-{2}\", \"-{3}\",\n" +
                                "{0}                          and \"-{4}\" options.",
                                Characters.HorizontalTab, CommandLineOption.AnyInitialize,
                                CommandLineOption.PreInitialize, CommandLineOption.Initialize,
                                CommandLineOption.PostInitialize));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <fileName> : Reads the entire specified file, attempting to\n" +
                                "{0}                        interpret each line as a list of arguments to\n" +
                                "{0}                        be inserted in order, replacing both the\n" +
                                "{0}                        \"-{1}\" option and the file name and then\n" +
                                "{0}                        continues processing arguments.  The literal\n" +
                                "{0}                        string \"{2}\" or \"{3}\" may be used to specify\n" +
                                "{0}                        the standard input stream as the file to read.",
                                Characters.HorizontalTab, CommandLineOption.Arguments,
                                CommandLineArgument.StandardInput, StandardChannel.Input));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : Waits until a key is pressed and then triggers a managed\n" +
                                "{0}         debugger break (useful for attaching a managed debugger before\n" +
                                "{0}         any arguments after it are processed).",
                                Characters.HorizontalTab, CommandLineOption.Break));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : Enables debug mode for the interpreter and then continues\n" +
                                "{0}         processing arguments (i.e. various strategically placed\n" +
                                "{0}         diagnostic messages are produced to help troubleshoot the\n" +
                                "{0}         startup process).",
                                Characters.HorizontalTab, CommandLineOption.Debug));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <encodingName> : Sets the encoding to use for script files\n" +
                                "{0}                           and then continues processing arguments.",
                                Characters.HorizontalTab, CommandLineOption.Encoding));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} [string ...] : Evaluates the specified string(s) and then\n" +
                                "{0}                         exits.",
                                Characters.HorizontalTab, CommandLineOption.Evaluate));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} [string ...] : Evaluates the specified base64 encoded\n" +
                                "{0}                                string(s) and then exits.  This is\n" +
                                "{0}                                useful for strings that may contain\n" +
                                "{0}                                complex quoting constructs that would\n" +
                                "{0}                                otherwise conflict with the operating\n" +
                                "{0}                                system command line quoting.",
                                Characters.HorizontalTab, CommandLineOption.EvaluateEncoded));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <fileName> [argument ...] : Evaluates the specified file and then\n" +
                                "{0}                                  exits.",
                                Characters.HorizontalTab, CommandLineOption.File));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : Enables forced initialization of the script library\n" +
                                "{0}                   and then continues processing arguments.",
                                Characters.HorizontalTab, CommandLineOption.ForceInitialize));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : Displays version and syntax information and then exits.",
                                Characters.HorizontalTab, CommandLineOption.Help));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : Immediately attempts to initialize the script library for\n" +
                                "{0}              the interpreter and then continues processing arguments.",
                                Characters.HorizontalTab, CommandLineOption.Initialize));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : Enables interactive mode for the interpreter and then\n" +
                                "{0}               continues processing arguments.",
                                Characters.HorizontalTab, CommandLineOption.Interactive));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <directory> : This option is processed prior to interpreter\n" +
                                "{0}                       creation.  Sets the script library location to\n" +
                                "{0}                       the specified directory and then continues\n" +
                                "{0}                       processing arguments.",
                                Characters.HorizontalTab, CommandLineOption.Library));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <enable> : Enables or disables Tcl {2} compliant namespace\n" +
                                "{0}                       support for the interpreter and then continues\n" +
                                "{0}                       processing arguments.  However, unlike native\n" +
                                "{0}                       Tcl, the \"dangers of creative writing\" does not\n" +
                                "{0}                       apply (see wiki page \"http://wiki.tcl.tk/1030\").",
                                Characters.HorizontalTab, CommandLineOption.Namespaces, TclVars.VersionValue));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : This option is processed prior to the standard\n" +
                                "{0}                       argument processing and it causes processing of\n" +
                                "{0}                       arguments from the file \"{2}\" to\n" +
                                "{0}                       be skipped (i.e. if it exists in the executable\n" +
                                "{0}                       directory) and then continues processing\n" +
                                "{0}                       arguments.",
                                Characters.HorizontalTab, CommandLineOption.NoArgumentsFileName, argvFileName));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : Arranges for the interactive loop to be entered instead of\n" +
                                "{0}          exiting the process and then continues processing arguments.",
                                Characters.HorizontalTab, CommandLineOption.NoExit));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : Disables tracing and then continues processing arguments.",
                                Characters.HorizontalTab, CommandLineOption.NoTrace));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : Waits for a key to be pressed and then continues processing\n" +
                                "{0}         arguments (useful for attaching a managed debugger before any\n" +
                                "{0}         scripts [with the possible exception of the script library]\n" +
                                "{0}         have been evaluated).",
                                Characters.HorizontalTab, CommandLineOption.Pause));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <pluginName> <arguments> : Stores the specified\n" +
                                "{0}                                            arguments and arranges for\n" +
                                "{0}                                            them to be passed into the\n" +
                                "{0}                                            specified plugin if/when it\n" +
                                "{0}                                            is subsequently loaded into\n" +
                                "{0}                                            the interpreter and then\n" +
                                "{0}                                            continues processing\n" +
                                "{0}                                            arguments.  If the plugin\n" +
                                "{0}                                            is never loaded into the\n" +
                                "{0}                                            interpreter after this\n" +
                                "{0}                                            point, the arguments will\n" +
                                "{0}                                            never be used again.",
                                Characters.HorizontalTab, CommandLineOption.PluginArguments));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} [pattern] [all] [argument ...] : Runs the specified plugin\n" +
                                "{0}                                             test(s) or the full plugin\n" +
                                "{0}                                             test suite(s) if no\n" +
                                "{0}                                             pattern is supplied and\n" +
                                "{0}                                             then exits.",
                                Characters.HorizontalTab, CommandLineOption.PluginTest));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <fileName> : Evaluates the specified file (after the script\n" +
                                "{0}                       library has been initialized) and then continues\n" +
                                "{0}                       processing arguments.  If the script library has\n" +
                                "{0}                       not been initialized, an error is generated (see\n" +
                                "{0}                       the \"-{2}\" option, above).",
                                Characters.HorizontalTab, CommandLineOption.PostFile,
                                CommandLineOption.Initialize));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <script> : Evaluates the specified script (after the\n" +
                                "{0}                           script library has been initialized) and\n" +
                                "{0}                           then continues processing arguments.  If the\n" +
                                "{0}                           script library has not been initialized, an\n" +
                                "{0}                           error is generated (see the \"-{2}\"\n" +
                                "{0}                           option, above).",
                                Characters.HorizontalTab, CommandLineOption.PostInitialize,
                                CommandLineOption.Initialize));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <fileName> : Evaluates the specified file (before the script\n" +
                                "{0}                      library has been initialized) and then continues\n" +
                                "{0}                      processing arguments.  If the script library has\n" +
                                "{0}                      been initialized, an error is generated (see the\n" +
                                "{0}                      \"-{2}\" option, above).",
                                Characters.HorizontalTab, CommandLineOption.PreFile,
                                CommandLineOption.Initialize));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <script> : Evaluates the specified script (before the\n" +
                                "{0}                          script library has been initialized) and then\n" +
                                "{0}                          continues processing arguments.  If the\n" +
                                "{0}                          script library has been initialized, an error\n" +
                                "{0}                          is generated (see the \"-{2}\" option,\n" +
                                "{0}                          above).",
                                Characters.HorizontalTab, CommandLineOption.PreInitialize,
                                CommandLineOption.Initialize));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <profile> : Loads the specified host profile and then\n" +
                                "{0}                     continues processing arguments.",
                                Characters.HorizontalTab, CommandLineOption.Profile));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <settings> : Loads the specified interpreter settings,\n" +
                                "{0}                          recreates the interpreter based on the new\n" +
                                "{0}                          settings, and then continues processing\n" +
                                "{0}                          arguments.",
                                Characters.HorizontalTab, CommandLineOption.Reconfigure));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <optionName> : Adds, removes, or resets the specified\n" +
                                "{0}                              runtime option(s) and then continues\n" +
                                "{0}                              processing arguments.  If the script\n" +
                                "{0}                              library has not been initialized, an\n" +
                                "{0}                              error is generated (see the \"-{2}\"\n" +
                                "{0}                              option, above).",
                                Characters.HorizontalTab, CommandLineOption.RuntimeOption,
                                CommandLineOption.Initialize));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : Enables \"safe\" mode for the interpreter and then continues\n" +
                                "{0}        processing arguments (all \"unsafe\" commands will be hidden).",
                                Characters.HorizontalTab, CommandLineOption.Safe));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <enable> : Enables or disables initialization of the\n" +
                                "{0}                          script library and then continues processing\n" +
                                "{0}                          arguments.",
                                Characters.HorizontalTab, CommandLineOption.SetInitialize));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <enable> : Enables or disables entering the interactive loop\n" +
                                "{0}                    and then continues processing arguments.",
                                Characters.HorizontalTab, CommandLineOption.SetLoop));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : Enables \"standard\" mode for the interpreter and then\n" +
                                "{0}            continues processing arguments (all \"non-standard\" commands\n" +
                                "{0}            will be hidden).",
                                Characters.HorizontalTab, CommandLineOption.Standard));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : Enables single-step mode for the script debugger and then\n" +
                                "{0}        continues processing arguments.",
                                Characters.HorizontalTab, CommandLineOption.Step));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} [pattern] [all] [argument ...] : Runs the specified test(s) or\n" +
                                "{0}                                       the full test suite(s) if no\n" +
                                "{0}                                       pattern is supplied and then\n" +
                                "{0}                                       exits.",
                                Characters.HorizontalTab, CommandLineOption.Test));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <directory> : Sets the base directory for the test\n" +
                                "{0}                             suite.  This directory is used when\n" +
                                "{0}                             searching for test files matching a\n" +
                                "{0}                             specific pattern.",
                                Characters.HorizontalTab, CommandLineOption.TestDirectory));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : Enables tracing to all active trace listeners (including the\n" +
                                "{0}         console, if applicable) and then continues processing\n" +
                                "{0}         arguments.",
                                Characters.HorizontalTab, CommandLineOption.Trace));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : Enables trace listener output to potentially be written\n" +
                                "{0}               to the host for the interpreter and then continues\n" +
                                "{0}               processing arguments.  This option is intended for use\n" +
                                "{0}               with custom shells.  The default shell does not make use\n" +
                                "{0}               of the interpreter flag set by this option.",
                                Characters.HorizontalTab, CommandLineOption.TraceToHost));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} <path> : Sets the vendor path (i.e. the name of an\n" +
                                "{0}                     additional sub-directory within each directory\n" +
                                "{0}                     searched when attempting to find user-specific\n" +
                                "{0}                     and/or application-specific files) and then\n" +
                                "{0}                     continues processing arguments.",
                                Characters.HorizontalTab, CommandLineOption.VendorPath));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}-{1} : Displays detailed version information and then exits.",
                                Characters.HorizontalTab, CommandLineOption.Version));
                        }

                        if (showEnvironment)
                        {
                            if (showError || showBanner || showLegalese || showUsage || showOptions)
                                interactiveHost.WriteLine();

                            WriteSectionHeader(interactiveHost, "Environment Notes", UsageWidth);
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}Environment variable names may be case-sensitive (i.e. it depends on\n" +
                                "{0}the underlying operating system).",
                                Characters.HorizontalTab));
                            interactiveHost.WriteLine();
                            WriteSectionHeader(interactiveHost, "Environment Variables", UsageWidth);
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything],\n" +
                                "{0}internal calls into the garbage collector will always wait for all\n" +
                                "{0}pending finalizers to complete, even when run from a non-default\n" +
                                "{0}application domain context.  By default, waiting for all pending\n" +
                                "{0}finalizers to complete is disabled in non-default application domain\n" +
                                "{0}contexts in an attempt to prevent potential deadlocks.",
                                Characters.HorizontalTab, EnvVars.AlwaysWaitForGC));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], waits until a\n" +
                                "{0}key is pressed and then triggers a managed debugger break (useful for\n" +
                                "{0}attaching a managed debugger before any significant initialization has\n" +
                                "{0}been performed).",
                                Characters.HorizontalTab, EnvVars.Break));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], the console\n" +
                                "{0}window will be enabled.  This option is intended to be processed by\n" +
                                "{0}custom shells.  The default shell does not process this option (i.e. it\n" +
                                "{0}always attempts to use and/or create a console window).",
                                Characters.HorizontalTab, EnvVars.Console));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set, its value will be\n" +
                                "{0}used to alter or set the creation flags for the interpreter.  If the\n" +
                                "{0}value cannot be converted to creation flags, it will be ignored.",
                                Characters.HorizontalTab, EnvVars.CreateFlags));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], debug mode is\n" +
                                "{0}enabled immediately after creating the interpreter (i.e. various\n" +
                                "{0}strategically placed diagnostic messages are produced to help\n" +
                                "{0}troubleshoot the startup process).",
                                Characters.HorizontalTab, EnvVars.Debug));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], quiet\n" +
                                "{0}mode is enabled immediately after creating the interpreter (see the\n" +
                                "{0}\"{2}\" environment variable, below).",
                                Characters.HorizontalTab, EnvVars.DefaultQuiet, EnvVars.Quiet));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything],\n" +
                                "{0}tracing of managed call stack information is enabled immediately after\n" +
                                "{0}creating the interpreter (see the \"{2}\" environment variable,\n" +
                                "{0}below).",
                                Characters.HorizontalTab, EnvVars.DefaultTraceStack, EnvVars.TraceStack));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], it will be\n" +
                                "{0}interpreted as the name of the base directory to be used when figuring\n" +
                                "{0}out where the script library is located; however, it will only be used\n" +
                                "{0}when explicitly attempting to automatically detect its location.",
                                Characters.HorizontalTab, EnvVars.Eagle));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], it will\n" +
                                "{0}be interpreted as the name of the base directory to be used when\n" +
                                "{0}figuring out where the script library, packages, and tests are located.",
                                Characters.HorizontalTab, EnvVars.EagleBase));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" or \"{2}\" environment variables are set [to\n" +
                                "{0}anything], they will be interpreted as lists of directory names where\n" +
                                "{0}the script library and/or additional package indexes may be located.",
                                Characters.HorizontalTab, EnvVars.EagleLibPath, EnvVars.TclLibPath));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" or \"{2}\" environment variables are set\n" +
                                "{0}[to anything], they will be interpreted as directory names where the\n" +
                                "{0}script library and/or additional package indexes may be located.",
                                Characters.HorizontalTab, EnvVars.EagleLibrary, EnvVars.TclLibrary));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\", \"{2}\", \"{3}\", or \"{4}\"\n" +
                                "{0}environment variables are set [to anything], their values will be used\n" +
                                "{0}by the native Tcl integration subsystem as directory/file locations to\n" +
                                "{0}check for native Tcl libraries.",
                                Characters.HorizontalTab, EnvVars.EagleTclDll, EnvVars.EagleTkDll,
                                EnvVars.TclDll, EnvVars.TkDll));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\", \"{2}\", \"{3}\", or \"{4}\"\n" +
                                "{0}environment variables are set [to anything], their values will be used\n" +
                                "{0}by the test suite as directory/file locations to check for native Tcl\n" +
                                "{0}shells.",
                                Characters.HorizontalTab, EnvVars.EagleTclShell, EnvVars.EagleTkShell,
                                EnvVars.TclShell, EnvVars.TkShell));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set, its value will be\n"+
                                "{0}used to override the length limit for elided text that would otherwise\n"+
                                "{0}use the default length limit.  If the value cannot be converted to an\n"+
                                "{0}integer, it will be ignored.",
                                Characters.HorizontalTab, EnvVars.EllipsisLimit));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything],\n" +
                                "{0}interactive mode is enabled immediately after creating the interpreter.",
                                Characters.HorizontalTab, EnvVars.Interactive));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set, its value will\n" +
                                "{0}be used to alter or set the instance flags for the interpreter.  If the\n" +
                                "{0}value cannot be converted to instance flags, it will be ignored.",
                                Characters.HorizontalTab, EnvVars.InterpreterFlags));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], internal\n" +
                                "{0}calls into the garbage collector will be disabled.",
                                Characters.HorizontalTab, EnvVars.NeverGC));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything],\n" +
                                "{0}internal calls into the garbage collector will never wait for all\n" +
                                "{0}pending finalizers to complete.  By default, waiting for all pending\n" +
                                "{0}finalizers to complete is disabled in non-default application domain\n" +
                                "{0}contexts in an attempt to prevent potential deadlocks.",
                                Characters.HorizontalTab, EnvVars.NeverWaitForGC));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], the host\n" +
                                "{0}script cancellation interface will not be enabled (e.g. the Control-C\n" +
                                "{0}key being pressed will not trigger script cancellation).",
                                Characters.HorizontalTab, EnvVars.NoCancel));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], the console\n" +
                                "{0}output will not be in color.",
                                Characters.HorizontalTab, EnvVars.NoColor));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], the\n" +
                                "{0}console window will be disabled.  This option is intended to be\n" +
                                "{0}processed by custom shells.  The default shell does not process this\n" +
                                "{0}option (i.e. it always attempts to use and/or create a console window).",
                                Characters.HorizontalTab, EnvVars.NoConsole));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], the console\n" +
                                "{0}icon will not be changed.",
                                Characters.HorizontalTab, EnvVars.NoIcon));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], script\n" +
                                "{0}library initialization is skipped after creating the interpreter.",
                                Characters.HorizontalTab, EnvVars.NoInitialize));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], the\n" +
                                "{0}interactive loop will not be entered.",
                                Characters.HorizontalTab, EnvVars.NoLoop));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], the host\n" +
                                "{0}profile will not be loaded.",
                                Characters.HorizontalTab, EnvVars.NoProfile));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything],\n" +
                                "{0}exceptions will not be thrown when a disposed object is accessed.",
                                Characters.HorizontalTab, EnvVars.NoThrowOnDisposed));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], the console\n" +
                                "{0}title will not be changed.",
                                Characters.HorizontalTab, EnvVars.NoTitle));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], all tracing\n" +
                                "{0}will be disabled.",
                                Characters.HorizontalTab, EnvVars.NoTrace));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], assembly\n" +
                                "{0}files will not be checked for trust during the interpreter creation\n" +
                                "{0}process.",
                                Characters.HorizontalTab, EnvVars.NoTrusted));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], the\n" +
                                "{0}native utility library will not be loaded.",
                                Characters.HorizontalTab, EnvVars.NoUtility));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], selected\n" +
                                "{0}diagnostic messages will be disabled during the interpreter creation\n" +
                                "{0}process.",
                                Characters.HorizontalTab, EnvVars.NoVerbose));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], assembly\n" +
                                "{0}strong name signatures will not be verified during the interpreter\n" +
                                "{0}creation process.",
                                Characters.HorizontalTab, EnvVars.NoVerified));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], the host\n" +
                                "{0}will attempt to load the specified profile.",
                                Characters.HorizontalTab, EnvVars.Profile));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], potentially\n" +
                                "{0}important diagnostic messages about non-fatal (yet otherwise\n" +
                                "{0}unreportable) errors will not cause a modal message box to be displayed\n" +
                                "{0}when the originating interpreter [host] is unknown or unavailable.  Use\n" +
                                "{0}of this environment variable is not recommended (i.e. normally, it\n" +
                                "{0}would be preferable to determine the root cause of the message and fix\n" +
                                "{0}that instead).",
                                Characters.HorizontalTab, EnvVars.Quiet));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], enable \"safe\"\n" +
                                "{0}mode for the interpreter (all \"unsafe\" commands will be hidden).",
                                Characters.HorizontalTab, EnvVars.Safe));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], enable\n" +
                                "{0}\"standard\" mode for the interpreter (all \"non-standard\" commands will\n" +
                                "{0}be hidden).",
                                Characters.HorizontalTab, EnvVars.Standard));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], single-step\n" +
                                "{0}mode for the script debugger is enabled immediately after creating the\n" +
                                "{0}interpreter.",
                                Characters.HorizontalTab, EnvVars.Step));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], unhandled\n" +
                                "{0}exceptions are rethrown after being reported.",
                                Characters.HorizontalTab, EnvVars.Throw));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], tracing to\n" +
                                "{0}all active trace listeners (including the console, if applicable) will\n" +
                                "{0}be enabled before any significant initialization has been performed.",
                                Characters.HorizontalTab, EnvVars.Trace));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], trace\n" +
                                "{0}listener output may include managed call stack information.",
                                Characters.HorizontalTab, EnvVars.TraceStack));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], trace\n" +
                                "{0}listener output may be sent to the host for the interpreter.  This\n" +
                                "{0}option is intended for use with custom shells.  The default shell does\n" +
                                "{0}not make use of the interpreter flag set by this option.",
                                Characters.HorizontalTab, EnvVars.TraceToHost));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], the\n" +
                                "{0}existing console will be used, if available (i.e. by attaching to it).",
                                Characters.HorizontalTab, EnvVars.UseAttach));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], it will\n" +
                                "{0}be interpreted as the name of the file or directory where the optional\n" +
                                "{0}native utility library is located.",
                                Characters.HorizontalTab, EnvVars.UtilityPath));
                            interactiveHost.WriteLine();
                            interactiveHost.WriteLine(String.Format(
                                "{0}If the \"{1}\" environment variable is set [to anything], it will\n" +
                                "{0}be interpreted as the name of an additional sub-directory within each\n" +
                                "{0}directory searched when attempting to find user-specific and/or\n" +
                                "{0}application-specific files.",
                                Characters.HorizontalTab, EnvVars.VendorPath));
                        }

                        result = String.Empty;
                        return ReturnCode.Ok;
                    }
                    else
                    {
                        result = "interpreter host not available";
                    }
                }
                else
                {
                    result = "invalid interpreter";
                }
            }
            catch (Exception e)
            {
                result = e;
            }

            return ReturnCode.Error;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        public static ReturnCode WriteVersion(
            Interpreter interpreter,
            bool showBanner,
            bool showLegalese,
            bool showSource,
            bool showUpdate,
            bool showPlugins,
            bool showOptions,
            ref Result result
            )
        {
            try
            {
                if (interpreter != null)
                {
                    IInteractiveHost interactiveHost = interpreter.Host;

                    if (interactiveHost != null)
                    {
                        if (showBanner)
                            WriteBanner(interpreter, false, false, false, false);

                        if (showLegalese)
                        {
                            if (showBanner)
                                interactiveHost.WriteLine();

                            WriteLegalese(interpreter, true);
                        }

                        Assembly assembly = showSource || showUpdate ?
                            GlobalState.GetAssembly() : null;

                        if (showSource)
                        {
                            if (showBanner || showLegalese)
                                interactiveHost.WriteLine();

                            interactiveHost.WriteLine("Compiled from sources:");
                            interactiveHost.WriteLine();
                            interactiveHost.Write(Characters.HorizontalTab);
                            interactiveHost.WriteLine(String.Format(
                                versionSourceFormat,
                                FormatOps.SourceId(assembly, defaultSourceId),
                                FormatOps.SourceTimeStamp(assembly,
                                    defaultSourceTimeStamp)));
                        }

                        if (showUpdate)
                        {
                            if (showBanner || showLegalese || showSource)
                                interactiveHost.WriteLine();

                            AssemblyName assemblyName = GlobalState.GetAssemblyName();

                            interactiveHost.WriteLine("Using update settings:");
                            interactiveHost.WriteLine();
                            interactiveHost.Write(Characters.HorizontalTab);
                            interactiveHost.WriteLine(String.Format(
                                versionUpdateFormat,
                                FormatOps.Uri(assembly, defaultUri),
                                String.Format(Vars.Platform.UpdatePathAndQueryValue,
                                    GlobalState.GetAssemblyUpdateVersion()),
                                FormatOps.PublicKeyToken(assemblyName,
                                    Characters.Asterisk.ToString()),
                                FormatOps.CultureName(
                                    GlobalState.GetAssemblyCultureInfo(),
                                    false)));
                        }

                        bool wrotePlugin = false; /* NOTE: Was there a plugin? */

                        if (showPlugins)
                        {
                            PluginWrapperDictionary plugins = interpreter.CopyPlugins();

                            if (plugins != null)
                            {
                                foreach (bool system in new bool[] { true, false })
                                {
                                    bool wrote = false;

                                    foreach (KeyValuePair<string, _Wrappers.Plugin> pair in plugins)
                                    {
                                        IPlugin plugin = pair.Value;

                                        if (plugin == null)
                                            continue;

                                        if (FlagOps.HasFlags(
                                                plugin.Flags, PluginFlags.System, true) != system)
                                        {
                                            continue;
                                        }

                                        Result aboutResult = null;

                                        if ((plugin.About(
                                                interpreter, ref aboutResult) == ReturnCode.Ok) &&
                                            !String.IsNullOrEmpty(aboutResult))
                                        {
                                            if (!wrote)
                                            {
                                                if ((system && (showBanner || showLegalese ||
                                                        showSource || showUpdate)) ||
                                                    (!system && wrotePlugin))
                                                {
                                                    interactiveHost.WriteLine();
                                                }

                                                interactiveHost.WriteLine(String.Format(
                                                    "Using {0} plugins:",
                                                    system ? "core" : "loaded"));
                                                if (system) interactiveHost.WriteLine();

                                                wrote = true;
                                            }

                                            if (!system) interactiveHost.WriteLine();
                                            interactiveHost.WriteLine(aboutResult);
                                        }
                                    }

                                    if (!wrotePlugin && wrote)
                                        wrotePlugin = true;
                                }
                            }
                        }

                        if (showOptions)
                        {
                            StringList options = DefineConstants.OptionList;

                            if (options != null)
                            {
                                int maximumLength = 0;

                                foreach (string option in options)
                                {
                                    if (!String.IsNullOrEmpty(option) &&
                                        (option.Length > maximumLength))
                                    {
                                        maximumLength = option.Length;
                                    }
                                }

                                if (maximumLength > 0)
                                {
                                    if (showBanner || showLegalese || showSource ||
                                        showUpdate || wrotePlugin)
                                    {
                                        interactiveHost.WriteLine();
                                    }

                                    interactiveHost.WriteLine("Compiled with options:");
                                    interactiveHost.WriteLine();

                                    int count = 0;

                                    foreach (string option in options)
                                    {
                                        if (!String.IsNullOrEmpty(option))
                                        {
                                            //
                                            // HACK: Right align the option within this column.
                                            //
                                            interactiveHost.Write(Characters.HorizontalTab);
                                            interactiveHost.Write(String.Format(
                                                optionFormat.Replace(lengthPlaceholder,
                                                (maximumLength).ToString()), option));

                                            if ((++count % OptionsPerLine) == 0)
                                            {
                                                interactiveHost.WriteLine();
                                                count = 0;
                                            }
                                        }
                                    }

                                    if (count > 0)
                                    {
                                        interactiveHost.WriteLine();
                                        count = 0;
                                    }
                                }
                            }
                        }

                        result = String.Empty;
                        return ReturnCode.Ok;
                    }
                    else
                    {
                        result = "interpreter host not available";
                    }
                }
                else
                {
                    result = "invalid interpreter";
                }
            }
            catch (Exception e)
            {
                result = e;
            }

            return ReturnCode.Error;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

#if INTERACTIVE_COMMANDS
        private static bool WriteInteractiveHelpColumns(
            IHost host,
            IEnumerable<string> collection,
            string format,
            string prefix,
            int maximumLength,
            int countPerLine,
            ConsoleColor foregroundColor,
            ConsoleColor backgroundColor
            )
        {
            int count = 0;

            foreach (string item in collection)
            {
                if (item == null)
                    continue;

                //
                // HACK: Right align the command name within this column.
                //
                int length = maximumLength - item.Length + columnPadding;

                if (!HostTryWriteColor(host, String.Format(format.Replace(
                        lengthPlaceholder, length.ToString()), prefix,
                        item), false, foregroundColor, backgroundColor))
                {
                    return false;
                }

                if ((++count % countPerLine) == 0)
                {
                    if (!host.WriteLine())
                        return false;

                    count = 0;
                }
                else if (!host.Write(Characters.Space))
                {
                    return false;
                }
            }

            if (count > 0)
            {
                if (!host.WriteLine())
                    return false;

                count = 0;
            }

            return true;
        }

        ///////////////////////////////////////////////////////////////////////////////////////////////

        public static ReturnCode WriteInteractiveHelp(
            Interpreter interpreter,
            ArgumentList arguments,
            ref Result result
            )
        {
            if (interpreter != null)
            {
                IHost host = interpreter.Host;

                if (host != null)
                {
                    string topic = null;

                    if ((arguments != null) && (arguments.Count >= 2))
                        topic = StringOps.NullIfEmpty(arguments[1]);

                    bool showGroups = true; /* TODO: Good default? */
                    bool showCommands = true; /* TODO: Good default? */

                    if ((arguments != null) && (arguments.Count >= 3))
                    {
                        if (Value.GetBoolean2(arguments[2],
                                ValueFlags.AnyBoolean, interpreter.CultureInfo,
                                ref showGroups, ref result) != ReturnCode.Ok)
                        {
                            return ReturnCode.Error;
                        }
                    }

                    if ((arguments != null) && (arguments.Count >= 4))
                    {
                        if (Value.GetBoolean2(arguments[3],
                                ValueFlags.AnyBoolean, interpreter.CultureInfo,
                                ref showCommands, ref result) != ReturnCode.Ok)
                        {
                            return ReturnCode.Error;
                        }
                    }

                    StringListDictionary groups = showGroups ?
                        GetInteractiveCommandGroups(interpreter) : null;

                    StringPairDictionary help = showCommands ?
                        GetInteractiveCommandHelp(interpreter) : null;

                    ConsoleColor helpForegroundColor = _ConsoleColor.Default;
                    ConsoleColor helpBackgroundColor = _ConsoleColor.Default;

                    interpreter.GetHostColors(host, ColorName.Help,
                        ref helpForegroundColor, ref helpBackgroundColor);

                    ConsoleColor helpItemForegroundColor = _ConsoleColor.Default;
                    ConsoleColor helpItemBackgroundColor = _ConsoleColor.Default;

                    interpreter.GetHostColors(host, ColorName.HelpItem,
                        ref helpItemForegroundColor, ref helpItemBackgroundColor);

                    if (topic != null)
                    {
                        // host.WriteLine();

                        HostTryWriteColor(host,
                            FormatHelpItem(interpreter, groups, help, topic, false),
                            true, helpItemForegroundColor, helpItemBackgroundColor);

                        // host.WriteLine();
                    }
                    else
                    {
                        host.WriteLine();

                        HostTryWriteColor(host,
                            "WARNING: Please note that all of the following commands work best when invoked\n" +
                            "         interactively (i.e. they cannot be easily or consistently invoked via\n" +
                            "         script).\n\n" +
                            "         Built-in interactive commands may be overridden by defining a command\n" +
                            "         or procedure with an identical name.  Overridden built-in interactive\n" +
                            "         commands and interactive extension commands will be listed within the\n" +
                            "         \"extension\" interactive command group.",
                            true, helpForegroundColor, helpBackgroundColor);

                        host.WriteLine();

                        string prefix = ShellOps.InteractiveCommandPrefix;

                        HostTryWriteColor(host, String.Format(
                            "Please type \"{0}help ?topic?\" for more information on a specific topic.",
                            prefix), true, helpForegroundColor, helpBackgroundColor);

                        if (help != null)
                        {
                            host.WriteLine();

                            int maximumLength = ListOps.GetMaximumLength(help.Keys);

                            if (groups != null)
                            {
                                bool once = false;

                                foreach (KeyValuePair<string, StringList> pair in groups)
                                {
                                    if (once)
                                        host.WriteLine();

                                    StringList keys = pair.Value;

                                    if ((keys == null) || (keys.Count == 0))
                                        continue;

                                    HostTryWriteColor(host, String.Format(
                                        "The {0} available {1} {2}: ",
                                        keys.Count, FormatOps.WrapOrNull(pair.Key),
                                        keys.Count != 1 ? "commands are" : "command is"),
                                        true, helpForegroundColor, helpBackgroundColor);

                                    host.WriteLine();

                                    WriteInteractiveHelpColumns(host, keys,
                                        commandListFormat, prefix, maximumLength, CommandsPerLine,
                                        helpItemForegroundColor, helpItemBackgroundColor);

                                    once = true;
                                }
                            }
                            else
                            {
                                StringSortedList keys = new StringSortedList(help.Keys);

                                if ((keys != null) && (keys.Count > 0))
                                {
                                    HostTryWriteColor(host, String.Format(
                                        "The {0} available {1}: ", keys.Count,
                                        keys.Count != 1 ? "commands are" : "command is"),
                                        true, helpForegroundColor, helpBackgroundColor);

                                    host.WriteLine();

                                    WriteInteractiveHelpColumns(host, keys.Keys,
                                        commandListFormat, prefix, maximumLength, CommandsPerLine,
                                        helpItemForegroundColor, helpItemBackgroundColor);
                                }
                            }

                            // host.WriteLine();
                        }
                        else if (groups != null)
                        {
                            host.WriteLine();

                            StringSortedList keys = new StringSortedList(groups.Keys);

                            if ((keys != null) && (keys.Count > 0))
                            {
                                HostTryWriteColor(host, String.Format(
                                    "The {0} available command {1}: ", keys.Count,
                                    keys.Count != 1 ? "groups are" : "group is"),
                                    true, helpForegroundColor, helpBackgroundColor);

                                host.WriteLine();

                                int maximumLength = ListOps.GetMaximumLength(groups.Keys);

                                WriteInteractiveHelpColumns(host, keys.Keys,
                                    groupListFormat, null, maximumLength, GroupsPerLine,
                                    helpItemForegroundColor, helpItemBackgroundColor);

                                // host.WriteLine();
                            }
                        }
                    }

                    //
                    // NOTE: If we managed to display any help at all, return Ok.
                    //
                    result = String.Empty;
                    return ReturnCode.Ok;
                }
                else
                {
                    result = "interpreter host not available";
                }
            }
            else
            {
                result = "invalid interpreter";
            }

            return ReturnCode.Error;
        }
#endif
#endif
        #endregion
    }
}
