Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 5245 was 5245, checked in by bensch, 19 years ago

orxonox/trunk: autoCompletion now gives a very nice output

File size: 11.0 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: ...
13   co-programmer: ...
14*/
15
16//#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_
17
18#include "shell_completion.h"
19
20#include "shell_input.h"
21#include "shell_command.h"
22
23#include "substring.h"
24#include "base_object.h"
25#include "class_list.h"
26#include "list.h"
27#include "debug.h"
28
29#include "stdlibincl.h"
30
31using namespace std;
32
33/**
34 * standard constructor
35 * @todo this constructor is not jet implemented - do it
36*/
37ShellCompletion::ShellCompletion(ShellInput* input)
38{
39  this->completionList = NULL;
40  this->input = input;
41}
42
43
44/**
45 * standard deconstructor
46*/
47ShellCompletion::~ShellCompletion ()
48{
49  // delete what has to be deleted here
50  if (this->completionList)
51  {
52    this->emptyCompletionList();
53    delete this->completionList;
54  }
55}
56
57
58
59/**
60 * autocompletes the Shell's inputLine
61 * @returns true, if a result was found, false otherwise
62 */
63bool ShellCompletion::autoComplete(ShellInput* input)
64{
65  const char* completionLine;      //< the inputLine we complete.
66
67  long classID;                    //< the classID retrieved from the Class.
68  tList<BaseObject>* objectList;   //< the list of Objects stored in classID
69  bool emptyComplete = false;      //< if the completion input is empty string. e.g ""
70  long completeType = SHELLC_NONE; //< the Type we'd like to complete.
71  const char* completeString;      //< the string to complete.
72
73
74  PRINTF(5)("AutoComplete on input\n");
75  this->emptyCompletionList();
76
77  if (input != NULL)
78    this->input = input;
79  if (this->input == NULL)
80  {
81    PRINTF(2)("No ShellInput supplied\n");
82    return false;
83  }
84
85  // Check if we are in a input. eg. the supplied string "class " and now we complete either function or object
86  if (this->input->getInput() != NULL &&
87      strrchr(this->input->getInput(), ' ') >= this->input->getInput() + strlen(this->input->getInput())-1)
88  {
89    emptyComplete = true;
90  }
91
92  // CREATE INPUTS
93  if (this->input->getInput() == NULL)
94    completionLine = "";
95  else
96    completionLine = this->input->getInput() + strspn(this->input->getInput(), " \t\n");
97  SubString inputSplits(completionLine, true);
98
99  // What String will be completed
100  if (emptyComplete == true)
101    completeString = "";
102  else
103    completeString = inputSplits.getString(inputSplits.getCount()-1);
104
105  // CLASS COMPLETION
106  if (inputSplits.getCount() == 0)
107  {
108    completeType |= SHELLC_CLASS;
109    completeType |= SHELLC_ALIAS;
110
111  }
112  else if (inputSplits.getCount() == 1 && emptyComplete == false)
113  {
114    completeType |= SHELLC_CLASS;
115    completeType |= SHELLC_ALIAS;
116  }
117
118  // OBJECT/FUNCTION COMPLETIONS
119  else if ((inputSplits.getCount() == 1 && emptyComplete == true) ||
120            (inputSplits.getCount() == 2 && emptyComplete == false))
121  {
122    classID = ClassList::StringToID(inputSplits.getString(0));
123    objectList = ClassList::getList(classID);
124    if (classID == CL_NULL)
125      return false;
126    else
127    {
128      if (objectList != NULL && objectList->getSize() == 1)
129        completeType |= SHELLC_FUNCTION;
130      completeType |= SHELLC_OBJECT;
131    }
132  }
133  else if ((inputSplits.getCount() == 2 && emptyComplete == true) ||
134            (inputSplits.getCount() == 3 && emptyComplete == false))
135  {
136    classID = ClassList::StringToID(inputSplits.getString(0));
137    if (classID == CL_NULL)
138      return false;
139    else
140     completeType |= SHELLC_FUNCTION;
141  }
142
143  if (completeType & SHELLC_CLASS)
144    this->objectComplete(completeString, CL_SHELL_COMMAND_CLASS);
145  if (completeType & SHELLC_OBJECT)
146    this->objectComplete(completeString, classID);
147  if (completeType & SHELLC_FUNCTION)
148    this->functionComplete(completeString, classID);
149  if (completeType & SHELLC_ALIAS)
150    this->aliasComplete(completeString);
151
152
153  this->generalComplete(completeString);
154  return true;
155}
156
157/**
158 * autocompletes a className
159 * @param classBegin the Beginning of a String to autoComplete
160 * @return true on success, false otherwise
161 */
162bool ShellCompletion::classComplete(const char* classBegin)
163{
164  if (unlikely(classBegin == NULL))
165    return false;
166  const tList<const char>* clList = ClassList::getClassList();
167  if (clList != NULL)
168  {
169    if (!this->addToCompleteList(clList, classBegin, SHELLC_CLASS))
170      return false;
171  }
172  else
173    return false;
174  return true;
175}
176
177/**
178 * autocompletes an ObjectName
179 * @param objectBegin the beginning string of a Object
180 * @param classID the ID of the Class to search for.
181 * @return true on success, false otherwise
182 */
183bool ShellCompletion::objectComplete(const char* objectBegin, long classID)
184{
185  if (unlikely(objectBegin == NULL))
186    return false;
187  const tList<BaseObject>* boList = ClassList::getList(classID);
188  if (boList != NULL)
189  {
190    SHELLC_TYPE type = SHELLC_OBJECT;
191    if (classID == CL_SHELL_COMMAND_CLASS)
192      type = SHELLC_CLASS;
193    if (!this->addToCompleteList(boList, objectBegin, type))
194      return false;
195  }
196  else
197    return false;
198  return true;
199}
200
201/**
202 * completes a Function
203 * @param functionBegin the beginning of the function String
204 * @param classID the class' ID to complete the function of
205 */
206bool ShellCompletion::functionComplete(const char* functionBegin, long classID)
207{
208  if (unlikely(functionBegin == NULL))
209    return false;
210  tList<const char> fktList;
211  ShellCommandClass::getCommandListOfClass(ClassList::IDToString(classID), &fktList);
212  //printf("%s\n", boList->firstElement()->getName());
213  if (!this->addToCompleteList(&fktList, functionBegin, SHELLC_FUNCTION))
214    return false;
215  return true;
216}
217
218/**
219 * completes an Alias
220 * @param aliasBegin the beginning of the Alias-String to complete
221 * @returns true on succes, false if something went wrong
222 */
223bool ShellCompletion::aliasComplete(const char* aliasBegin)
224{
225  if (unlikely(aliasBegin == NULL))
226    return false;
227  tList<const char> aliasList;
228  ShellCommandClass::getCommandListOfAlias(&aliasList);
229  //printf("%s\n", boList->firstElement()->getName());
230  if (!this->addToCompleteList(&aliasList, aliasBegin, SHELLC_ALIAS))
231    return false;
232  return true;
233}
234
235
236/**
237 * completes the inputline on grounds of an inputList
238 * @param begin the String to search in the inputList, and to extend with it.
239 * @param displayAs how to display the found value to the user, printf-style, !!with only one %s!! ex.: "::%s::"
240 * @param addBack what should be added at the end of the completion
241 * @param addFront what should be added to the front of one finished completion
242 * @return true if ok, false otherwise
243 */
244bool ShellCompletion::generalComplete(const char* begin, const char* displayAs, const char* addBack, const char* addFront)
245{
246  if (completionList == NULL || this->input == NULL )
247    return false;
248  if (completionList->getSize() == 0)
249    return false;
250
251  ShellC_Element* addElem = completionList->firstElement();
252  const char* addString = addElem->name;
253  unsigned int addLength = 0;
254  unsigned int inputLenght = strlen(begin);
255
256  // Determin the longest Match
257  if (addString != NULL)
258    addLength = strlen(addString);
259  tIterator<ShellC_Element>* charIterator = completionList->getIterator();
260  ShellC_Element* charElem = charIterator->firstElement();
261  SHELLC_TYPE changeType = SHELLC_NONE;
262  while (charElem != NULL)
263  {
264    if (charElem->type != changeType)
265    {
266      if (changeType != SHELLC_NONE)
267        PRINT(0)("\n");
268      PRINT(0)("%s: ", ShellCompletion::typeToString(charElem->type));
269      changeType = charElem->type;
270    }
271    PRINTF(0)("%s ", charElem->name);
272    for (unsigned int i = inputLenght; i < addLength; i++)
273      if (addString[i] != charElem->name[i])
274      {
275       addLength = i;
276//       break;
277      }
278    charElem = charIterator->nextElement();
279  }
280  delete charIterator;
281  PRINT(0)("\n");
282
283  if (addLength >= inputLenght)
284  {
285    char* adder = new char[addLength+1];
286    strncpy(adder, addString, addLength);
287    adder[addLength] = '\0';
288
289    if (this->input)
290    {
291     this->input->removeCharacters(inputLenght);
292     this->input->addCharacters(adder);
293
294      if (completionList->getSize() == 1)
295      {
296        if ( addBack != NULL )
297         this->input->addCharacters(addBack);
298        this->input->addCharacter(' ');
299      }
300     delete[] adder;
301    }
302  }
303  return true;
304}
305
306/**
307 * searches for classes, which beginn with completionBegin
308 * @param inputList the List to parse through
309 * @param completionBegin the beginning string
310 * !! The strings MUST NOT be deleted !!
311 */
312bool ShellCompletion::addToCompleteList(const tList<const char>* inputList, const char* completionBegin, SHELLC_TYPE type)
313{
314  if (inputList == NULL || completionBegin == NULL)
315    return false;
316  unsigned int searchLength = strlen(completionBegin);
317
318  tIterator<const char>* iterator = inputList->getIterator();
319  const char* enumString = iterator->firstElement();
320  while (enumString != NULL)
321  {
322    if (strlen(enumString) >= searchLength &&
323        !strncasecmp(enumString, completionBegin, searchLength))
324    {
325      printf("%s\n", enumString);
326      ShellC_Element* newElem = new ShellC_Element;
327      newElem->name = enumString;
328      newElem->type = type;
329      this->completionList->add(newElem);
330    }
331    enumString = iterator->nextElement();
332  }
333  delete iterator;
334
335  return true;
336}
337
338/**
339 * searches for classes, which beginn with completionBegin
340 * @param inputList the List to parse through
341 * @param completionBegin the beginning string
342 * !! The strings MUST NOT be deleted !!
343 */
344bool ShellCompletion::addToCompleteList(const tList<BaseObject>* inputList, const char* completionBegin, SHELLC_TYPE type)
345{
346  if (inputList == NULL || completionBegin == NULL)
347    return false;
348  unsigned int searchLength = strlen(completionBegin);
349
350  tIterator<BaseObject>* iterator = inputList->getIterator();
351  BaseObject* enumBO = iterator->firstElement();
352  while (enumBO != NULL)
353  {
354    if (enumBO->getName() != NULL &&
355        strlen(enumBO->getName()) >= searchLength &&
356        !strncasecmp(enumBO->getName(), completionBegin, searchLength))
357    {
358      ShellC_Element* newElem = new ShellC_Element;
359      newElem->name = enumBO->getName();
360      newElem->type = type;
361      this->completionList->add(newElem);
362    }
363    enumBO = iterator->nextElement();
364  }
365  delete iterator;
366
367  return true;
368}
369
370/**
371 * deletes the Completion List.
372 *
373 * This is done at the beginning of each completion-run
374 */
375void ShellCompletion::emptyCompletionList()
376{
377  if (this->completionList != NULL)
378  {
379    tIterator<ShellC_Element>* elemIT = this->completionList->getIterator();
380    ShellC_Element* elem = elemIT->firstElement();
381    while (elem != NULL)
382    {
383      delete elem;
384      elem = elemIT->nextElement();
385    }
386    delete this->completionList;
387  }
388  this->completionList = new tList<ShellC_Element>;
389}
390
391const char* ShellCompletion::typeToString(SHELLC_TYPE type)
392{
393  switch (type)
394  {
395    default:// SHELLC_NONE
396      return "error";
397    case  SHELLC_CLASS:
398      return "class";
399    case SHELLC_OBJECT:
400      return "object";
401    case SHELLC_FUNCTION:
402      return "function";
403    case SHELLC_ALIAS:
404      return "alias";
405  }
406}
Note: See TracBrowser for help on using the repository browser.