Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Nov 20, 2009, 4:55:40 PM (14 years ago)
Author:
rgrieder
Message:

Merged console branch back to trunk.

Location:
code/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • code/trunk

  • code/trunk/src/libraries/core/Shell.cc

    r5929 r6105  
    2323 *      Fabian 'x3n' Landau
    2424 *   Co-authors:
    25  *      ...
     25 *      Reto Grieder
    2626 *
    2727 */
     
    3030
    3131#include "util/OutputHandler.h"
     32#include "util/StringUtils.h"
     33#include "util/SubString.h"
    3234#include "CommandExecutor.h"
    3335#include "CoreIncludes.h"
    3436#include "ConfigValueIncludes.h"
    35 #include "Core.h"
    3637#include "ConsoleCommand.h"
    37 
    38 #define SHELL_UPDATE_LISTENERS(function) \
    39     for (std::list<ShellListener*>::iterator it = this->listeners_.begin(); it != this->listeners_.end(); ) \
    40         (*(it++))->function()
    4138
    4239namespace orxonox
    4340{
    44     SetConsoleCommand(Shell, clearShell, true);
    45     SetConsoleCommand(Shell, history, true);
    46 
    4741    SetConsoleCommandShortcut(OutputHandler, log);
    4842    SetConsoleCommandShortcut(OutputHandler, error);
     
    5145    SetConsoleCommandShortcut(OutputHandler, debug);
    5246
    53     Shell* Shell::singletonPtr_s = 0;
    54 
    55     Shell::Shell()
    56     {
    57         int level = Core::getSoftDebugLevel(OutputHandler::LD_Shell);
    58         Core::setSoftDebugLevel(OutputHandler::LD_Shell, -1);
    59 
     47    Shell::Shell(const std::string& consoleName, bool bScrollable, bool bPrependOutputLevel)
     48        : OutputListener(consoleName)
     49        , inputBuffer_(new InputBuffer())
     50        , consoleName_(consoleName)
     51        , bPrependOutputLevel_(bPrependOutputLevel)
     52        , bScrollable_(bScrollable)
     53    {
    6054        RegisterRootObject(Shell);
    6155
     
    6458        this->historyPosition_ = 0;
    6559        this->historyOffset_ = 0;
    66         this->finishedLastLine_ = true;
    67         this->bAddOutputLevel_ = false;
    68 
    69         this->clearLines();
    70 
    71         this->inputBuffer_ = new InputBuffer();
     60        this->bFinishedLastLine_ = true;
     61
     62        this->clearOutput();
    7263        this->configureInputBuffer();
    73 
    74         this->outputBuffer_.registerListener(this);
    75         OutputHandler::getOutStream().setOutputBuffer(&this->outputBuffer_);
    7664
    7765        // Get a config file for the command history
     
    7967        ConfigFileManager::getInstance().setFilename(this->commandHistoryConfigFileType_, "commandHistory.ini");
    8068
     69        // Use a stringstream object to buffer the output and get it line by line in update()
     70        this->outputStream_ = &this->outputBuffer_;
     71
    8172        this->setConfigValues();
    8273
    83         Core::setSoftDebugLevel(OutputHandler::LD_Shell, level);
     74        // Get the previous output and add it to the Shell
     75        for (OutputHandler::OutputVectorIterator it = OutputHandler::getInstance().getOutputVectorBegin();
     76            it != OutputHandler::getInstance().getOutputVectorEnd(); ++it)
     77        {
     78            if (it->first <= this->getSoftDebugLevel())
     79            {
     80                this->outputBuffer_ << it->second;
     81                this->outputChanged(it->first);
     82            }
     83        }
     84
     85        // Register the shell as output listener
     86        OutputHandler::getInstance().registerOutputListener(this);
    8487    }
    8588
    8689    Shell::~Shell()
    8790    {
    88         OutputHandler::getOutStream().setOutputBuffer(0);
    89         if (this->inputBuffer_)
    90             this->inputBuffer_->destroy();
     91        OutputHandler::getInstance().unregisterOutputListener(this);
     92        this->inputBuffer_->destroy();
    9193    }
    9294
    9395    void Shell::setConfigValues()
    9496    {
    95         SetConfigValueGeneric(commandHistoryConfigFileType_, maxHistoryLength_, 100)
     97        SetConfigValue(maxHistoryLength_, 100)
    9698            .callback(this, &Shell::commandHistoryLengthChanged);
    97         SetConfigValueGeneric(commandHistoryConfigFileType_, historyOffset_, 0)
     99        SetConfigValue(historyOffset_, 0)
    98100            .callback(this, &Shell::commandHistoryOffsetChanged);
    99101        SetConfigValueVectorGeneric(commandHistoryConfigFileType_, commandHistory_, std::vector<std::string>());
     102
     103#ifdef ORXONOX_RELEASE
     104        const unsigned int defaultLevel = 1;
     105#else
     106        const unsigned int defaultLevel = 3;
     107#endif
     108        SetConfigValueGeneric(ConfigFileType::Settings, softDebugLevel_, "softDebugLevel" + this->consoleName_, "OutputHandler", defaultLevel)
     109            .description("The maximal level of debug output shown in the Shell");
     110        this->setSoftDebugLevel(this->softDebugLevel_);
    100111    }
    101112
     
    121132    {
    122133        this->inputBuffer_->registerListener(this, &Shell::inputChanged, true);
    123         this->inputBuffer_->registerListener(this, &Shell::execute, '\r', false);
    124         this->inputBuffer_->registerListener(this, &Shell::hintandcomplete, '\t', true);
    125         this->inputBuffer_->registerListener(this, &Shell::backspace, '\b', true);
    126         this->inputBuffer_->registerListener(this, &Shell::deletechar, KeyCode::Delete);
    127         this->inputBuffer_->registerListener(this, &Shell::exit, static_cast<char>(27), true);
    128         this->inputBuffer_->registerListener(this, &Shell::cursor_right, KeyCode::Right);
    129         this->inputBuffer_->registerListener(this, &Shell::cursor_left, KeyCode::Left);
    130         this->inputBuffer_->registerListener(this, &Shell::cursor_end, KeyCode::End);
    131         this->inputBuffer_->registerListener(this, &Shell::cursor_home, KeyCode::Home);
    132         this->inputBuffer_->registerListener(this, &Shell::history_up, KeyCode::Up);
    133         this->inputBuffer_->registerListener(this, &Shell::history_down, KeyCode::Down);
    134         this->inputBuffer_->registerListener(this, &Shell::scroll_up, KeyCode::PageUp);
    135         this->inputBuffer_->registerListener(this, &Shell::scroll_down, KeyCode::PageDown);
    136     }
    137 
    138     void Shell::clearShell()
    139     {
    140         Shell::getInstance().clearLines();
    141     }
    142 
     134        this->inputBuffer_->registerListener(this, &Shell::execute,         '\r',   false);
     135        this->inputBuffer_->registerListener(this, &Shell::execute,         '\n',   false);
     136        this->inputBuffer_->registerListener(this, &Shell::hintAndComplete, '\t',   true);
     137        this->inputBuffer_->registerListener(this, &Shell::backspace,       '\b',   true);
     138        this->inputBuffer_->registerListener(this, &Shell::backspace,       '\177', true);
     139        this->inputBuffer_->registerListener(this, &Shell::exit,            '\033', true); // escape
     140        this->inputBuffer_->registerListener(this, &Shell::deleteChar,      KeyCode::Delete);
     141        this->inputBuffer_->registerListener(this, &Shell::cursorRight,     KeyCode::Right);
     142        this->inputBuffer_->registerListener(this, &Shell::cursorLeft,      KeyCode::Left);
     143        this->inputBuffer_->registerListener(this, &Shell::cursorEnd,       KeyCode::End);
     144        this->inputBuffer_->registerListener(this, &Shell::cursorHome,      KeyCode::Home);
     145        this->inputBuffer_->registerListener(this, &Shell::historyUp,       KeyCode::Up);
     146        this->inputBuffer_->registerListener(this, &Shell::historyDown,     KeyCode::Down);
     147        if (this->bScrollable_)
     148        {
     149            this->inputBuffer_->registerListener(this, &Shell::scrollUp,    KeyCode::PageUp);
     150            this->inputBuffer_->registerListener(this, &Shell::scrollDown,  KeyCode::PageDown);
     151        }
     152        else
     153        {
     154            this->inputBuffer_->registerListener(this, &Shell::historySearchUp,   KeyCode::PageUp);
     155            this->inputBuffer_->registerListener(this, &Shell::historySearchDown, KeyCode::PageDown);
     156        }
     157    }
     158
     159    /*
    143160    void Shell::history()
    144161    {
     
    146163
    147164        for (unsigned int i = instance.historyOffset_; i < instance.commandHistory_.size(); ++i)
    148             instance.addLine(instance.commandHistory_[i], -1);
     165            instance.addOutputLine(instance.commandHistory_[i], -1);
    149166        for (unsigned int i =  0; i < instance.historyOffset_; ++i)
    150             instance.addLine(instance.commandHistory_[i], -1);
    151     }
     167            instance.addOutputLine(instance.commandHistory_[i], -1);
     168    }
     169    */
    152170
    153171    void Shell::registerListener(ShellListener* listener)
    154172    {
    155         this->listeners_.insert(this->listeners_.end(), listener);
     173        this->listeners_.push_back(listener);
    156174    }
    157175
     
    161179        {
    162180            if ((*it) == listener)
    163                 this->listeners_.erase(it++);
     181                it = this->listeners_.erase(it);
    164182            else
    165183                ++it;
     
    170188    {
    171189        this->inputBuffer_->setCursorPosition(cursor);
    172         SHELL_UPDATE_LISTENERS(cursorChanged);
    173     }
    174 
    175     void Shell::setInput(const std::string& input)
    176     {
    177         this->inputBuffer_->set(input);
    178         this->inputChanged();
    179     }
    180 
    181     void Shell::addLine(const std::string& line, int level)
    182     {
    183         int original_level = OutputHandler::getOutStream().getOutputLevel();
    184         OutputHandler::getOutStream().setOutputLevel(level);
    185 
    186         if (!this->finishedLastLine_)
    187             this->outputBuffer_ << std::endl;
    188 
    189         this->outputBuffer_ << line << std::endl;
    190         OutputHandler::getOutStream().setOutputLevel(original_level);
    191     }
    192 
    193     void Shell::clearLines()
    194     {
    195         this->lines_.clear();
    196         this->scrollIterator_ = this->lines_.begin();
     190        this->updateListeners<&ShellListener::cursorChanged>();
     191    }
     192
     193    void Shell::addOutputLine(const std::string& line, int level)
     194    {
     195        // Make sure we really only have one line per line (no new lines!)
     196        SubString lines(line, '\n');
     197        for (unsigned i = 0; i < lines.size(); ++i)
     198        {
     199            if (level <= this->softDebugLevel_)
     200                this->outputLines_.push_front(lines[i]);
     201            this->updateListeners<&ShellListener::lineAdded>();
     202        }
     203    }
     204
     205    void Shell::clearOutput()
     206    {
     207        this->outputLines_.clear();
     208        this->scrollIterator_ = this->outputLines_.begin();
    197209
    198210        this->scrollPosition_ = 0;
    199         this->finishedLastLine_ = true;
    200 
    201         SHELL_UPDATE_LISTENERS(linesChanged);
     211        this->bFinishedLastLine_ = true;
     212
     213        this->updateListeners<&ShellListener::linesChanged>();
    202214    }
    203215
     
    207219            return this->scrollIterator_;
    208220        else
    209             return this->lines_.begin();
     221            return this->outputLines_.begin();
    210222    }
    211223
    212224    std::list<std::string>::const_iterator Shell::getEndIterator() const
    213225    {
    214         return this->lines_.end();
     226        return this->outputLines_.end();
    215227    }
    216228
     
    231243    }
    232244
    233     void Shell::outputChanged()
    234     {
    235         std::string output;
    236         bool newline;
     245    void Shell::outputChanged(int level)
     246    {
     247        bool newline = false;
    237248        do
    238249        {
    239             newline = this->outputBuffer_.getLine(&output);
     250            std::string output;
     251            std::getline(this->outputBuffer_, output);
     252
     253            bool eof = this->outputBuffer_.eof();
     254            bool fail = this->outputBuffer_.fail();
     255            if (eof)
     256                this->outputBuffer_.flush();
     257            if (eof || fail)
     258                this->outputBuffer_.clear();
     259            newline = (!eof && !fail);
    240260
    241261            if (!newline && output == "")
    242262                break;
    243263
    244             if (this->finishedLastLine_)
     264            if (this->bFinishedLastLine_)
    245265            {
    246                 if (this->bAddOutputLevel_)
    247                     output.insert(0, 1, static_cast<char>(OutputHandler::getOutStream().getOutputLevel()));
    248 
    249                 this->lines_.insert(this->lines_.begin(), output);
     266                if (this->bPrependOutputLevel_)
     267                    output.insert(0, 1, static_cast<char>(level));
     268
     269                this->outputLines_.push_front(output);
    250270
    251271                if (this->scrollPosition_)
    252272                    this->scrollPosition_++;
    253273                else
    254                     this->scrollIterator_ = this->lines_.begin();
    255 
    256                 this->finishedLastLine_ = newline;
     274                    this->scrollIterator_ = this->outputLines_.begin();
     275
     276                this->bFinishedLastLine_ = newline;
    257277
    258278                if (!this->scrollPosition_)
    259279                {
    260                     SHELL_UPDATE_LISTENERS(lineAdded);
     280                    this->updateListeners<&ShellListener::lineAdded>();
    261281                }
    262282            }
    263283            else
    264284            {
    265                 (*this->lines_.begin()) += output;
    266                 this->finishedLastLine_ = newline;
    267                 SHELL_UPDATE_LISTENERS(onlyLastLineChanged);
     285                (*this->outputLines_.begin()) += output;
     286                this->bFinishedLastLine_ = newline;
     287                this->updateListeners<&ShellListener::onlyLastLineChanged>();
    268288            }
    269289
     
    271291    }
    272292
    273     void Shell::inputChanged()
    274     {
    275         SHELL_UPDATE_LISTENERS(inputChanged);
    276         SHELL_UPDATE_LISTENERS(cursorChanged);
    277     }
    278 
    279     void Shell::execute()
    280     {
    281         this->addToHistory(this->inputBuffer_->get());
    282         this->addLine(this->inputBuffer_->get(), 0);
    283 
    284         if (!CommandExecutor::execute(this->inputBuffer_->get()))
    285             this->addLine("Error: Can't execute \"" + this->inputBuffer_->get() + "\".", 1);
    286 
    287         this->clear();
    288     }
    289 
    290     void Shell::hintandcomplete()
    291     {
    292         this->inputBuffer_->set(CommandExecutor::complete(this->inputBuffer_->get()));
    293         this->addLine(CommandExecutor::hint(this->inputBuffer_->get()), -1);
    294 
    295         this->inputChanged();
    296     }
    297 
    298     void Shell::backspace()
    299     {
    300         this->inputBuffer_->removeBehindCursor();
    301         SHELL_UPDATE_LISTENERS(inputChanged);
    302         SHELL_UPDATE_LISTENERS(cursorChanged);
    303     }
    304 
    305     void Shell::deletechar()
    306     {
    307         this->inputBuffer_->removeAtCursor();
    308         SHELL_UPDATE_LISTENERS(inputChanged);
    309     }
    310 
    311     void Shell::clear()
     293    void Shell::clearInput()
    312294    {
    313295        this->inputBuffer_->clear();
    314296        this->historyPosition_ = 0;
    315         SHELL_UPDATE_LISTENERS(inputChanged);
    316         SHELL_UPDATE_LISTENERS(cursorChanged);
    317     }
    318 
    319     void Shell::cursor_right()
     297        this->updateListeners<&ShellListener::inputChanged>();
     298        this->updateListeners<&ShellListener::cursorChanged>();
     299    }
     300
     301    void Shell::setPromptPrefix(const std::string& str)
     302    {
     303    }
     304
     305
     306    // ##########################################
     307    // ###   InputBuffer callback functions   ###
     308    // ##########################################
     309
     310    void Shell::inputChanged()
     311    {
     312        this->updateListeners<&ShellListener::inputChanged>();
     313        this->updateListeners<&ShellListener::cursorChanged>();
     314    }
     315
     316    void Shell::execute()
     317    {
     318        this->addToHistory(this->inputBuffer_->get());
     319        this->updateListeners<&ShellListener::executed>();
     320
     321        if (!CommandExecutor::execute(this->inputBuffer_->get()))
     322            this->addOutputLine("Error: Can't execute \"" + this->inputBuffer_->get() + "\".", 1);
     323
     324        this->clearInput();
     325    }
     326
     327    void Shell::hintAndComplete()
     328    {
     329        this->inputBuffer_->set(CommandExecutor::complete(this->inputBuffer_->get()));
     330        this->addOutputLine(CommandExecutor::hint(this->inputBuffer_->get()), -1);
     331
     332        this->inputChanged();
     333    }
     334
     335    void Shell::backspace()
     336    {
     337        this->inputBuffer_->removeBehindCursor();
     338        this->updateListeners<&ShellListener::inputChanged>();
     339        this->updateListeners<&ShellListener::cursorChanged>();
     340    }
     341
     342    void Shell::exit()
     343    {
     344        if (this->inputBuffer_->getSize() > 0)
     345        {
     346            this->clearInput();
     347            return;
     348        }
     349
     350        this->clearInput();
     351        this->scrollPosition_ = 0;
     352        this->scrollIterator_ = this->outputLines_.begin();
     353
     354        this->updateListeners<&ShellListener::exit>();
     355    }
     356
     357    void Shell::deleteChar()
     358    {
     359        this->inputBuffer_->removeAtCursor();
     360        this->updateListeners<&ShellListener::inputChanged>();
     361    }
     362
     363    void Shell::cursorRight()
    320364    {
    321365        this->inputBuffer_->increaseCursor();
    322         SHELL_UPDATE_LISTENERS(cursorChanged);
    323     }
    324 
    325     void Shell::cursor_left()
     366        this->updateListeners<&ShellListener::cursorChanged>();
     367    }
     368
     369    void Shell::cursorLeft()
    326370    {
    327371        this->inputBuffer_->decreaseCursor();
    328         SHELL_UPDATE_LISTENERS(cursorChanged);
    329     }
    330 
    331     void Shell::cursor_end()
     372        this->updateListeners<&ShellListener::cursorChanged>();
     373    }
     374
     375    void Shell::cursorEnd()
    332376    {
    333377        this->inputBuffer_->setCursorToEnd();
    334         SHELL_UPDATE_LISTENERS(cursorChanged);
    335     }
    336 
    337     void Shell::cursor_home()
     378        this->updateListeners<&ShellListener::cursorChanged>();
     379    }
     380
     381    void Shell::cursorHome()
    338382    {
    339383        this->inputBuffer_->setCursorToBegin();
    340         SHELL_UPDATE_LISTENERS(cursorChanged);
    341     }
    342 
    343     void Shell::history_up()
     384        this->updateListeners<&ShellListener::cursorChanged>();
     385    }
     386
     387    void Shell::historyUp()
    344388    {
    345389        if (this->historyPosition_ < this->commandHistory_.size())
     
    350394    }
    351395
    352     void Shell::history_down()
     396    void Shell::historyDown()
    353397    {
    354398        if (this->historyPosition_ > 0)
     
    359403    }
    360404
    361     void Shell::scroll_up()
    362     {
    363         if (this->scrollIterator_ != this->lines_.end())
     405    void Shell::historySearchUp()
     406    {
     407        if (this->historyPosition_ == this->historyOffset_)
     408            return;
     409        unsigned int cursorPosition = this->getCursorPosition();
     410        std::string input_str(this->getInput().substr(0, cursorPosition)); // only search for the expression from the beginning of the inputline until the cursor position
     411        for (unsigned int newPos = this->historyPosition_ + 1; newPos <= this->historyOffset_; newPos++)
     412        {
     413            if (getLowercase(this->commandHistory_[this->historyOffset_ - newPos]).find(getLowercase(input_str)) == 0) // search case insensitive
     414            {
     415                this->historyPosition_ = newPos;
     416                this->inputBuffer_->set(this->getFromHistory());
     417                this->setCursorPosition(cursorPosition);
     418                return;
     419            }
     420        }
     421    }
     422
     423    void Shell::historySearchDown()
     424    {
     425        if (this->historyPosition_ == 0)
     426            return;
     427        unsigned int cursorPosition = this->getCursorPosition();
     428        std::string input_str(this->getInput().substr(0, cursorPosition)); // only search for the expression from the beginning
     429        for (unsigned int newPos = this->historyPosition_ - 1; newPos > 0; newPos--)
     430        {
     431            if (getLowercase(this->commandHistory_[this->historyOffset_ - newPos]).find(getLowercase(input_str)) == 0) // sear$
     432            {
     433                this->historyPosition_ = newPos;
     434                this->inputBuffer_->set(this->getFromHistory());
     435                this->setCursorPosition(cursorPosition);
     436                return;
     437            }
     438        }
     439    }
     440
     441    void Shell::scrollUp()
     442    {
     443        if (this->scrollIterator_ != this->outputLines_.end())
    364444        {
    365445            ++this->scrollIterator_;
    366446            ++this->scrollPosition_;
    367447
    368             SHELL_UPDATE_LISTENERS(linesChanged);
    369         }
    370     }
    371 
    372     void Shell::scroll_down()
    373     {
    374         if (this->scrollIterator_ != this->lines_.begin())
     448            this->updateListeners<&ShellListener::linesChanged>();
     449        }
     450    }
     451
     452    void Shell::scrollDown()
     453    {
     454        if (this->scrollIterator_ != this->outputLines_.begin())
    375455        {
    376456            --this->scrollIterator_;
    377457            --this->scrollPosition_;
    378458
    379             SHELL_UPDATE_LISTENERS(linesChanged);
    380         }
    381     }
    382 
    383     void Shell::exit()
    384     {
    385         if (this->inputBuffer_->getSize() > 0)
    386         {
    387             this->clear();
    388             return;
    389         }
    390 
    391         this->clear();
    392         this->scrollPosition_ = 0;
    393         this->scrollIterator_ = this->lines_.begin();
    394 
    395         SHELL_UPDATE_LISTENERS(exit);
     459            this->updateListeners<&ShellListener::linesChanged>();
     460        }
    396461    }
    397462}
Note: See TracChangeset for help on using the changeset viewer.