Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

ok, I fixed something.

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 "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            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, KeyCode::Delete);
113        this->inputBuffer_->registerListener(this, &Shell::exit, (char)27, true);
114        this->inputBuffer_->registerListener(this, &Shell::cursor_right, KeyCode::Right);
115        this->inputBuffer_->registerListener(this, &Shell::cursor_left, KeyCode::Left);
116        this->inputBuffer_->registerListener(this, &Shell::cursor_end, KeyCode::End);
117        this->inputBuffer_->registerListener(this, &Shell::cursor_home, KeyCode::Home);
118        this->inputBuffer_->registerListener(this, &Shell::history_up, KeyCode::Up);
119        this->inputBuffer_->registerListener(this, &Shell::history_down, KeyCode::Down);
120        this->inputBuffer_->registerListener(this, &Shell::scroll_up, KeyCode::PageUp);
121        this->inputBuffer_->registerListener(this, &Shell::scroll_down, KeyCode::PageDown);
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.