Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network/src/core/Shell.cc @ 1446

Last change on this file since 1446 was 1446, checked in by landauf, 16 years ago

merged console branch into network branch

after several heavy troubles it compiles, but there is still a bug I couldn't fix: orxonox crashes as soon as one presses a key after opening the console… maybe someone else sees the problem?

File size: 11.5 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#include "CommandExecutor.h"
31#include "CoreIncludes.h"
32#include "ConfigValueIncludes.h"
33#include "CoreSettings.h"
34#include "ConsoleCommand.h"
35#include "InputManager.h"
36
37#define SHELL_UPDATE_LISTENERS(function) \
38    for (std::list<ShellListener*>::iterator it = this->listeners_.begin(); it != this->listeners_.end(); ++it) \
39        (*it)->function()
40
41namespace orxonox
42{
43    SetConsoleCommand(Shell, clearShell, true);
44    SetConsoleCommand(Shell, history, true);
45
46    Shell::Shell()
47    {
48        RegisterRootObject(Shell);
49
50        this->scrollPosition_ = 0;
51        this->maxHistoryLength_ = 100;
52        this->historyPosition_ = 0;
53        this->historyOffset_ = 0;
54        this->finishedLastLine_ = true;
55        this->bAddOutputLevel_ = false;
56
57        this->clearLines();
58
59        this->inputBuffer_ = 0;
60        this->setInputBuffer(new InputBuffer());
61
62        this->outputBuffer_.registerListener(this);
63
64        this->setConfigValues();
65    }
66
67    Shell& Shell::createShell()
68    {
69        int level = CoreSettings::getSoftDebugLevel(OutputHandler::LD_Shell);
70        CoreSettings::setSoftDebugLevel(OutputHandler::LD_Shell, -1);
71        static Shell instance;
72        CoreSettings::setSoftDebugLevel(OutputHandler::LD_Shell, level);
73        return instance;
74    }
75
76    Shell& Shell::getInstance()
77    {
78        static Shell& instance = createShell();
79        return instance;
80    }
81
82    void Shell::setConfigValues()
83    {
84        SetConfigValue(maxHistoryLength_, 100);
85        SetConfigValue(historyOffset_, 0);
86        SetConfigValueVector(commandHistory_, std::vector<std::string>());
87
88        if (this->historyOffset_ >= this->maxHistoryLength_)
89            this->historyOffset_ = 0;
90
91        while (this->commandHistory_.size() > this->maxHistoryLength_)
92        {
93            unsigned int index = this->commandHistory_.size() - 1;
94            this->commandHistory_.erase(this->commandHistory_.begin() + index);
95            ModifyConfigValue(commandHistory_, remove, index);
96        }
97    }
98
99    void Shell::setInputBuffer(InputBuffer* buffer)
100    {
101        if (this->inputBuffer_)
102        {
103            this->inputBuffer_->unregisterListener(this);
104            delete this->inputBuffer_;
105        }
106
107        this->inputBuffer_ = buffer;
108        this->inputBuffer_->registerListener(this, &Shell::inputChanged, true);
109        this->inputBuffer_->registerListener(this, &Shell::execute, '\r', false);
110        this->inputBuffer_->registerListener(this, &Shell::hintandcomplete, '\t', true);
111        this->inputBuffer_->registerListener(this, &Shell::backspace, '\b', true);
112        this->inputBuffer_->registerListener(this, &Shell::deletechar, OIS::KC_DELETE);
113        this->inputBuffer_->registerListener(this, &Shell::exit, (char)27, true);
114        this->inputBuffer_->registerListener(this, &Shell::cursor_right, OIS::KC_RIGHT);
115        this->inputBuffer_->registerListener(this, &Shell::cursor_left, OIS::KC_LEFT);
116        this->inputBuffer_->registerListener(this, &Shell::cursor_end, OIS::KC_END);
117        this->inputBuffer_->registerListener(this, &Shell::cursor_home, OIS::KC_HOME);
118        this->inputBuffer_->registerListener(this, &Shell::history_up, OIS::KC_UP);
119        this->inputBuffer_->registerListener(this, &Shell::history_down, OIS::KC_DOWN);
120        this->inputBuffer_->registerListener(this, &Shell::scroll_up, OIS::KC_PGUP);
121        this->inputBuffer_->registerListener(this, &Shell::scroll_down, OIS::KC_PGDOWN);
122    }
123
124    void Shell::clearShell()
125    {
126        Shell::getInstance().clearLines();
127    }
128
129    void Shell::history()
130    {
131        Shell& instance = Shell::getInstance();
132
133        for (int i = instance.historyOffset_; i < (int)instance.commandHistory_.size(); ++i)
134            instance.addLine(instance.commandHistory_[i], -1);
135        for (int i =  0; i < (int)instance.historyOffset_; ++i)
136            instance.addLine(instance.commandHistory_[i], -1);
137    }
138
139    void Shell::registerListener(ShellListener* listener)
140    {
141        this->listeners_.insert(this->listeners_.end(), listener);
142    }
143
144    void Shell::unregisterListener(ShellListener* listener)
145    {
146        for (std::list<ShellListener*>::iterator it = this->listeners_.begin(); it != this->listeners_.end(); )
147        {
148            if ((*it) == listener)
149                this->listeners_.erase(it++);
150            else
151                ++it;
152        }
153    }
154
155    void Shell::setCursorPosition(unsigned int cursor)
156    {
157        this->inputBuffer_->setCursorPosition(cursor);
158        SHELL_UPDATE_LISTENERS(cursorChanged);
159    }
160
161    void Shell::setInput(const std::string& input)
162    {
163        this->inputBuffer_->set(input);
164        this->inputChanged();
165    }
166
167    void Shell::addLine(const std::string& line, int level)
168    {
169        int original_level = OutputHandler::getOutStream().getOutputLevel();
170        OutputHandler::getOutStream().setOutputLevel(level);
171
172        if (!this->finishedLastLine_)
173            this->outputBuffer_ << std::endl;
174
175        this->outputBuffer_ << line << std::endl;
176        OutputHandler::getOutStream().setOutputLevel(original_level);
177    }
178
179    void Shell::clearLines()
180    {
181        this->lines_.clear();
182        this->scrollIterator_ = this->lines_.begin();
183
184        this->scrollPosition_ = 0;
185        this->finishedLastLine_ = true;
186
187        SHELL_UPDATE_LISTENERS(linesChanged);
188    }
189
190    std::list<std::string>::const_iterator Shell::getNewestLineIterator() const
191    {
192        if (this->scrollPosition_)
193            return this->scrollIterator_;
194        else
195            return this->lines_.begin();
196    }
197
198    std::list<std::string>::const_iterator Shell::getEndIterator() const
199    {
200        return this->lines_.end();
201    }
202
203    void Shell::addToHistory(const std::string& command)
204    {
205        ModifyConfigValue(commandHistory_, set, this->historyOffset_, command);
206        this->historyPosition_ = 0;
207        ModifyConfigValue(historyOffset_, set, (this->historyOffset_ + 1) % this->maxHistoryLength_);
208    }
209
210    std::string Shell::getFromHistory() const
211    {
212        unsigned int index = mod(((int)this->historyOffset_) - ((int)this->historyPosition_), this->maxHistoryLength_);
213        if (index < this->commandHistory_.size() && this->historyPosition_ != 0)
214            return this->commandHistory_[index];
215        else
216            return "";
217    }
218
219    void Shell::outputChanged()
220    {
221        std::string output;
222        bool newline;
223        do
224        {
225            newline = this->outputBuffer_.getLine(&output);
226
227            if (!newline && output == "")
228                break;
229
230            if (this->finishedLastLine_)
231            {
232                if (this->bAddOutputLevel_)
233                    output.insert(0, 1, (char)OutputHandler::getOutStream().getOutputLevel());
234
235                this->lines_.insert(this->lines_.begin(), output);
236
237                if (this->scrollPosition_)
238                    this->scrollPosition_++;
239                else
240                    this->scrollIterator_ = this->lines_.begin();
241
242                this->finishedLastLine_ = newline;
243
244                if (!this->scrollPosition_)
245                {
246                    SHELL_UPDATE_LISTENERS(lineAdded);
247                }
248            }
249            else
250            {
251                (*this->lines_.begin()) += output;
252                this->finishedLastLine_ = newline;
253                SHELL_UPDATE_LISTENERS(onlyLastLineChanged);
254            }
255
256        } while (newline);
257    }
258
259    void Shell::inputChanged()
260    {
261        SHELL_UPDATE_LISTENERS(inputChanged);
262        SHELL_UPDATE_LISTENERS(cursorChanged);
263    }
264
265    void Shell::execute()
266    {
267        this->addToHistory(this->inputBuffer_->get());
268        this->addLine(this->inputBuffer_->get(), 0);
269
270        if (!CommandExecutor::execute(this->inputBuffer_->get()))
271            this->addLine("Error: Can't execute \"" + this->inputBuffer_->get() + "\".", 1);
272
273        this->clear();
274    }
275
276    void Shell::hintandcomplete()
277    {
278        this->inputBuffer_->set(CommandExecutor::complete(this->inputBuffer_->get()));
279        this->addLine(CommandExecutor::hint(this->inputBuffer_->get()), -1);
280
281        this->inputChanged();
282    }
283
284    void Shell::backspace()
285    {
286        this->inputBuffer_->removeBehindCursor();
287        SHELL_UPDATE_LISTENERS(inputChanged);
288        SHELL_UPDATE_LISTENERS(cursorChanged);
289    }
290
291    void Shell::deletechar()
292    {
293        this->inputBuffer_->removeAtCursor();
294        SHELL_UPDATE_LISTENERS(inputChanged);
295    }
296
297    void Shell::clear()
298    {
299        this->inputBuffer_->clear();
300        this->historyPosition_ = 0;
301        SHELL_UPDATE_LISTENERS(inputChanged);
302        SHELL_UPDATE_LISTENERS(cursorChanged);
303    }
304
305    void Shell::cursor_right()
306    {
307        this->inputBuffer_->increaseCursor();
308        SHELL_UPDATE_LISTENERS(cursorChanged);
309    }
310
311    void Shell::cursor_left()
312    {
313        this->inputBuffer_->decreaseCursor();
314        SHELL_UPDATE_LISTENERS(cursorChanged);
315    }
316
317    void Shell::cursor_end()
318    {
319        this->inputBuffer_->setCursorToEnd();
320        SHELL_UPDATE_LISTENERS(cursorChanged);
321    }
322
323    void Shell::cursor_home()
324    {
325        this->inputBuffer_->setCursorToBegin();
326        SHELL_UPDATE_LISTENERS(cursorChanged);
327    }
328
329    void Shell::history_up()
330    {
331        if (this->historyPosition_ < this->commandHistory_.size())
332        {
333            this->historyPosition_++;
334            this->inputBuffer_->set(this->getFromHistory());
335        }
336    }
337
338    void Shell::history_down()
339    {
340        if (this->historyPosition_ > 0)
341        {
342            this->historyPosition_--;
343            this->inputBuffer_->set(this->getFromHistory());
344        }
345    }
346
347    void Shell::scroll_up()
348    {
349        if (this->scrollIterator_ != this->lines_.end())
350        {
351            ++this->scrollIterator_;
352            ++this->scrollPosition_;
353
354            SHELL_UPDATE_LISTENERS(linesChanged);
355        }
356    }
357
358    void Shell::scroll_down()
359    {
360        if (this->scrollIterator_ != this->lines_.begin())
361        {
362            --this->scrollIterator_;
363            --this->scrollPosition_;
364
365            SHELL_UPDATE_LISTENERS(linesChanged);
366        }
367    }
368
369    void Shell::exit()
370    {
371        if (this->inputBuffer_->getSize() > 0)
372        {
373            this->clear();
374            return;
375        }
376
377        this->clear();
378        this->scrollPosition_ = 0;
379        this->scrollIterator_ = this->lines_.begin();
380
381        SHELL_UPDATE_LISTENERS(exit);
382    }
383}
Note: See TracBrowser for help on using the repository browser.