Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1494 was 1494, checked in by rgrieder, 16 years ago
  • set the svn:eol-style property to all files so, that where ever you check out, you'll get the right line endings (had to change every file with mixed endings to windows in order to set the property)
  • Property svn:eol-style set to native
File size: 11.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#include "CommandExecutor.h"
31#include "CoreIncludes.h"
32#include "ConfigValueIncludes.h"
33#include "CoreSettings.h"
34#include "ConsoleCommand.h"
35#include "InputInterfaces.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            // TODO: may be very dangerous. InputManager already deletes InputBuffer instance!!!
105            delete this->inputBuffer_;
106        }
107
108        this->inputBuffer_ = buffer;
109        this->inputBuffer_->registerListener(this, &Shell::inputChanged, true);
110        this->inputBuffer_->registerListener(this, &Shell::execute, '\r', false);
111        this->inputBuffer_->registerListener(this, &Shell::hintandcomplete, '\t', true);
112        this->inputBuffer_->registerListener(this, &Shell::backspace, '\b', true);
113        this->inputBuffer_->registerListener(this, &Shell::deletechar, KeyCode::Delete);
114        this->inputBuffer_->registerListener(this, &Shell::exit, (char)27, true);
115        this->inputBuffer_->registerListener(this, &Shell::cursor_right, KeyCode::Right);
116        this->inputBuffer_->registerListener(this, &Shell::cursor_left, KeyCode::Left);
117        this->inputBuffer_->registerListener(this, &Shell::cursor_end, KeyCode::End);
118        this->inputBuffer_->registerListener(this, &Shell::cursor_home, KeyCode::Home);
119        this->inputBuffer_->registerListener(this, &Shell::history_up, KeyCode::Up);
120        this->inputBuffer_->registerListener(this, &Shell::history_down, KeyCode::Down);
121        this->inputBuffer_->registerListener(this, &Shell::scroll_up, KeyCode::PageUp);
122        this->inputBuffer_->registerListener(this, &Shell::scroll_down, KeyCode::PageDown);
123    }
124
125    void Shell::clearShell()
126    {
127        Shell::getInstance().clearLines();
128    }
129
130    void Shell::history()
131    {
132        Shell& instance = Shell::getInstance();
133
134        for (int i = instance.historyOffset_; i < (int)instance.commandHistory_.size(); ++i)
135            instance.addLine(instance.commandHistory_[i], -1);
136        for (int i =  0; i < (int)instance.historyOffset_; ++i)
137            instance.addLine(instance.commandHistory_[i], -1);
138    }
139
140    void Shell::registerListener(ShellListener* listener)
141    {
142        this->listeners_.insert(this->listeners_.end(), listener);
143    }
144
145    void Shell::unregisterListener(ShellListener* listener)
146    {
147        for (std::list<ShellListener*>::iterator it = this->listeners_.begin(); it != this->listeners_.end(); )
148        {
149            if ((*it) == listener)
150                this->listeners_.erase(it++);
151            else
152                ++it;
153        }
154    }
155
156    void Shell::setCursorPosition(unsigned int cursor)
157    {
158        this->inputBuffer_->setCursorPosition(cursor);
159        SHELL_UPDATE_LISTENERS(cursorChanged);
160    }
161
162    void Shell::setInput(const std::string& input)
163    {
164        this->inputBuffer_->set(input);
165        this->inputChanged();
166    }
167
168    void Shell::addLine(const std::string& line, int level)
169    {
170        int original_level = OutputHandler::getOutStream().getOutputLevel();
171        OutputHandler::getOutStream().setOutputLevel(level);
172
173        if (!this->finishedLastLine_)
174            this->outputBuffer_ << std::endl;
175
176        this->outputBuffer_ << line << std::endl;
177        OutputHandler::getOutStream().setOutputLevel(original_level);
178    }
179
180    void Shell::clearLines()
181    {
182        this->lines_.clear();
183        this->scrollIterator_ = this->lines_.begin();
184
185        this->scrollPosition_ = 0;
186        this->finishedLastLine_ = true;
187
188        SHELL_UPDATE_LISTENERS(linesChanged);
189    }
190
191    std::list<std::string>::const_iterator Shell::getNewestLineIterator() const
192    {
193        if (this->scrollPosition_)
194            return this->scrollIterator_;
195        else
196            return this->lines_.begin();
197    }
198
199    std::list<std::string>::const_iterator Shell::getEndIterator() const
200    {
201        return this->lines_.end();
202    }
203
204    void Shell::addToHistory(const std::string& command)
205    {
206        ModifyConfigValue(commandHistory_, set, this->historyOffset_, command);
207        this->historyPosition_ = 0;
208        ModifyConfigValue(historyOffset_, set, (this->historyOffset_ + 1) % this->maxHistoryLength_);
209    }
210
211    std::string Shell::getFromHistory() const
212    {
213        unsigned int index = mod(((int)this->historyOffset_) - ((int)this->historyPosition_), this->maxHistoryLength_);
214        if (index < this->commandHistory_.size() && this->historyPosition_ != 0)
215            return this->commandHistory_[index];
216        else
217            return "";
218    }
219
220    void Shell::outputChanged()
221    {
222        std::string output;
223        bool newline;
224        do
225        {
226            newline = this->outputBuffer_.getLine(&output);
227
228            if (!newline && output == "")
229                break;
230
231            if (this->finishedLastLine_)
232            {
233                if (this->bAddOutputLevel_)
234                    output.insert(0, 1, (char)OutputHandler::getOutStream().getOutputLevel());
235
236                this->lines_.insert(this->lines_.begin(), output);
237
238                if (this->scrollPosition_)
239                    this->scrollPosition_++;
240                else
241                    this->scrollIterator_ = this->lines_.begin();
242
243                this->finishedLastLine_ = newline;
244
245                if (!this->scrollPosition_)
246                {
247                    SHELL_UPDATE_LISTENERS(lineAdded);
248                }
249            }
250            else
251            {
252                (*this->lines_.begin()) += output;
253                this->finishedLastLine_ = newline;
254                SHELL_UPDATE_LISTENERS(onlyLastLineChanged);
255            }
256
257        } while (newline);
258    }
259
260    void Shell::inputChanged()
261    {
262        SHELL_UPDATE_LISTENERS(inputChanged);
263        SHELL_UPDATE_LISTENERS(cursorChanged);
264    }
265
266    void Shell::execute()
267    {
268        this->addToHistory(this->inputBuffer_->get());
269        this->addLine(this->inputBuffer_->get(), 0);
270
271        if (!CommandExecutor::execute(this->inputBuffer_->get()))
272            this->addLine("Error: Can't execute \"" + this->inputBuffer_->get() + "\".", 1);
273
274        this->clear();
275    }
276
277    void Shell::hintandcomplete()
278    {
279        this->inputBuffer_->set(CommandExecutor::complete(this->inputBuffer_->get()));
280        this->addLine(CommandExecutor::hint(this->inputBuffer_->get()), -1);
281
282        this->inputChanged();
283    }
284
285    void Shell::backspace()
286    {
287        this->inputBuffer_->removeBehindCursor();
288        SHELL_UPDATE_LISTENERS(inputChanged);
289        SHELL_UPDATE_LISTENERS(cursorChanged);
290    }
291
292    void Shell::deletechar()
293    {
294        this->inputBuffer_->removeAtCursor();
295        SHELL_UPDATE_LISTENERS(inputChanged);
296    }
297
298    void Shell::clear()
299    {
300        this->inputBuffer_->clear();
301        this->historyPosition_ = 0;
302        SHELL_UPDATE_LISTENERS(inputChanged);
303        SHELL_UPDATE_LISTENERS(cursorChanged);
304    }
305
306    void Shell::cursor_right()
307    {
308        this->inputBuffer_->increaseCursor();
309        SHELL_UPDATE_LISTENERS(cursorChanged);
310    }
311
312    void Shell::cursor_left()
313    {
314        this->inputBuffer_->decreaseCursor();
315        SHELL_UPDATE_LISTENERS(cursorChanged);
316    }
317
318    void Shell::cursor_end()
319    {
320        this->inputBuffer_->setCursorToEnd();
321        SHELL_UPDATE_LISTENERS(cursorChanged);
322    }
323
324    void Shell::cursor_home()
325    {
326        this->inputBuffer_->setCursorToBegin();
327        SHELL_UPDATE_LISTENERS(cursorChanged);
328    }
329
330    void Shell::history_up()
331    {
332        if (this->historyPosition_ < this->commandHistory_.size())
333        {
334            this->historyPosition_++;
335            this->inputBuffer_->set(this->getFromHistory());
336        }
337    }
338
339    void Shell::history_down()
340    {
341        if (this->historyPosition_ > 0)
342        {
343            this->historyPosition_--;
344            this->inputBuffer_->set(this->getFromHistory());
345        }
346    }
347
348    void Shell::scroll_up()
349    {
350        if (this->scrollIterator_ != this->lines_.end())
351        {
352            ++this->scrollIterator_;
353            ++this->scrollPosition_;
354
355            SHELL_UPDATE_LISTENERS(linesChanged);
356        }
357    }
358
359    void Shell::scroll_down()
360    {
361        if (this->scrollIterator_ != this->lines_.begin())
362        {
363            --this->scrollIterator_;
364            --this->scrollPosition_;
365
366            SHELL_UPDATE_LISTENERS(linesChanged);
367        }
368    }
369
370    void Shell::exit()
371    {
372        if (this->inputBuffer_->getSize() > 0)
373        {
374            this->clear();
375            return;
376        }
377
378        this->clear();
379        this->scrollPosition_ = 0;
380        this->scrollIterator_ = this->lines_.begin();
381
382        SHELL_UPDATE_LISTENERS(exit);
383    }
384}
Note: See TracBrowser for help on using the repository browser.