예제 #1
0
void Terminal::SetPrompt(const char *input_){
	prompt = input_;
	
	//Calculate the offset.
	//This is long winded as we want to ignore the escape sequences
	offset = 0;
	size_t pos = 0, lastPos = 0;
	while ((pos = prompt.find("\033[",lastPos)) != std::string::npos) {
		//Increase offset by number characters prior to escape
		offset += pos - lastPos;
		lastPos = pos;

		//Identify which escape code we found.
		//First try reset code then loop through other codes
		if (pos == prompt.find(TermColors::Reset,pos)) {
			lastPos += std::string(TermColors::Reset).length();
		}
		else {
			for(auto it=attrMap.begin(); it!= attrMap.end(); ++it) {
				//If the attribute is at the same position then we found this attribute and we turn it on
				if (pos == prompt.find(it->first,pos)) {
					//Iterate position to suppress printing the escape string
					lastPos += std::string(it->first).length();
					break;
				}
			}
		}	
	}
	offset += prompt.length() - lastPos;
	update_cursor_();

	print(input_window,prompt.c_str());
	refresh_();
}
예제 #2
0
// Force a character to the input screen
void Terminal::in_char_(const char input_){
	cursX++;
	//If in insert mode we overwite the character otherwise insert it.
	if (cmd.GetInsertMode()) waddch(input_window, input_);
	else winsch(input_window, input_);
	update_cursor_();
	refresh_();
}
예제 #3
0
void Terminal::clear_(){
	for(int start = cmd.GetSize() + offset; start >= offset; start--){
		wmove(input_window, 0, start);
		wdelch(input_window);
	}
	cmd.Clear();
	cursX = offset;
	update_cursor_();
	refresh_();
}
예제 #4
0
void Terminal::Initialize(){
	if(init){ return; }
	
	original = std::cout.rdbuf(); // Back-up cout's streambuf
	pbuf = stream.rdbuf(); // Get stream's streambuf
	std::cout.flush();
	std::cout.rdbuf(pbuf); // Assign streambuf to cout
	
	main = initscr();
	
	if(main == NULL ){ // Attempt to initialize ncurses
		std::cout.rdbuf(original); // Restore cout's original streambuf
		fprintf(stderr, " Error: failed to initialize ncurses!\n");
	}
	else{		
   		getmaxyx(stdscr, _winSizeY, _winSizeX);
		output_window = newpad(_scrollbackBufferSize, _winSizeX);
		input_window = newpad(1, _winSizeX);
		wmove(output_window, _scrollbackBufferSize-1, 0); // Set the output cursor at the bottom so that new text will scroll up
		
		if (halfdelay(5) == ERR) { // Timeout after 5/10 of a second
			std::cout << "WARNING: Unable to set terminal blocking half delay to 0.5s!\n";
			std::cout << "\tThis will increase CPU usage in the command thread.\n";
			if (nodelay(input_window, true) == ERR) { //Disable the blocking timeout.
				std::cout << "ERROR: Unable to remove terminal blocking!\n";
				std::cout << "\tThe command thread will be locked until a character is entered. This will reduce functionality of terminal status bar and timeout.\n";
			}
		}
		keypad(input_window, true); // Capture special keys
		noecho(); // Turn key echoing off
		
		scrollok(output_window, true);
		scrollok(input_window, true);

		if (NCURSES_MOUSE_VERSION > 0) {		
			mousemask(ALL_MOUSE_EVENTS,NULL);
			mouseinterval(0);
		}

		init = true;
		offset = 0;
		
		// Set the position of the physical cursor
		cursX = 0; cursY = _winSizeY-1;
		update_cursor_();
		refresh_();

		init_colors_();
	}
	
	setup_signal_handlers();
}
예제 #5
0
/**Take the list of matching tab complete values and output resulting tab completion.
 * If the list is empty nothing happens, if a unique value is given the command is completed. If there are multiple
 * matches the common part of the matches is determined and printed to the input. If there is no common part of the
 * matches and the tab key has been pressed twice the list of matches is printed for the user to decide.
 *
 * \param[in] matches A vector of strings of trailing characters matching the current command.
 */
