35 #include "../../commands_h.h"
40 , m_currentCommandCursorPosition(0)
41 , m_inEscapeSequence(false)
42 , m_historyEntryToCopyFrom(0)
43 , m_commandHistoryInsertPosition(0)
44 , m_commandHistoryMaxSize(100)
46 m_commandHistory.resize(m_commandHistoryMaxSize,
"");
49 assert(m_GXemul != NULL);
53 #include "../../commands.h"
72 return m_commandHistoryInsertPosition;
74 size_t lastInsertedPosition =
75 (m_commandHistoryInsertPosition - 1 + m_commandHistoryMaxSize)
76 % m_commandHistoryMaxSize;
78 if (m_commandHistory[lastInsertedPosition] == command)
79 return m_commandHistoryInsertPosition;
81 m_commandHistory[m_commandHistoryInsertPosition ++] = command;
82 m_commandHistoryInsertPosition %= m_commandHistoryMaxSize;
84 return m_commandHistoryInsertPosition;
93 int index = (m_commandHistoryInsertPosition - nStepsBack +
94 m_commandHistoryMaxSize) % m_commandHistoryMaxSize;
96 return m_commandHistory[index];
100 bool CommandInterpreter::TabComplete(
string& commandString,
101 size_t& cursorPosition,
bool visibleShowAvailable)
103 string wordToComplete;
104 bool firstWordOnLine =
true;
106 size_t pos = cursorPosition;
109 if (commandString[pos] ==
' ')
111 wordToComplete = commandString[pos] + wordToComplete;
116 if (commandString[pos] !=
' ') {
117 firstWordOnLine =
false;
122 bool completeCommands = firstWordOnLine;
124 if (wordToComplete ==
"") {
125 if (!visibleShowAvailable)
130 if (completeCommands) {
132 vector<string> allCommands;
133 for (Commands::const_iterator it = m_commands.begin();
134 it != m_commands.end(); ++it)
135 allCommands.push_back(it->first);
137 ShowAvailableWords(allCommands);
141 FindPathByPartialMatch(
""));
146 vector<string> matches;
149 FindPathByPartialMatch(wordToComplete,
true);
151 if (completeCommands) {
152 Commands::const_iterator it = m_commands.begin();
153 for (; it != m_commands.end(); ++it) {
154 const string& commandName = it->first;
155 if (commandName.substr(0, wordToComplete.length())
157 matches.push_back(commandName);
162 if (matches.size() == 0)
165 string completedWord;
168 if (matches.size() == 1) {
170 completedWord = matches[0];
173 size_t i, n = matches.size();
174 for (
size_t pos2 = 0; ; pos2 ++) {
175 if (pos2 >= matches[0].length())
178 for (i=1; i<n; i++) {
179 if (matches[i][pos2] != ch)
190 if (visibleShowAvailable)
191 ShowAvailableWords(matches);
195 if (!completedWord.empty()) {
196 cursorPosition -= wordToComplete.length();
197 commandString.erase(cursorPosition, wordToComplete.length());
198 commandString.insert(cursorPosition, completedWord);
199 cursorPosition += completedWord.length();
211 if (matches.size() == 1 && cursorPosition == commandString.length()) {
212 bool isCommand =
false;
213 Commands::const_iterator it = m_commands.begin();
214 for (; it != m_commands.end(); ++it) {
215 const string& commandName = it->first;
216 if (commandName == matches[0]) {
223 commandString +=
" ";
228 return matches.size() == 1;
232 bool CommandInterpreter::TabCompleteWithSubname(
string& commandString,
233 size_t& cursorPosition,
bool visibleShowAvailable)
235 if (cursorPosition == 0)
239 size_t pos = cursorPosition - 1;
241 while (pos > 0 && commandString[pos] !=
'.') {
254 bool success = TabComplete(commandString, pos, visibleShowAvailable);
264 int startOfComponentName = pos;
265 while (startOfComponentName >= 0 &&
266 commandString[startOfComponentName] !=
' ')
267 -- startOfComponentName;
269 if (startOfComponentName < 0)
270 startOfComponentName = 0;
272 string componentName = commandString.substr(startOfComponentName,
273 pos - startOfComponentName);
277 LookupPath(componentName);
279 cursorPosition = pos + nStepsBack;
285 size_t startOfMethodName = pos + 1;
286 size_t methodNameLen = 0;
287 while (startOfMethodName + methodNameLen < cursorPosition &&
288 commandString[startOfMethodName+methodNameLen] !=
' ')
291 string methodName = commandString.substr(startOfMethodName,
296 vector<string> names;
297 vector<string> matchingNames;
301 if (methodName.length() != 0) {
302 for (
size_t i=0; i<names.size(); ++i) {
303 if (names[i].substr(0, methodName.length()) ==
306 matchingNames.push_back(names[i]);
310 matchingNames = names;
313 if (matchingNames.size() == 0)
319 string longestPossibleMatch =
"";
320 size_t i, n = matchingNames.size();
321 for (
size_t pos2 = 0; ; pos2 ++) {
322 if (pos2 >= matchingNames[0].length())
325 for (i=1; i<n; i++) {
326 if (matchingNames[i][pos2] != ch)
330 longestPossibleMatch += ch;
335 commandString.replace(startOfMethodName, methodNameLen,
336 longestPossibleMatch);
337 cursorPosition += longestPossibleMatch.length() - methodNameLen;
340 if (nrOfMatches == 1)
344 if (visibleShowAvailable) {
345 vector<string> allNames;
346 vector<string> matchingNames2;
349 for (
size_t j=0; j<allNames.size(); ++j) {
350 if (methodName.length() == 0 ||
351 allNames[j].substr(0, methodName.length()) == methodName)
352 matchingNames2.push_back(allNames[j]);
355 if (matchingNames2.size() > 0) {
357 ShowAvailableWords(matchingNames2);
360 if (visibleShowAvailable) {
361 vector<string> allNames;
362 vector<string> matchingNames2;
365 for (
size_t j=0; j<allNames.size(); ++j) {
366 if (methodName.length() == 0 ||
367 allNames[j].substr(0, methodName.length()) == methodName)
368 matchingNames2.push_back(allNames[j]);
371 if (matchingNames2.size() > 0) {
373 ShowAvailableWords(matchingNames2);
383 if (m_inEscapeSequence) {
384 m_escapeSequence += key;
389 if (m_escapeSequence ==
"[C") {
390 m_inEscapeSequence =
false;
392 }
else if (m_escapeSequence ==
"[D") {
393 m_inEscapeSequence =
false;
395 }
else if (m_escapeSequence ==
"OH") {
396 m_inEscapeSequence =
false;
398 }
else if (m_escapeSequence ==
"[H") {
399 m_inEscapeSequence =
false;
401 }
else if (m_escapeSequence ==
"OF") {
402 m_inEscapeSequence =
false;
404 }
else if (m_escapeSequence ==
"[F") {
405 m_inEscapeSequence =
false;
407 }
else if (m_escapeSequence ==
"[A") {
408 m_inEscapeSequence =
false;
410 }
else if (m_escapeSequence ==
"[B") {
411 m_inEscapeSequence =
false;
413 }
else if (m_escapeSequence.length() > 2) {
420 m_inEscapeSequence =
false;
434 m_currentCommandCursorPosition = 0;
438 if (m_currentCommandCursorPosition > 0)
439 m_currentCommandCursorPosition --;
443 if (m_currentCommandCursorPosition <
444 m_currentCommandString.length())
445 m_currentCommandString.erase(
446 m_currentCommandCursorPosition, 1);
450 m_currentCommandCursorPosition =
451 m_currentCommandString.length();
455 if (m_currentCommandCursorPosition <
456 m_currentCommandString.length())
457 m_currentCommandCursorPosition ++;
461 ClearCurrentInputLineVisually();
462 m_currentCommandString.resize(m_currentCommandCursorPosition);
466 ClearCurrentInputLineVisually();
468 m_historyEntryToCopyFrom --;
469 if (m_historyEntryToCopyFrom < 0)
470 m_historyEntryToCopyFrom = 0;
472 m_currentCommandString =
474 m_currentCommandCursorPosition =
475 m_currentCommandString.length();
479 ClearCurrentInputLineVisually();
481 m_historyEntryToCopyFrom ++;
482 m_currentCommandString =
486 if (m_currentCommandString ==
"") {
487 m_historyEntryToCopyFrom --;
488 m_currentCommandString =
491 m_currentCommandCursorPosition =
492 m_currentCommandString.length();
501 ClearCurrentInputLineVisually();
504 while (m_currentCommandCursorPosition > 0) {
505 if (m_currentCommandString[
506 m_currentCommandCursorPosition-1] ==
' ') {
507 m_currentCommandCursorPosition --;
508 m_currentCommandString.erase(
509 m_currentCommandCursorPosition, 1);
518 while (m_currentCommandCursorPosition > 0) {
519 if (m_currentCommandString[
520 m_currentCommandCursorPosition-1] !=
' ') {
521 m_currentCommandCursorPosition --;
522 m_currentCommandString.erase(
523 m_currentCommandCursorPosition, 1);
533 if (m_currentCommandCursorPosition > 0) {
534 m_currentCommandCursorPosition --;
535 m_currentCommandString.erase(
536 m_currentCommandCursorPosition, 1);
542 m_inEscapeSequence =
true;
543 m_escapeSequence =
"";
549 bool success = TabComplete(m_currentCommandString,
550 m_currentCommandCursorPosition,
true);
556 TabCompleteWithSubname(m_currentCommandString,
557 m_currentCommandCursorPosition,
true);
567 if (!m_currentCommandString.empty()) {
570 RunCommand(m_currentCommandString, &ignoredResult);
572 }
else if (m_mayBeReexecuted !=
"") {
581 m_currentCommandString.insert(
582 m_currentCommandCursorPosition, 1, key);
583 m_currentCommandCursorPosition ++;
587 if (key !=
'\n' && key !=
'\r')
591 return key ==
'\n' || key ==
'\r';
595 void CommandInterpreter::ShowAvailableWords(
const vector<string>& words)
599 const size_t n = words.size();
604 for (i=0; i<n; ++i) {
605 size_t len = words[i].length();
613 std::stringstream msg;
615 for (i=0; i<n; ++i) {
619 size_t len = words[i].length();
623 for (
size_t j=len; j<maxLen; j++) {
628 if (lineLen >= 77 - maxLen || i == n-1) {
641 m_currentCommandString, m_currentCommandCursorPosition);
645 void CommandInterpreter::ClearCurrentInputLineVisually()
647 string clearString =
"";
648 clearString.insert((
size_t)0, m_currentCommandString.length(),
' ');
651 clearString, m_currentCommandCursorPosition);
657 m_currentCommandString =
"";
658 m_currentCommandCursorPosition = 0;
659 m_historyEntryToCopyFrom = 0;
663 static void SplitIntoWords(
const string& commandOrig,
664 string& commandName, vector<string>& arguments)
666 string command = commandOrig;
675 int insideParenthesesCount = 0;
676 while (pos < command.length()) {
677 if (command[pos] ==
'(')
678 insideParenthesesCount ++;
679 if (command[pos] ==
')')
680 insideParenthesesCount --;
681 if (command[pos] ==
'=' && insideParenthesesCount == 0) {
682 command.replace(pos, 1,
" = ");
691 while (pos < command.length()) {
693 while (pos < command.length() && command[pos] ==
' ')
696 if (pos >= command.length())
702 while (pos < command.length() && command[pos] !=
' ') {
703 newWord += command[pos];
707 if (commandName.empty())
708 commandName = newWord;
710 arguments.push_back(newWord);
715 void CommandInterpreter::VariableAssignment(
const string& componentPath,
716 const string& variableName,
const string& expression)
719 LookupPath(componentPath);
724 variableName +
"'? (Internal error.)\n");
725 throw std::exception();
738 stringstream changeMessages;
741 string msg = changeMessages.str();
743 msg =
"(No state change.)\n";
749 bool CommandInterpreter::RunComponentMethod(
750 const string& componentPathAndMethod,
const vector<string>& arguments)
757 string componentPath;
764 LookupPath(componentPathAndMethod);
770 string tabcompleted = componentPathAndMethod;
771 size_t tmpLen = tabcompleted.length();
772 if (TabComplete(tabcompleted, tmpLen)) {
774 LookupPath(tabcompleted);
781 if (componentPathAndMethod.find(
".") == string::npos)
784 size_t pos = componentPathAndMethod.find_last_of(
'.');
787 componentPath = componentPathAndMethod.substr(0, pos);
789 LookupPath(componentPath);
790 if (!component.
IsNULL()) {
791 methodName = componentPathAndMethod.substr(pos+1);
796 tabcompleted = componentPath;
797 tmpLen = tabcompleted.length();
798 if (TabComplete(tabcompleted, tmpLen)) {
800 LookupPath(tabcompleted);
801 if (!component.
IsNULL()) {
803 componentPathAndMethod.substr(pos+1);
814 if (methodName.empty()) {
819 vector<string> variableNames;
827 for (i=0; i<variableNames.size(); i++)
828 if (variableNames[i].length() > maxLen)
829 maxLen = variableNames[i].length();
831 for (i=0; i<variableNames.size(); i++) {
832 const string& name = variableNames[i];
833 if (name ==
"name" || name ==
"template")
837 for (
size_t j=name.length(); j<=maxLen; j++)
842 ss <<
"= (unknown?)";
856 vector<string> names;
860 for (
size_t i=0; i<names.size(); ++i) {
861 if (names[i].substr(0, methodName.length()) == methodName) {
863 fullMatch = names[i];
867 if (nrOfMatches == 1) {
872 m_mayBeReexecuted = componentPathAndMethod;
882 for (
size_t i=0; i<names.size(); ++i) {
884 if (names[i] == methodName) {
886 fullMatch = names[i];
891 if (names[i].substr(0, methodName.length()) == methodName) {
893 fullMatch = names[i];
899 if (nrOfMatches == 1) {
900 if (arguments.size() > 0) {
901 if (arguments.size() == 1 ||
902 arguments[0] !=
"=") {
907 "Syntax error. Variable assignment syntax"
908 " is:\n <variable> = <expression>\n");
916 "Unknown variable.\n");
921 for (
size_t i=1; i<arguments.size(); ++i)
922 assignment += arguments[i] +
" ";
924 VariableAssignment(component->
GeneratePath(), fullMatch, assignment);
934 ss <<
" = (unknown variable?)";
946 ss << methodName <<
": ambiguous method or variable name of "
949 ss << methodName <<
": not a method or variable of "
961 vector<string> arguments;
962 SplitIntoWords(command, commandName, arguments);
964 m_mayBeReexecuted =
"";
969 Commands::iterator it = m_commands.find(commandName);
970 if (it == m_commands.end()) {
972 string commandTabCompleted = commandName;
973 size_t tmpCursorPos = commandTabCompleted.length();
974 TabComplete(commandTabCompleted, tmpCursorPos);
977 while (commandTabCompleted.length() > 0 &&
978 commandTabCompleted[commandTabCompleted.length()-1] ==
' ')
979 commandTabCompleted.erase(
980 commandTabCompleted.length() - 1);
983 it = m_commands.find(commandTabCompleted);
984 if (it == m_commands.end()) {
987 if (RunComponentMethod(commandName, arguments))
990 ": unknown command. Type help for help.\n");
995 if (arguments.size() != 0 && (it->second)->GetArgumentFormat() ==
"") {
997 " takes no arguments. Type help " + commandName +
998 " for help on the syntax.\n");
1003 bool success = (it->second)->Execute(*m_GXemul, arguments);
1004 if (pSuccess != NULL) {
1005 *pSuccess = success;
1012 if ((it->second)->MayBeReexecutedWithoutArgs())
1013 m_mayBeReexecuted = it->first;
1021 return m_currentCommandString;
1028 #ifdef WITHUNITTESTS
1030 static void Test_CommandInterpreter_AddKey_ReturnValue()
1036 ci.
AddKey(
'a') ==
false);
1039 ci.
AddKey(
'\0') ==
false);
1042 ci.
AddKey(
'\n') ==
true);
1045 ci.
AddKey(
'\r') ==
true);
1048 static void Test_CommandInterpreter_KeyBuffer()
1118 static void Test_CommandInterpreter_KeyBuffer_CursorMovement()
1175 static void Test_CommandInterpreter_KeyBuffer_CtrlK()
1208 static void Test_CommandInterpreter_KeyBuffer_CtrlW()
1270 static void Test_CommandInterpreter_CommandHistory()
1332 DummyCommand2(
int& valueRef)
1333 :
Command(
"dummycommand",
"[args]")
1342 bool Execute(
GXemul& gxemul,
const vector<string>& arguments)
1350 return "A dummy command used for unit testing.";
1355 return "This is just a dummy command used for unit testing.";
1369 DummyCommand3(
int& valueRef)
1370 :
Command(
"dummycmd",
"[args]")
1379 bool Execute(
GXemul& gxemul,
const vector<string>& arguments)
1387 return "A dummy command used for unit testing.";
1392 return "This is just a dummy command used for unit testing.";
1399 static void Test_CommandInterpreter_AddCommand()
1411 " with the same name",
1421 static void Test_CommandInterpreter_TabCompletion_EmptyLine()
1431 static void Test_CommandInterpreter_TabCompletion_FullWord()
1458 " the tab-completed word",
1462 static void Test_CommandInterpreter_TabCompletion_SpacesFirstOnLine()
1481 static void Test_CommandInterpreter_TabCompletion_Partial()
1504 static void Test_CommandInterpreter_TabCompletion_C()
1521 static void Test_CommandInterpreter_TabCompletion_OnlyCommandAsFirstWord()
1549 static void Test_CommandInterpreter_TabCompletion_ComponentName()
1568 static void Test_CommandInterpreter_TabCompletion_ComponentNameAlreadyComplete()
1588 static void Test_CommandInterpreter_TabCompletion_ComponentNameMultiple()
1601 UnitTest::Assert(
"there are both cpu0 and cpu1, so don't expand all the way",
1607 static void Test_CommandInterpreter_TabCompletion_ComponentNameMultipleParents()
1626 static void Test_CommandInterpreter_TabCompletion_ComponentNameNonexist()
1646 static void Test_CommandInterpreter_TabCompletion_ComponentNameAsArgument()
1678 static void Test_CommandInterpreter_TabCompletion_CWithComponents()
1697 static void Test_CommandInterpreter_TabCompletion_roWithComponents()
1717 static void Test_CommandInterpreter_TabCompletion_ComponentMethods_Empty()
1733 static void Test_CommandInterpreter_TabCompletion_ComponentMethods()
1750 static void Test_CommandInterpreter_TabCompletion_ComponentMethods_Middle()
1775 static void Test_CommandInterpreter_TabCompletion_ComponentMethods_Arg()
1802 static void Test_CommandInterpreter_TabCompletion_ComponentVariables()
1816 UnitTest::Assert(
"tab completion should have caused expansion cpu -> cpu0",
1820 static void Test_CommandInterpreter_TabCompletion_ComponentVariables_Max()
1836 UnitTest::Assert(
"tab completion should have caused expansion ram -> ram0",
1840 static void Test_CommandInterpreter_TabCompletion_ComponentVariables_Max2()
1860 UnitTest::Assert(
"tab completion should have caused expansion ram -> ram0",
1868 static void Test_CommandInterpreter_NonExistingCommand()
1874 ci.
RunCommand(
"nonexistingcommand") ==
false);
1877 static void Test_CommandInterpreter_SimpleCommand()
1889 static void Test_CommandInterpreter_SimpleCommand_NoArgsAllowed()
1898 " fail when attempt is made to execute it with arguments",
1902 static void Test_CommandInterpreter_ComponentMethods()
1919 ci.
RunCommand(
"root.machine0.mainbus0.cpu") ==
true);
1921 ci.
RunCommand(
"root.machine0.mainbus0.cpu0") ==
true);
1923 ci.
RunCommand(
"root.machine0.mainbus0.cpu.u") ==
true);
1925 ci.
RunCommand(
"root.machine0.mainbus0.cpu0.unassemble") ==
true);
1928 static void Test_CommandInterpreter_ComponentVariables_NoArgs()
1941 ci.
RunCommand(
"root.machine0.mainbus0.cpu0.pau") ==
true);
1944 static void Test_CommandInterpreter_ComponentVariables_Ambiguous()
1952 UnitTest::Assert(
"cpu.f should not work, there should be multiple matches",
1956 static void Test_CommandInterpreter_ComponentVariables_PartialIsOk()
1974 UNITTEST(Test_CommandInterpreter_AddKey_ReturnValue);
1975 UNITTEST(Test_CommandInterpreter_KeyBuffer);
1976 UNITTEST(Test_CommandInterpreter_KeyBuffer_CursorMovement);
1977 UNITTEST(Test_CommandInterpreter_KeyBuffer_CtrlK);
1978 UNITTEST(Test_CommandInterpreter_KeyBuffer_CtrlW);
1981 UNITTEST(Test_CommandInterpreter_CommandHistory);
1984 UNITTEST(Test_CommandInterpreter_AddCommand);
1987 UNITTEST(Test_CommandInterpreter_TabCompletion_EmptyLine);
1988 UNITTEST(Test_CommandInterpreter_TabCompletion_FullWord);
1989 UNITTEST(Test_CommandInterpreter_TabCompletion_SpacesFirstOnLine);
1990 UNITTEST(Test_CommandInterpreter_TabCompletion_Partial);
1991 UNITTEST(Test_CommandInterpreter_TabCompletion_C);
1992 UNITTEST(Test_CommandInterpreter_TabCompletion_OnlyCommandAsFirstWord);
1993 UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentName);
1994 UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentNameAlreadyComplete);
1995 UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentNameMultiple);
1996 UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentNameMultipleParents);
1997 UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentNameNonexist);
1998 UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentNameAsArgument);
1999 UNITTEST(Test_CommandInterpreter_TabCompletion_CWithComponents);
2000 UNITTEST(Test_CommandInterpreter_TabCompletion_roWithComponents);
2001 UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentMethods_Empty);
2002 UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentMethods);
2003 UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentMethods_Middle);
2004 UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentMethods_Arg);
2005 UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentVariables);
2006 UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentVariables_Max);
2007 UNITTEST(Test_CommandInterpreter_TabCompletion_ComponentVariables_Max2);
2010 UNITTEST(Test_CommandInterpreter_NonExistingCommand);
2011 UNITTEST(Test_CommandInterpreter_SimpleCommand);
2012 UNITTEST(Test_CommandInterpreter_SimpleCommand_NoArgsAllowed);
2013 UNITTEST(Test_CommandInterpreter_ComponentMethods);
2014 UNITTEST(Test_CommandInterpreter_ComponentVariables_NoArgs);
2015 UNITTEST(Test_CommandInterpreter_ComponentVariables_Ambiguous);
2016 UNITTEST(Test_CommandInterpreter_ComponentVariables_PartialIsOk);