/* server/console.cc This file is part of the Osirion project and is distributed under the terms and conditions of the GNU General Public License version 2 */ #include #include #include "server/console.h" #include "core/core.h" #include "sys/consoleinterface.h" #include "auxiliary/functions.h" #ifdef HAVE_CURSES #include #endif namespace server { bool console_initialized = false; bool console_updated = false; const size_t MAXHISTOLINES = 512; Console server_console; #ifdef HAVE_CURSES WINDOW *stdwin; #endif Console *console() { return (&server_console); } void Console::init() { #ifdef HAVE_CURSES stdwin = initscr(); // initialize the ncurses window cbreak(); // disable input line buffering noecho(); // don't show typed characters keypad(stdwin, TRUE); // enable special keys nodelay(stdwin, TRUE); // non-blocking input curs_set(1); // disable cursor if (has_colors() == TRUE) { start_color(); // this is ncurses-specific use_default_colors(); // COLOR_PAIR(0) is terminal default init_pair(1, COLOR_RED, -1); init_pair(2, COLOR_GREEN, -1); init_pair(3, COLOR_YELLOW, -1); init_pair(4, COLOR_BLUE, -1); init_pair(5, COLOR_CYAN, -1); init_pair(6, COLOR_MAGENTA, -1); init_pair(7, -1, -1); } console_initialized = true; console_updated = true; #endif // HAVE_CURSES con_print << "Initializing console..." << std::endl; #ifdef HAVE_CURSES server_console.history.clear(); server_console.history.push_back(""); server_console.history_pos = server_console.history.rbegin(); server_console.input_pos = 0; server_console.draw(); #endif // HAVE_CURSES } void Console::shutdown() { con_print << "Shutting down console..." << std::endl; #ifdef HAVE_CURSES server_console.draw(); endwin(); console_initialized = false; #endif } #ifdef HAVE_CURSES void Console::resize() { if (!console_initialized) return; endwin(); refresh(); draw(); } void Console::flush() { if (rcon()) return; char line[MAXCMDSIZE]; while(consoleinterface_buffer.getline(line, MAXCMDSIZE-1)) { while (consoleinterface_text.size() >= sys::MAXCONLINES) { consoleinterface_text.pop_front(); } consoleinterface_text.push_back(std::string(line)); console_updated = true; } consoleinterface_buffer.clear(); } void Console::set_color(const char *color_code) { if (!has_colors()) return; int color = 0; bool bold = false; if (aux::is_base_color_code(color_code)) { // base colors // Black=0, Red=1, Green=2, Yellow=3, Blue=4, Cyan=5, Magenta=6, White=7 color = *(color_code+1) - '0'; if (color == 3 || color == 0) bold = true; else bold = false; } else if (aux::is_core_color_code(color_code)) { switch (*(color_code+1)) { case 'N': // normal color case 'D': // debug color color = 0; break; case 'B': // bold color color = 0; bold = true; break; case 'W': // warning color color = 3; bold = true; break; case 'R': // error color color = 1; bold = true; break; case 'F': // fancy color color = 2; bold = true; break; } } color_set(color, NULL); if (bold) attron(A_BOLD); else attroff(A_BOLD); } void Console::draw_background() { color_set(0, NULL); attroff(A_BOLD); bkgdset(' '); clear(); // draw version string color_set(2, NULL); std::string versionstr("The Osirion Project "); versionstr.append(core::version()); int y = stdwin->_maxx - 1 - versionstr.size(); if (y < 0) y = 0; mvaddnstr(0, y, versionstr.c_str(), stdwin->_maxx - 1); } void Console::draw_text() { int w = stdwin->_maxx; int h = stdwin->_maxy; if ((w < 3) || (h < 3)) return; std::deque lines; int console_scroll = 0; int height = stdwin->_maxy - 2; int width = stdwin->_maxx - 1; int bottom = (int) consoleinterface_text.size() - console_scroll; int current_line = 0; // parse console text, wrap long lines for (std::deque::iterator it = consoleinterface_text.begin(); it != consoleinterface_text.end() && current_line < bottom; it++) { if (current_line >= bottom - height) { std::string linedata(*it); linedata += '\n'; std::string word; int word_length = 0; std::string line; int line_length = 0; const char *c = linedata.c_str(); char pen = 'N'; char wordpen = 'N'; while (*c) { // color code if (aux::is_color_code(c)) { c++; pen = *c; word += '^'; word += pen; } // new word, wrap if necessary else if ((*c == '\n' ) || ( *c == ' ')) { if (line_length + word_length > width) { if (line.size()) { lines.push_back(line); line.clear(); line += '^'; line += wordpen; line_length = 0; } } line.append(word); line_length += word_length; word.clear(); word_length = 0; wordpen = pen; // new line if (*c == '\n' ) { lines.push_back(line); line.clear(); line_length = 0; // new word } else if (*c == ' ' ) { line += ' '; line_length++; } } // new character else { word += *c; word_length++; if (word_length == width) { if (line.size()) { lines.push_back(line); line.clear(); line += '^'; line += wordpen; line_length = 0; } line.append(word); line_length = word_length; word.clear(); word_length = 0; wordpen = pen; } } c++; } } current_line++; } int y = stdwin->_maxy - 1; color_set(0, NULL); attroff(A_BOLD); for (std::deque::reverse_iterator rit = lines.rbegin(); (y > 0) && (rit != lines.rend()); ++rit) { const char *c = (*rit).c_str(); int x = 0; while (*c) { if (aux::is_color_code(c)) { set_color(c); c++; } else { mvaddnstr(y, x, c, 1); x++; } c++; } y--; } } void Console::draw_input() { color_set(0, NULL); attron(A_BOLD); // draw input text mvaddstr(stdwin->_maxy, 0, ">"); mvaddstr(stdwin->_maxy, 1, (*history_pos).c_str()); // fill the remainder with spaces for (int i=1 + (*history_pos).size(); i < stdwin->_maxx; i++) addch(' '); // move the cursor to input position move(stdwin->_maxy, 1 + (*history_pos).size()); } void Console::draw() { if (!console_initialized) return; draw_background(); draw_text(); draw_input(); wrefresh(stdwin); console_updated = false; console_lastrefresh = 0; } void Console::frame(float seconds) { flush(); if (!console_initialized) return; console_lastrefresh += seconds; bool input_updated = false; int key = wgetch(stdwin); while (key != ERR) { if (key == KEY_BACKSPACE || key == 8 || key == 127) { if ((*history_pos).size() && input_pos) { (*history_pos).erase(input_pos-1, 1); input_pos--; input_updated = true; } break; } else if (key == KEY_STAB || key ==9) { core::CommandBuffer::complete( (*history_pos), input_pos); input_updated = true; break; } else if (key == KEY_LEFT) { } else if (key == KEY_HOME) { } else if (key == KEY_RIGHT) { } else if (key == KEY_END) { } else if (key == KEY_UP) { } else if (key == KEY_DOWN) { } else if (key == KEY_ENTER || key == '\n') { if ((*history_pos).size()) { // store input into history while (history.size() >= MAXHISTOLINES) { history.pop_front(); } core::cmd() << (*history_pos) << std::endl; con_print << "^B>" << (*history_pos) << std::endl; (*history.rbegin()) = (*history_pos); history.push_back(""); history_pos = history.rbegin(); input_pos = 0; input_updated = true; } break; } else if (key == KEY_PPAGE) { } else if (key == KEY_NPAGE) { } else if ((key >= 32) && (key < 127) && ((*history_pos).size() < MAXCMDSIZE)) { if (input_pos == (*history_pos).size()) { (*history_pos) += (char)key; } else { (*history_pos).insert(input_pos, 1, (char)key); } input_pos++; input_updated = true; } key = wgetch(stdwin); } if (console_updated) { draw(); } else if (input_updated) { draw_input(); } } #endif // HAVE_CURSES }