+
+}
+// End of Console::autocomplete helper functions
+
+void
+Console::autocomplete()
+{
+ //int autocompleteFrom = inputBuffer.find_last_of(" ();+", inputBufferPosition);
+ int autocompleteFrom = inputBuffer.find_last_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_->.", inputBufferPosition);
+ if (autocompleteFrom != (int)std::string::npos) {
+ autocompleteFrom += 1;
+ } else {
+ autocompleteFrom = 0;
+ }
+ std::string prefix = inputBuffer.substr(autocompleteFrom, inputBufferPosition - autocompleteFrom);
+ addLines("> "+prefix);
+
+ std::list<std::string> cmds;
+
+ ready_vm();
+
+ // append all keys of the current root table to list
+ sq_pushroottable(vm); // push root table
+ while(true) {
+ // check all keys (and their children) for matches
+ sq_insert_commands(cmds, vm, "", prefix);
+
+ // cycle through parent(delegate) table
+ SQInteger oldtop = sq_gettop(vm);
+ if(SQ_FAILED(sq_getdelegate(vm, -1)) || oldtop == sq_gettop(vm)) {
+ break;
+ }
+ sq_remove(vm, -2); // remove old table
+ }
+ sq_pop(vm, 1); // remove table
+
+ // depending on number of hits, show matches or autocomplete
+ if (cmds.size() == 0) addLines("No known command starts with \""+prefix+"\"");
+ if (cmds.size() == 1) {
+ // one match: just replace input buffer with full command
+ std::string replaceWith = cmds.front();
+ inputBuffer.replace(autocompleteFrom, prefix.length(), replaceWith);
+ inputBufferPosition += (replaceWith.length() - prefix.length());
+ }
+ if (cmds.size() > 1) {
+ // multiple matches: show all matches and set input buffer to longest common prefix
+ std::string commonPrefix = cmds.front();
+ while (cmds.begin() != cmds.end()) {
+ std::string cmd = cmds.front();
+ cmds.pop_front();
+ addLines(cmd);
+ for (int n = commonPrefix.length(); n >= 1; n--) {
+ if (cmd.compare(0, n, commonPrefix) != 0) commonPrefix.resize(n-1); else break;
+ }
+ }
+ std::string replaceWith = commonPrefix;
+ inputBuffer.replace(autocompleteFrom, prefix.length(), replaceWith);
+ inputBufferPosition += (replaceWith.length() - prefix.length());
+ }
+}
+
+void
+Console::addLines(std::string s)
+{
+ std::istringstream iss(s);
+ std::string line;
+ while (std::getline(iss, line, '\n')) addLine(line);
+}
+
+void
+Console::addLine(std::string s)
+{
+ // output line to stderr
+ std::cerr << s << std::endl;
+
+ // wrap long lines
+ std::string overflow;
+ unsigned int line_count = 0;
+ do {
+ lines.push_front(Font::wrap_to_chars(s, 99, &overflow));
+ line_count++;
+ s = overflow;
+ } while (s.length() > 0);
+
+ // trim scrollback buffer
+ while (lines.size() >= 1000)
+ lines.pop_back();
+
+ // increase console height if necessary
+ if (height < 64) {
+ if(height < 4)
+ height = 4;
+ height += fontheight * line_count;
+ }
+
+ // reset console to full opacity
+ alpha = 1.0;
+
+ // increase time that console stays open
+ if(stayOpen < 6)
+ stayOpen += 1.5;
+}
+
+void
+Console::parse(std::string s)
+{
+ // make sure we actually have something to parse
+ if (s.length() == 0) return;
+
+ // add line to history
+ history.push_back(s);
+ history_position = history.end();
+
+ // split line into list of args
+ std::vector<std::string> args;
+ size_t start = 0;
+ size_t end = 0;
+ while (1) {
+ start = s.find_first_not_of(" ,", end);
+ end = s.find_first_of(" ,", start);
+ if (start == s.npos) break;
+ args.push_back(s.substr(start, end-start));
+ }
+
+ // command is args[0]
+ if (args.size() == 0) return;
+ std::string command = args.front();
+ args.erase(args.begin());
+
+ // ignore if it's an internal command
+ if (consoleCommand(command,args)) return;
+
+ try {
+ execute_script(s);
+ } catch(std::exception& e) {
+ addLines(e.what());
+ }
+
+}
+
+bool
+Console::consoleCommand(std::string /*command*/, std::vector<std::string> /*arguments*/)
+{
+ return false;
+}
+
+bool
+Console::hasFocus()
+{
+ return focused;
+}
+
+void
+Console::show()
+{
+ if(!config->console_enabled)
+ return;
+
+ focused = true;
+ height = 256;
+ alpha = 1.0;
+ SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
+}
+
+void
+Console::hide()
+{
+ focused = false;
+ height = 0;
+ stayOpen = 0;
+
+ // clear input buffer
+ inputBuffer = "";
+ inputBufferPosition = 0;
+ SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
+}
+
+void
+Console::toggle()
+{
+ if (Console::hasFocus()) {
+ Console::hide();
+ }
+ else {
+ Console::show();
+ }
+}
+
+void
+Console::update(float elapsed_time)
+{
+ if(stayOpen > 0) {
+ stayOpen -= elapsed_time;
+ if(stayOpen < 0)
+ stayOpen = 0;
+ } else if(!focused && height > 0) {
+ alpha -= elapsed_time * FADE_SPEED;
+ if(alpha < 0) {
+ alpha = 0;
+ height = 0;
+ }
+ }
+}
+
+void
+Console::draw(DrawingContext& context)
+{
+ if (height == 0)
+ return;
+
+ int layer = LAYER_GUI + 1;
+
+ context.push_transform();
+ context.set_alpha(alpha);
+ context.draw_surface(background2.get(), Vector(SCREEN_WIDTH/2 - background->get_width()/2 - background->get_width() + backgroundOffset, height - background->get_height()), layer);
+ context.draw_surface(background2.get(), Vector(SCREEN_WIDTH/2 - background->get_width()/2 + backgroundOffset, height - background->get_height()), layer);
+ for (int x = (SCREEN_WIDTH/2 - background->get_width()/2 - (static_cast<int>(ceilf((float)SCREEN_WIDTH / (float)background->get_width()) - 1) * background->get_width())); x < SCREEN_WIDTH; x+=background->get_width()) {
+ context.draw_surface(background.get(), Vector(x, height - background->get_height()), layer);
+ }
+ backgroundOffset+=10;
+ if (backgroundOffset > (int)background->get_width()) backgroundOffset -= (int)background->get_width();