void Terminal::TabComplete(std::vector<std::string> matches) {
	//No tab complete matches so we do nothing.
	if (matches.size() == 0) {
		return;
	}
	//A unique match so we extend the command with completed text
	else if (matches.size() == 1) {
		if (matches.at(0).find("/") == std::string::npos && (unsigned int) (cursX - offset) == cmd.Get().length()) {
			matches.at(0).append(" ");
		}
		cmd.Insert(cursX - offset, matches.at(0).c_str());
		waddstr(input_window, cmd.Get().substr(cursX - offset).c_str());
		cursX += matches.at(0).length();
		text_length += matches.at(0).length();
	}
	else {
		//Fill out the matching part
		std::string commonStr = matches.at(0);
		for (auto it=matches.begin()+1;it!=matches.end() && !commonStr.empty();++it) {
			while (!commonStr.empty()) {
				if ((*it).find(commonStr) == 0) break;
				commonStr.erase(commonStr.length() - 1);
			}
		}
		if (!commonStr.empty()) {
			cmd.Insert(cursX - offset, commonStr.c_str());
			waddstr(input_window, cmd.Get().substr(cursX - offset).c_str());
			cursX += commonStr.length();
			text_length += commonStr.length();
		}
		//Display the options
		else if (tabCount > 1) {
			//Compute the header position
			size_t headerPos = cmd.Get().find_last_of(" /",cursX - offset - 1);
			std::string header;
			if (headerPos == std::string::npos) 
				header = cmd.Get();
			else
				header = cmd.Get().substr(headerPos+1,cursX - offset - 1 - headerPos);
			std::cout << prompt.c_str() << cmd.Get() << "\n";
			for (auto it=matches.begin();it!=matches.end();++it) {
				std::cout << header << (*it) << "\t";
			}
			std::cout << "\n";
		}
	}
	update_cursor_();
	refresh_();
}
예제 #6
0
/**Creates a status window and the refreshes the output. Takes an optional number of lines, defaulted to 1.
 *
 * \param[in] numLines Vertical size of status window.
 */
