Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/shell/shell_completion.cc @ 7371

Last change on this file since 7371 was 7371, checked in by bensch, 18 years ago

orxonox/trunk: better completion-algos

File size: 9.5 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Benjamin Grauer
13   co-programmer: ...
14*/
15
16//#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_
17
18#include "shell_completion.h"
19#include "shell_command_class.h"
20
21#include "shell_input.h"
22#include "shell_command.h"
23
24#include "substring.h"
25#include "base_object.h"
26#include "class_list.h"
27#include "debug.h"
28
29#include "stdlibincl.h"
30
31using namespace std;
32
33/**
34 * @brief standard constructor
35 */
36ShellCompletion::ShellCompletion()
37{ }
38
39
40/**
41 * @brief standard deconstructor
42 */
43ShellCompletion::~ShellCompletion ()
44{ }
45
46
47
48/**
49 * @brief autocompletes the Shell's inputLine
50 * @param input the input to complete.
51 * @returns true, if a result was found, false otherwise
52 */
53bool ShellCompletion::autoComplete(std::string& input)
54{
55  const char* completionLine;           //< the inputLine we complete.
56
57  long classID;                         //< the classID retrieved from the Class.
58  const std::list<BaseObject*>* objectList;   //< the list of Objects stored in classID
59  bool emptyComplete = false;           //< if the completion input is empty string. e.g ""
60  long completeType = SHELLC_NONE;      //< the Type we'd like to complete.
61  std::string completeString;           //< the string to complete.
62
63
64  PRINTF(5)("AutoComplete on input\n");
65  this->clearCompletionList();
66
67  // Check if we are in a input. eg. the supplied string "class " and now we complete either function or object
68  if (input[input.size()-1] == ' ')
69    emptyComplete = true;
70
71  // CREATE INPUTS
72  SubString inputSplits(input, SubString::WhiteSpacesWithComma);
73
74  // What String will be completed
75  if (emptyComplete == true)
76    completeString = "";
77  else
78    completeString = inputSplits.getString(inputSplits.size()-1);
79
80  // CLASS COMPLETION
81  if (inputSplits.size() == 0)
82  {
83    completeType |= SHELLC_CLASS;
84    completeType |= SHELLC_ALIAS;
85  }
86  else if (inputSplits.size() == 1 && emptyComplete == false)
87  {
88    completeType |= SHELLC_CLASS;
89    completeType |= SHELLC_ALIAS;
90  }
91
92  // OBJECT/FUNCTION COMPLETIONS
93  else if ((inputSplits.size() == 1 && emptyComplete == true) ||
94            (inputSplits.size() == 2 && emptyComplete == false))
95  {
96    classID = ClassList::StringToID(inputSplits.getString(0));
97    objectList = ClassList::getList((ClassID)classID);
98    if (classID != CL_NULL)
99      completeType |= SHELLC_OBJECT;
100    //if (objectList != NULL && objectList->getSize() == 1)
101      completeType |= SHELLC_FUNCTION;
102  }
103  else if ((inputSplits.size() == 2 && emptyComplete == true) ||
104            (inputSplits.size() == 3 && emptyComplete == false))
105  {
106    classID = ClassList::StringToID(inputSplits.getString(0));
107    if (classID == CL_NULL)
108      return false;
109    else
110     completeType |= SHELLC_FUNCTION;
111  }
112
113  if (completeType & SHELLC_CLASS)
114    this->objectComplete(completeString, CL_SHELL_COMMAND_CLASS);
115  if (completeType & SHELLC_OBJECT)
116    this->objectComplete(completeString, classID);
117  if (completeType & SHELLC_FUNCTION)
118    this->functionComplete(completeString, inputSplits.getString(0));
119  if (completeType & SHELLC_ALIAS)
120    this->aliasComplete(completeString);
121
122
123  this->generalComplete(input, completeString);
124  return true;
125}
126
127/**
128 * @brief autocompletes a className
129 * @param classBegin the Beginning of a String to autoComplete
130 * @return true on success, false otherwise
131 */
132bool ShellCompletion::classComplete(const std::string& classBegin)
133{
134  const std::list<std::string>* clList = ClassList::getClassNames();
135  if (clList != NULL)
136  {
137    if (!this->addToCompleteList(*clList, classBegin, SHELLC_CLASS))
138      return false;
139  }
140  else
141    return false;
142  return true;
143}
144
145/**
146 * @brief autocompletes an ObjectName
147 * @param objectBegin the beginning string of a Object
148 * @param classID the ID of the Class to search for.
149 * @return true on success, false otherwise
150 */
151bool ShellCompletion::objectComplete(const std::string& objectBegin, long classID)
152{
153  const std::list<BaseObject*>* boList = ClassList::getList((ClassID)classID);
154  if (boList != NULL)
155  {
156    SHELLC_TYPE type = SHELLC_OBJECT;
157    if (classID == CL_SHELL_COMMAND_CLASS)
158      type = SHELLC_CLASS;
159    if (!this->addToCompleteList(*boList, objectBegin, type))
160      return false;
161  }
162  else
163    return false;
164  return true;
165}
166
167/**
168 * @brief completes a Function
169 * @param functionBegin the beginning of the function String
170 * @param classID the class' ID to complete the function of
171 */
172bool ShellCompletion::functionComplete(const std::string& functionBegin, const std::string& className)
173{
174  std::list<std::string> fktList;
175  ShellCommandClass::getCommandListOfClass(className, &fktList);
176  //printf("%s\n", boList->firstElement()->getName());
177  if (!this->addToCompleteList(fktList, functionBegin, SHELLC_FUNCTION))
178    return false;
179  return true;
180}
181
182/**
183 * @brief completes an Alias
184 * @param aliasBegin the beginning of the Alias-String to complete
185 * @returns true on succes, false if something went wrong
186 */
187bool ShellCompletion::aliasComplete(const std::string& aliasBegin)
188{
189  std::list<std::string> aliasList;
190  ShellCommandClass::getCommandListOfAlias(&aliasList);
191  //printf("%s\n", boList->firstElement()->getName());
192  if (!this->addToCompleteList(aliasList, aliasBegin, SHELLC_ALIAS))
193    return false;
194  return true;
195}
196
197
198/**
199 * @brief completes the inputline on grounds of an inputList
200 * @param input the Input to complete.
201 * @param begin the String to search in the inputList, and to extend with it.
202 * @param displayAs how to display the found value to the user, printf-style, !!with only one %s!! ex.: "::%s::"
203 * @param addBack what should be added at the end of the completion
204 * @param addFront what should be added to the front of one finished completion
205 * @return true if ok, false otherwise
206 */
207bool ShellCompletion::generalComplete(std::string& input,
208                                      const std::string& begin, const std::string& displayAs,
209                                      const std::string& addBack, const std::string& addFront)
210{
211  if (completionList.size() == 0)
212    return false;
213
214  ShellC_Element addElem = completionList.front();
215  const std::string& addString = addElem.name;
216  unsigned int addLength = 0;
217  unsigned int inputLenght = begin.size();
218
219  // Determin the longest Match
220  addLength = addString.size();
221
222  SHELLC_TYPE changeType = SHELLC_NONE;
223  list<ShellC_Element>::iterator charIT;
224  for (charIT = completionList.begin(); charIT != completionList.end(); charIT++)
225  {
226    if ((*charIT).type != changeType)
227    {
228      if (changeType != SHELLC_NONE)
229        PRINT(0)("\n");
230      PRINT(0)("%s: ", ShellCompletion::typeToString((*charIT).type));
231      changeType = (*charIT).type;
232    }
233    PRINTF(0)("%s ", (*charIT).name.c_str());
234    for (unsigned int i = inputLenght; i < addLength; i++)
235      if (addString[i] != (*charIT).name[i])
236      {
237       addLength = i;
238//       break;
239      }
240  }
241  PRINT(0)("\n");
242
243  if (addLength >= inputLenght)
244  {
245    std::string adder = addString;
246    adder.resize(addLength);
247
248    input.resize(input.size()-inputLenght);
249    input += adder;
250
251    if (completionList.size() == 1)
252    {
253      if ( addBack != "")
254       input += addBack;
255      input += ' ';
256    }
257  }
258  return true;
259}
260
261/**
262 * @brief searches for classes, which beginn with completionBegin
263 * @param inputList the List to parse through
264 * @param completionBegin the beginning string
265 * !! The strings MUST NOT be deleted !!
266 */
267bool ShellCompletion::addToCompleteList(const std::list<std::string>& inputList, const std::string& completionBegin, SHELLC_TYPE type)
268{
269  unsigned int searchLength = completionBegin.size();
270
271  std::list<std::string>::const_iterator string;
272  for (string = inputList.begin(); string != inputList.end(); string++)
273  {
274    if ((*string).size() >= searchLength &&
275          !nocaseCmp(*string, completionBegin, searchLength))
276    {
277      printf ("%s\n", (*string).c_str());
278      ShellC_Element newElem;
279      newElem.name = (*string);
280      newElem.type = type;
281      this->completionList.push_back(newElem);
282    }
283  }
284  return true;
285}
286
287/**
288 * @brief searches for classes, which beginn with completionBegin
289 * @param inputList the List to parse through
290 * @param completionBegin the beginning string
291 * !! The strings MUST NOT be deleted !!
292 */
293bool ShellCompletion::addToCompleteList(const std::list<BaseObject*>& inputList, const std::string& completionBegin, SHELLC_TYPE type)
294{
295  unsigned int searchLength = completionBegin.size();
296
297  std::list<BaseObject*>::const_iterator bo;
298  for(bo = inputList.begin(); bo != inputList.end(); bo++)
299  {
300    if ((*bo)->getName() != NULL &&
301        strlen((*bo)->getName()) >= searchLength &&
302          !nocaseCmp((*bo)->getName(), completionBegin, searchLength))
303    {
304      ShellC_Element newElem;
305      newElem.name = (*bo)->getName();
306      newElem.type = type;
307      this->completionList.push_back(newElem);
308    }
309  }
310
311  return true;
312}
313
314/**
315 * @brief deletes the Completion List.
316 *
317 * This is done at the beginning of each completion-run
318 */
319void ShellCompletion::clearCompletionList()
320{
321  this->completionList.clear();
322}
323
324const char* ShellCompletion::typeToString(SHELLC_TYPE type)
325{
326  switch (type)
327  {
328    default:// SHELLC_NONE
329      return "error";
330    case  SHELLC_CLASS:
331      return "class";
332    case SHELLC_OBJECT:
333      return "object";
334    case SHELLC_FUNCTION:
335      return "function";
336    case SHELLC_ALIAS:
337      return "alias";
338  }
339}
Note: See TracBrowser for help on using the repository browser.