Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/console/src/libraries/core/Shell.cc @ 5973

Last change on this file since 5973 was 5973, checked in by rgrieder, 15 years ago

Input part of the IOConsole should be working (at least with SSH on tardis). Note: removed modules from compilation

  • Property svn:eol-style set to native
File size: 12.3 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "Shell.h"
30
31#include "util/OutputHandler.h"
32#include "CommandExecutor.h"
33#include "CoreIncludes.h"
34#include "ConfigValueIncludes.h"
35#include "Core.h"
36#include "ConsoleCommand.h"
37
38namespace orxonox
39{
40    SetConsoleCommand(Shell, clearShell, true);
41    SetConsoleCommand(Shell, history, true);
42
43    SetConsoleCommandShortcut(OutputHandler, log);
44    SetConsoleCommandShortcut(OutputHandler, error);
45    SetConsoleCommandShortcut(OutputHandler, warning);
46    SetConsoleCommandShortcut(OutputHandler, info);
47    SetConsoleCommandShortcut(OutputHandler, debug);
48
49    Shell* Shell::singletonPtr_s = 0;
50
51    Shell::Shell()
52    {
53        int level = Core::getSoftDebugLevel(OutputHandler::LD_Shell);
54        Core::setSoftDebugLevel(OutputHandler::LD_Shell, -1);
55
56        RegisterRootObject(Shell);
57
58        this->scrollPosition_ = 0;
59        this->maxHistoryLength_ = 100;
60        this->historyPosition_ = 0;
61        this->historyOffset_ = 0;
62        this->finishedLastLine_ = true;
63        this->bAddOutputLevel_ = false;
64
65        this->clearLines();
66
67        this->inputBuffer_ = new InputBuffer();
68        this->configureInputBuffer();
69
70        this->outputBuffer_.registerListener(this);
71        OutputHandler::getOutStream().setOutputBuffer(&this->outputBuffer_);
72
73        // Get a config file for the command history
74        this->commandHistoryConfigFileType_ = ConfigFileManager::getInstance().getNewConfigFileType();
75        ConfigFileManager::getInstance().setFilename(this->commandHistoryConfigFileType_, "commandHistory.ini");
76
77        this->setConfigValues();
78
79        Core::setSoftDebugLevel(OutputHandler::LD_Shell, level);
80    }
81
82    Shell::~Shell()
83    {
84        OutputHandler::getOutStream().setOutputBuffer(0);
85        if (this->inputBuffer_)
86            this->inputBuffer_->destroy();
87    }
88
89    void Shell::setConfigValues()
90    {
91        SetConfigValueGeneric(commandHistoryConfigFileType_, maxHistoryLength_, 100)
92            .callback(this, &Shell::commandHistoryLengthChanged);
93        SetConfigValueGeneric(commandHistoryConfigFileType_, historyOffset_, 0)
94            .callback(this, &Shell::commandHistoryOffsetChanged);
95        SetConfigValueVectorGeneric(commandHistoryConfigFileType_, commandHistory_, std::vector<std::string>());
96    }
97
98    void Shell::commandHistoryOffsetChanged()
99    {
100        if (this->historyOffset_ >= this->maxHistoryLength_)
101            this->historyOffset_ = 0;
102    }
103
104    void Shell::commandHistoryLengthChanged()
105    {
106        this->commandHistoryOffsetChanged();
107
108        while (this->commandHistory_.size() > this->maxHistoryLength_)
109        {
110            unsigned int index = this->commandHistory_.size() - 1;
111            this->commandHistory_.erase(this->commandHistory_.begin() + index);
112            ModifyConfigValue(commandHistory_, remove, index);
113        }
114    }
115
116    void Shell::configureInputBuffer()
117    {
118        this->inputBuffer_->registerListener(this, &Shell::inputChanged, true);
119        this->inputBuffer_->registerListener(this, &Shell::execute, '\r', false);
120        this->inputBuffer_->registerListener(this, &Shell::execute, '\n', false);
121        this->inputBuffer_->registerListener(this, &Shell::hintandcomplete, '\t', true);
122        this->inputBuffer_->registerListener(this, &Shell::backspace, '\b', true);
123        this->inputBuffer_->registerListener(this, &Shell::backspace, static_cast<char>(127), true);
124        this->inputBuffer_->registerListener(this, &Shell::deletechar, KeyCode::Delete);
125        this->inputBuffer_->registerListener(this, &Shell::exit, static_cast<char>(27), true);
126        this->inputBuffer_->registerListener(this, &Shell::cursor_right, KeyCode::Right);
127        this->inputBuffer_->registerListener(this, &Shell::cursor_left, KeyCode::Left);
128        this->inputBuffer_->registerListener(this, &Shell::cursor_end, KeyCode::End);
129        this->inputBuffer_->registerListener(this, &Shell::cursor_home, KeyCode::Home);
130        this->inputBuffer_->registerListener(this, &Shell::history_up, KeyCode::Up);
131        this->inputBuffer_->registerListener(this, &Shell::history_down, KeyCode::Down);
132        this->inputBuffer_->registerListener(this, &Shell::scroll_up, KeyCode::PageUp);
133        this->inputBuffer_->registerListener(this, &Shell::scroll_down, KeyCode::PageDown);
134    }
135
136    void Shell::clearShell()
137    {
138        Shell::getInstance().clearLines();
139    }
140
141    void Shell::history()
142    {
143        Shell& instance = Shell::getInstance();
144
145        for (unsigned int i = instance.historyOffset_; i < instance.commandHistory_.size(); ++i)
146            instance.addLine(instance.commandHistory_[i], -1);
147        for (unsigned int i =  0; i < instance.historyOffset_; ++i)
148            instance.addLine(instance.commandHistory_[i], -1);
149    }
150
151    void Shell::registerListener(ShellListener* listener)
152    {
153        this->listeners_.push_back(listener);
154    }
155
156    void Shell::unregisterListener(ShellListener* listener)
157    {
158        for (std::list<ShellListener*>::iterator it = this->listeners_.begin(); it != this->listeners_.end(); )
159        {
160            if ((*it) == listener)
161                it = this->listeners_.erase(it);
162            else
163                ++it;
164        }
165    }
166
167    void Shell::setCursorPosition(unsigned int cursor)
168    {
169        this->inputBuffer_->setCursorPosition(cursor);
170        this->updateListeners<&ShellListener::cursorChanged>();
171    }
172
173    void Shell::setInput(const std::string& input)
174    {
175        this->inputBuffer_->set(input);
176        this->inputChanged();
177    }
178
179    void Shell::addLine(const std::string& line, int level)
180    {
181        int original_level = OutputHandler::getOutStream().getOutputLevel();
182        OutputHandler::getOutStream().setOutputLevel(level);
183
184        if (!this->finishedLastLine_)
185            this->outputBuffer_ << std::endl;
186
187        this->outputBuffer_ << line << std::endl;
188        OutputHandler::getOutStream().setOutputLevel(original_level);
189    }
190
191    void Shell::clearLines()
192    {
193        this->lines_.clear();
194        this->scrollIterator_ = this->lines_.begin();
195
196        this->scrollPosition_ = 0;
197        this->finishedLastLine_ = true;
198
199        this->updateListeners<&ShellListener::linesChanged>();
200    }
201
202    std::list<std::string>::const_iterator Shell::getNewestLineIterator() const
203    {
204        if (this->scrollPosition_)
205            return this->scrollIterator_;
206        else
207            return this->lines_.begin();
208    }
209
210    std::list<std::string>::const_iterator Shell::getEndIterator() const
211    {
212        return this->lines_.end();
213    }
214
215    void Shell::addToHistory(const std::string& command)
216    {
217        ModifyConfigValue(commandHistory_, set, this->historyOffset_, command);
218        this->historyPosition_ = 0;
219        ModifyConfigValue(historyOffset_, set, (this->historyOffset_ + 1) % this->maxHistoryLength_);
220    }
221
222    std::string Shell::getFromHistory() const
223    {
224        unsigned int index = mod(static_cast<int>(this->historyOffset_) - static_cast<int>(this->historyPosition_), this->maxHistoryLength_);
225        if (index < this->commandHistory_.size() && this->historyPosition_ != 0)
226            return this->commandHistory_[index];
227        else
228            return "";
229    }
230
231    void Shell::outputChanged()
232    {
233        std::string output;
234        bool newline;
235        do
236        {
237            newline = this->outputBuffer_.getLine(&output);
238
239            if (!newline && output == "")
240                break;
241
242            if (this->finishedLastLine_)
243            {
244                if (this->bAddOutputLevel_)
245                    output.insert(0, 1, static_cast<char>(OutputHandler::getOutStream().getOutputLevel()));
246
247                this->lines_.insert(this->lines_.begin(), output);
248
249                if (this->scrollPosition_)
250                    this->scrollPosition_++;
251                else
252                    this->scrollIterator_ = this->lines_.begin();
253
254                this->finishedLastLine_ = newline;
255
256                if (!this->scrollPosition_)
257                {
258                    this->updateListeners<&ShellListener::lineAdded>();
259                }
260            }
261            else
262            {
263                (*this->lines_.begin()) += output;
264                this->finishedLastLine_ = newline;
265                this->updateListeners<&ShellListener::onlyLastLineChanged>();
266            }
267
268        } while (newline);
269    }
270
271    void Shell::inputChanged()
272    {
273        this->updateListeners<&ShellListener::inputChanged>();
274        this->updateListeners<&ShellListener::cursorChanged>();
275    }
276
277    void Shell::execute()
278    {
279        this->addToHistory(this->inputBuffer_->get());
280        this->addLine(this->inputBuffer_->get(), 0);
281
282        if (!CommandExecutor::execute(this->inputBuffer_->get()))
283            this->addLine("Error: Can't execute \"" + this->inputBuffer_->get() + "\".", 1);
284
285        this->clear();
286    }
287
288    void Shell::hintandcomplete()
289    {
290        this->inputBuffer_->set(CommandExecutor::complete(this->inputBuffer_->get()));
291        this->addLine(CommandExecutor::hint(this->inputBuffer_->get()), -1);
292
293        this->inputChanged();
294    }
295
296    void Shell::backspace()
297    {
298        this->inputBuffer_->removeBehindCursor();
299        this->updateListeners<&ShellListener::inputChanged>();
300        this->updateListeners<&ShellListener::cursorChanged>();
301    }
302
303    void Shell::deletechar()
304    {
305        this->inputBuffer_->removeAtCursor();
306        this->updateListeners<&ShellListener::inputChanged>();
307    }
308
309    void Shell::clear()
310    {
311        this->inputBuffer_->clear();
312        this->historyPosition_ = 0;
313        this->updateListeners<&ShellListener::inputChanged>();
314        this->updateListeners<&ShellListener::cursorChanged>();
315    }
316
317    void Shell::cursor_right()
318    {
319        this->inputBuffer_->increaseCursor();
320        this->updateListeners<&ShellListener::cursorChanged>();
321    }
322
323    void Shell::cursor_left()
324    {
325        this->inputBuffer_->decreaseCursor();
326        this->updateListeners<&ShellListener::cursorChanged>();
327    }
328
329    void Shell::cursor_end()
330    {
331        this->inputBuffer_->setCursorToEnd();
332        this->updateListeners<&ShellListener::cursorChanged>();
333    }
334
335    void Shell::cursor_home()
336    {
337        this->inputBuffer_->setCursorToBegin();
338        this->updateListeners<&ShellListener::cursorChanged>();
339    }
340
341    void Shell::history_up()
342    {
343        if (this->historyPosition_ < this->commandHistory_.size())
344        {
345            this->historyPosition_++;
346            this->inputBuffer_->set(this->getFromHistory());
347        }
348    }
349
350    void Shell::history_down()
351    {
352        if (this->historyPosition_ > 0)
353        {
354            this->historyPosition_--;
355            this->inputBuffer_->set(this->getFromHistory());
356        }
357    }
358
359    void Shell::scroll_up()
360    {
361        if (this->scrollIterator_ != this->lines_.end())
362        {
363            ++this->scrollIterator_;
364            ++this->scrollPosition_;
365
366            this->updateListeners<&ShellListener::linesChanged>();
367        }
368    }
369
370    void Shell::scroll_down()
371    {
372        if (this->scrollIterator_ != this->lines_.begin())
373        {
374            --this->scrollIterator_;
375            --this->scrollPosition_;
376
377            this->updateListeners<&ShellListener::linesChanged>();
378        }
379    }
380
381    void Shell::exit()
382    {
383        if (this->inputBuffer_->getSize() > 0)
384        {
385            this->clear();
386            return;
387        }
388
389        this->clear();
390        this->scrollPosition_ = 0;
391        this->scrollIterator_ = this->lines_.begin();
392
393        this->updateListeners<&ShellListener::exit>();
394    }
395}
Note: See TracBrowser for help on using the repository browser.