void Terminal::AddStatusWindow(unsigned short numLines) {
	_statusWindowSize = numLines;	
	//Create the new status pad.
	status_window = newpad(_statusWindowSize, _winSizeX);

	for (int i=0;i<numLines;i++) 
		statusStr.push_back(std::string(""));

	//Update the cursor position
	cursY = _winSizeY - _statusWindowSize - 1;
	update_cursor_();

	//Refresh the screen
	refresh_();
}
예제 #7
0
void Terminal::Initialize(){
	if(init){ return; }
	
	original = std::cout.rdbuf(); // Back-up cout's streambuf
	pbuf = stream.rdbuf(); // Get stream's streambuf
	std::cout.flush();
	std::cout.rdbuf(pbuf); // Assign streambuf to cout
	
	main = initscr();
	
	if(main == NULL ){ // Attempt to initialize ncurses
		std::cout.rdbuf(original); // Restore cout's original streambuf
		fprintf(stderr, " Error: failed to initialize ncurses!\n");
	}
	else{		
   		getmaxyx(stdscr, _winSizeY, _winSizeX);
		output_window = newpad(_scrollbackBufferSize, _winSizeX);
		input_window = newpad(1, _winSizeX);
		wmove(output_window, _scrollbackBufferSize-1, 0); // Set the output cursor at the bottom so that new text will scroll up
		
		halfdelay(5); // Timeout after 5/10 of a second
		keypad(input_window, true); // Capture special keys
		noecho(); // Turn key echoing off
		
		scrollok(output_window, true);
		scrollok(input_window, true);

		if (NCURSES_MOUSE_VERSION > 0) {		
			mousemask(ALL_MOUSE_EVENTS,NULL);
			mouseinterval(0);
		}

		init = true;
		text_length = 0;
		offset = 0;
		
		// Set the position of the physical cursor
		cursX = 0; cursY = _winSizeY-1;
		update_cursor_();
		refresh_();

		init_colors_();
	}
	
	setup_signal_handlers();
}
예제 #8
0
std::string Terminal::GetCommand(const int &prev_cmd_return_/*=0*/){
	std::string output = "";

	sclock::time_point commandRequestTime = sclock::now();
	sclock::time_point currentTime;

	//Update status message
	if (status_window) {
		werase(status_window);
		print(status_window,statusStr.at(0).c_str());
	}

	// Check for commands in the command queue.
	if(!prompt_user && !cmd_queue.empty()){ 
		while(true){
			output = cmd_queue.front();
			cmd_queue.pop_front();
			
			// Check for blank lines.
			if(!output.empty()){ break; }
		}
		from_script = true;
	}
	else{
		// Get a command from the user.
		while(true){
			if(SIGNAL_SEGFAULT){ // segmentation fault (SIGSEGV)
				Close();
				return "_SIGSEGV_";
			}
			if(SIGNAL_INTERRUPT){ // ctrl-c (SIGINT)
				SIGNAL_INTERRUPT = false;
				output = "CTRL_C";
				break;
			}
			if(SIGNAL_TERMSTOP){ // ctrl-z (SIGTSTP)
				SIGNAL_TERMSTOP = false;
				output = "CTRL_Z";
				break;
			}

			//Update status message
			if (status_window) {
				werase(status_window);
				print(status_window,statusStr.at(0).c_str());
			}

			flush(); // If there is anything in the stream, dump it to the screen

			// Time out if there is no command within the set interval (default 0.5 s). 
			if (commandTimeout_ > 0) {
				// Update the current time.
				currentTime = sclock::now();
				std::chrono::duration<float> time_span = std::chrono::duration_cast<std::chrono::duration<float>>(currentTime - commandRequestTime);
			
				// If the timeout has passed we simply return the empty output string.
				if (time_span.count() > commandTimeout_) {
					break;
				}
			}
		
			int keypress = wgetch(input_window);
	
			// Check for internal commands
			if(keypress == ERR){continue;} // No key was pressed in the interval
			else if(keypress == 10){ // Enter key (10)
				std::string temp_cmd = cmd.Get();
				//Reset the position in the history.
				commands.Reset();
				if(temp_cmd != "" && temp_cmd != commands.PeekPrev()){ // Only save this command if it is different than the previous command
					commands.Push(temp_cmd);
				}
				output = temp_cmd;
				std::cout << prompt << output << "\n";
				flush();
				_scrollPosition = 0;
				clear_();
				tabCount = 0;
				break;
			} 
			else if(keypress == '\t' && enableTabComplete) {
				tabCount++;
				output = cmd.Get().substr(0,cursX - offset) + "\t";
				break;
			}
			else if(keypress == 4){ // ctrl-d (EOT)
				output = "CTRL_D";
				clear_();
				tabCount = 0;
				break;
			}
			else if(keypress == 9){ } // Tab key (9)
			else if(keypress == KEY_UP){ // 259
				if(commands.GetIndex() == 0){ commands.Capture(cmd.Get()); }
				std::string temp_cmd = commands.GetPrev();
				if(temp_cmd != "NULL"){
					clear_();
					cmd.Set(temp_cmd);
					in_print_(cmd.Get().c_str());
				}
			}
			else if(keypress == KEY_DOWN){ // 258
				std::string temp_cmd = commands.GetNext();
				if(temp_cmd != "NULL"){
					clear_();
					cmd.Set(temp_cmd);
					in_print_(cmd.Get().c_str());
				}
			}
			else if(keypress == KEY_LEFT){ cursX--; } // 260
			else if(keypress == KEY_RIGHT){ cursX++; } // 261
			else if(keypress == KEY_PPAGE){ //Page up key
				scroll_(-(_winSizeY-2));
			}
			else if(keypress == KEY_NPAGE){ //Page down key
				scroll_(_winSizeY-2);
			}
			else if(keypress == KEY_BACKSPACE){ // 263
				wmove(input_window, 0, --cursX);
				wdelch(input_window);
				cmd.Pop(cursX - offset);
			}
			else if(keypress == KEY_DC){ // Delete character (330)
				//Remove character from terminal
				wdelch(input_window);
				//Remove character from cmd string
				cmd.Pop(cursX - offset);
			}
			else if(keypress == KEY_IC){ cmd.ToggleInsertMode(); } // Insert key (331)
			else if(keypress == KEY_HOME){ cursX = offset; }
			else if(keypress == KEY_END){ cursX = cmd.GetSize() + offset; }
			else if(keypress == KEY_MOUSE) { //Handle mouse events
				MEVENT mouseEvent;
				//Get information about mouse event.
				getmouse(&mouseEvent);
			
				switch (mouseEvent.bstate) {
					//Scroll up
					case BUTTON4_PRESSED:
						scroll_(-3);
						break;
					//Scroll down. (Yes the name is strange.)
					case REPORT_MOUSE_POSITION:
						scroll_(3);
						break;
				}
			}	
			else if(keypress == KEY_RESIZE) {
				//Do nothing with the resize key
			}
			else{ 
				in_char_((char)keypress); 
				cmd.Put((char)keypress, cursX - offset - 1);
			}

			// Check for cursor too far to the left
			if(cursX < offset){ cursX = offset + cmd.GetSize(); }
	
			// Check for cursor too far to the right
			if(cursX > (int)(cmd.GetSize() + offset)){ cursX = cmd.GetSize() + offset; }
	
			if (keypress != ERR) tabCount = 0;
			update_cursor_();
			refresh_();
		}
		
		if(prompt_user){ // Waiting for user to specify yes or no.
			if(output != "yes" && output != "y"){
				std::cout << prompt << "Aborting execution!\n";
				cmd_queue.clear();
			}
			prompt_user = false;
			return "";
		}
		
		from_script = false;
	}

	// In the event of an empty command, return.
	if(output.empty())
		return "";
		
	// Check for system commands.
	std::string temp_cmd_string = output.substr(output.find_first_not_of(' '), output.find_first_of(' ')); // Strip the command from the front of the input.
	std::string temp_arg_string = output.substr(output.find_first_of(' ')+1, output.find_first_of('#')); // Does not ignore leading whitespace.

	if(temp_cmd_string.empty() || temp_cmd_string[0] == '#'){
		// This is a comment line.
		return "";
	}

	if(temp_cmd_string.substr(0, output.find_first_of(' ')).find('.') != std::string::npos){
		if(temp_cmd_string == ".cmd"){ // Load a command script.
			std::string command_filename = temp_arg_string.substr(output.find_first_not_of(' ')); // Ignores leading whitespace.
			if(!LoadCommandFile(command_filename.c_str())){ // Failed to load command script.
				std::cout << prompt << "Error! Failed to load command script " << command_filename << ".\n";
			}
		}
		else if(temp_cmd_string == ".echo"){ // Print something to the screen.
			std::cout << prompt << temp_arg_string << std::endl;
		}
		else if(temp_cmd_string == ".prompt"){ // Prompt the user with a yes/no question.
			std::cout << prompt << temp_arg_string << " (yes/no)" << std::endl;
			prompt_user = true;
		}
		else{ // Unrecognized command.
			std::cout << prompt << "Error! Unrecognized system command " << temp_cmd_string << ".\n";
		}
	
		return ""; // Done processing the command. Don't need to send it to the caller.
	}

	// Print the command if it was read from a script. This is done so that the user
	// will know what is happening in the script file. It will also ignore system
	// commands in the file.
	if(from_script){
		std::cout << prompt << output << "\n";
		flush();
		_scrollPosition = 0;
		clear_();
		tabCount = 0;
	}
	
	return output;
}
예제 #9
0
// Force text to the input screen
void Terminal::in_print_(const char* input_){
	cursX += cstrlen(input_);
	waddstr(input_window, input_);
	update_cursor_();
	refresh_();
}
예제 #10
0
std::string Terminal::GetCommand(){
	std::string output = "";
	time_t commandRequestTime;
	time_t currentTime;
	time(&commandRequestTime);

	//Update status message
	if (status_window) {
		werase(status_window);
		print(status_window,statusStr.at(0).c_str());
	}

	while(true){
		if(SIGNAL_SEGFAULT){ // segmentation fault (SIGSEGV)
			Close();
			return "_SIGSEGV_";
		}
		if(SIGNAL_INTERRUPT){ // ctrl-c (SIGINT)
			SIGNAL_INTERRUPT = false;
			output = "CTRL_C";
			text_length = 0;
			break;
		}
		else if(SIGNAL_TERMSTOP){ // ctrl-z (SIGTSTP)
			SIGNAL_TERMSTOP = false;
			output = "CTRL_Z";
			text_length = 0;
			break;
		}

		flush(); // If there is anything in the stream, dump it to the screen

		//Time out if there is no command within the set interval (default 0.5 s). 
		if (commandTimeout_ > 0) {
			time(&currentTime);
			//If the timeout has passed we simply return the empty output string.
			if (currentTime > commandRequestTime + commandTimeout_) {
				break;
			}
		}
		
		int keypress = wgetch(input_window);
	
		// Check for internal commands
		if(keypress == ERR){ } // No key was pressed in the interval
		else if(keypress == 10){ // Enter key (10)
			std::string temp_cmd = cmd.Get();
			//Reset the position in the history.
			commands.Reset();
			if(temp_cmd != "" && temp_cmd != commands.PeekPrev()){ // Only save this command if it is different than the previous command
				commands.Push(temp_cmd);
			}
			output = temp_cmd;
			std::cout << prompt << output << "\n";
			flush();
			text_length = 0;
			_scrollPosition = 0;
			clear_();
			tabCount = 0;
			break;
		} 
		else if(keypress == '\t' && enableTabComplete) {
			tabCount++;
			output = cmd.Get().substr(0,cursX - offset) + "\t";
			break;
		}
		else if(keypress == 4){ // ctrl-d (EOT)
			output = "CTRL_D";
			text_length = 0;
			clear_();
			tabCount = 0;
			break;
		}
		else if(keypress == 9){ } // Tab key (9)
		else if(keypress == KEY_UP){ // 259
			if(commands.GetIndex() == 0){ commands.Capture(cmd.Get()); }
			std::string temp_cmd = commands.GetPrev();
			if(temp_cmd != "NULL"){
				clear_();
				cmd.Set(temp_cmd);
				in_print_(cmd.Get().c_str());
				text_length = cmd.GetSize();
			}
		}
		else if(keypress == KEY_DOWN){ // 258
			std::string temp_cmd = commands.GetNext();
			if(temp_cmd != "NULL"){
				clear_();
				cmd.Set(temp_cmd);
				in_print_(cmd.Get().c_str());
				text_length = cmd.GetSize();
			}
		}
		else if(keypress == KEY_LEFT){ cursX--; } // 260
		else if(keypress == KEY_RIGHT){ cursX++; } // 261
		else if(keypress == KEY_PPAGE){ //Page up key
			scroll_(-(_winSizeY-2));
		}
		else if(keypress == KEY_NPAGE){ //Page down key
			scroll_(_winSizeY-2);
		}
		else if(keypress == KEY_BACKSPACE){ // 263
			wmove(input_window, 0, --cursX);
			wdelch(input_window);
			cmd.Pop(cursX - offset);
			text_length = cmd.GetSize();
		}
		else if(keypress == KEY_DC){ // Delete character (330)
			//Remove character from terminal
			wdelch(input_window);
			//Remove character from cmd string
			cmd.Pop(cursX - offset);
			text_length = cmd.GetSize();
		}
		else if(keypress == KEY_IC){ cmd.ToggleInsertMode(); } // Insert key (331)
		else if(keypress == KEY_HOME){ cursX = offset; }
		else if(keypress == KEY_END){ cursX = text_length + offset; }
		else if(keypress == KEY_MOUSE) { //Handle mouse events
			MEVENT mouseEvent;
			//Get information about mouse event.
			getmouse(&mouseEvent);
			
			switch (mouseEvent.bstate) {
				//Scroll up
				case BUTTON4_PRESSED:
					scroll_(-3);
					break;
				//Scroll down. (Yes the name is strange.)
				case REPORT_MOUSE_POSITION:
					scroll_(3);
					break;
			}
		}	
		else if(keypress == KEY_RESIZE) {
			//Do nothing with the resize key
		}
		else{ 
			in_char_((char)keypress); 
			cmd.Put((char)keypress, cursX - offset - 1);
			text_length = cmd.GetSize();
		}
		
		// Check for cursor too far to the left
		if(cursX < offset){ cursX = offset; }
	
		// Check for cursor too far to the right
		if(cursX > (text_length + offset)){ cursX = text_length + offset; }
	
		//Update status message
		if (status_window) {
			werase(status_window);
			print(status_window,statusStr.at(0).c_str());
		}

		if (keypress != ERR) tabCount = 0;
		update_cursor_();
		refresh_();
	}
	return output;
}