Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/command/ArgumentCompletionFunctions.cc @ 10018

Last change on this file since 10018 was 9667, checked in by landauf, 11 years ago

merged core6 back to trunk

  • Property svn:eol-style set to native
File size: 15.0 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file
31    @brief Implementation of all argument completion functions
32*/
33
34#include "ArgumentCompletionFunctions.h"
35
36#include <map>
37#include <boost/filesystem.hpp>
38
39#include "util/Convert.h"
40#include "util/StringUtils.h"
41#include "core/class/Identifier.h"
42#include "core/config/SettingsConfigFile.h"
43#include "core/config/ConfigValueContainer.h"
44#include "CommandExecutor.h"
45#include "ConsoleCommand.h"
46#include "TclThreadManager.h"
47
48// Differentiate Boost Filesystem v2 and v3
49#if (BOOST_FILESYSTEM_VERSION < 3)
50#  define BF_LEAF leaf
51#  define BF_GENERIC_STRING string
52#  define BF_DICTIONARY_ENTRY_NAME string
53#else
54#  define BF_LEAF path().filename().string
55#  define BF_GENERIC_STRING generic_string
56#  define BF_DICTIONARY_ENTRY_NAME path().string
57#endif
58
59namespace orxonox
60{
61    namespace autocompletion
62    {
63        /**
64            @brief Fallback implementation, returns an empty list.
65        */
66        ARGUMENT_COMPLETION_FUNCTION_IMPLEMENTATION(fallback)()
67        {
68            return ArgumentCompletionList();
69        }
70
71        namespace detail
72        {
73            /**
74                @brief Returns true if a group of console commands is visible (i.e. if at least one command in this group is visible).
75            */
76            bool groupIsVisible(const std::map<std::string, ConsoleCommand*>& group, bool bOnlyShowHidden)
77            {
78                for (std::map<std::string, ConsoleCommand*>::const_iterator it_command = group.begin(); it_command != group.end(); ++it_command)
79                    if (it_command->second->isActive() && it_command->second->hasAccess() && (!it_command->second->isHidden())^bOnlyShowHidden)
80                        return true;
81
82                return false;
83            }
84
85            /**
86                @brief Returns a list of all console command groups AND all console command shortcuts.
87                @param fragment The last argument
88                @param bOnlyShowHidden If true, only hidden groups and commands are returned
89            */
90            ArgumentCompletionList _groupsandcommands(const std::string& fragment, bool bOnlyShowHidden)
91            {
92                // note: this function returns only arguments that begin with "fragment", which wouldn't be necessary for the
93                //       auto-completion, but it's necessary to place the line-break "\n" between groups and commands
94                //       only if both groups AND commands are in the list.
95
96                ArgumentCompletionList groupList;
97                std::string fragmentLC = getLowercase(fragment);
98
99                // get all the groups that are visible (except the shortcut group "")
100                const std::map<std::string, std::map<std::string, ConsoleCommand*> >& commands = ConsoleCommand::getCommands();
101                for (std::map<std::string, std::map<std::string, ConsoleCommand*> >::const_iterator it_group = commands.begin(); it_group != commands.end(); ++it_group)
102                    if (groupIsVisible(it_group->second, bOnlyShowHidden) && it_group->first != "" && (fragmentLC == "" || getLowercase(it_group->first).find(fragmentLC) == 0))
103                        groupList.push_back(ArgumentCompletionListElement(it_group->first, getLowercase(it_group->first)));
104
105                // now add all shortcuts (in group "")
106                std::map<std::string, std::map<std::string, ConsoleCommand*> >::const_iterator it_group = commands.find("");
107                if (it_group != commands.end())
108                {
109                    // add a line-break if the list isn't empty
110                    if (!groupList.empty())
111                        groupList.push_back(ArgumentCompletionListElement("", "", "\n"));
112
113                    // add the shortcuts
114                    for (std::map<std::string, ConsoleCommand*>::const_iterator it_command = it_group->second.begin(); it_command != it_group->second.end(); ++it_command)
115                        if (it_command->second->isActive() && it_command->second->hasAccess() && (!it_command->second->isHidden())^bOnlyShowHidden && (fragmentLC == "" || getLowercase(it_command->first).find(fragmentLC) == 0))
116                            groupList.push_back(ArgumentCompletionListElement(it_command->first, getLowercase(it_command->first)));
117                }
118
119                // if no shortcut was added, remove the line-break again
120                if (!groupList.empty() && groupList.back().getDisplay() == "\n")
121                    groupList.pop_back();
122
123                return groupList;
124            }
125
126            /**
127                @brief Returns a list of all console commands in a given group.
128                @param fragment The last argument
129                @param group The group's name
130                @param bOnlyShowHidden If true, only hidden console commands are returned
131            */
132            ArgumentCompletionList _subcommands(const std::string& fragment, const std::string& group, bool bOnlyShowHidden)
133            {
134                ArgumentCompletionList commandList;
135
136                std::string groupLC = getLowercase(group);
137
138                // find the iterator of the given group
139                std::map<std::string, std::map<std::string, ConsoleCommand*> >::const_iterator it_group = ConsoleCommand::getCommands().begin();
140                for ( ; it_group != ConsoleCommand::getCommands().end(); ++it_group)
141                    if (getLowercase(it_group->first) == groupLC)
142                        break;
143
144                // add all commands in the group to the list
145                if (it_group != ConsoleCommand::getCommands().end())
146                {
147                    for (std::map<std::string, ConsoleCommand*>::const_iterator it_command = it_group->second.begin(); it_command != it_group->second.end(); ++it_command)
148                        if (it_command->second->isActive() && it_command->second->hasAccess() && (!it_command->second->isHidden())^bOnlyShowHidden)
149                            commandList.push_back(ArgumentCompletionListElement(it_command->first, getLowercase(it_command->first)));
150                }
151
152                return commandList;
153            }
154        }
155
156        /**
157            @brief Returns a list of all console command groups AND all console command shortcuts.
158        */
159        ARGUMENT_COMPLETION_FUNCTION_IMPLEMENTATION(groupsandcommands)(const std::string& fragment)
160        {
161            return detail::_groupsandcommands(fragment, false);
162        }
163
164        /**
165            @brief Returns a list of all console commands in a given group.
166        */
167        ARGUMENT_COMPLETION_FUNCTION_IMPLEMENTATION(subcommands)(const std::string& fragment, const std::string& group)
168        {
169            return detail::_subcommands(fragment, group, false);
170        }
171
172        /**
173            @brief Returns a list of commands and groups and also supports auto-completion of the arguments of these commands.
174
175            This is a multi-word function, because commands are composed of 1-2 words and additional arguments.
176        */
177        ARGUMENT_COMPLETION_FUNCTION_IMPLEMENTATION_MULTI(command)(const std::string& fragment)
178        {
179            CommandEvaluation evaluation = CommandExecutor::evaluate(fragment);
180            const std::string& hint = evaluation.hint();
181
182            if (evaluation.getPossibleArguments().size() > 0 && evaluation.getPossibleArgumentsSize() > 0)
183            {
184                return evaluation.getPossibleArguments();
185            }
186            else
187            {
188                ArgumentCompletionList list;
189                list.push_back(ArgumentCompletionListElement("", "", hint));
190                return list;
191            }
192        }
193
194        /**
195            @brief Returns a list of hidden commands and groups and also supports auto-completion of the arguments of these commands.
196
197            This is a multi-word function, because commands are composed of 1-2 words and additional arguments.
198
199            This function makes commands visible that would usually be hidden.
200        */
201        ARGUMENT_COMPLETION_FUNCTION_IMPLEMENTATION_MULTI(hiddencommand)(const std::string& fragment)
202        {
203            SubString tokens(fragment, " ", SubString::WhiteSpaces, false, '\\', true, '"', true, '{', '}', true, '\0');
204
205            if (tokens.size() == 0)
206                return detail::_groupsandcommands(fragment, true);
207
208            if (ConsoleCommand::getCommandLC(getLowercase(tokens[0])))
209                return ARGUMENT_COMPLETION_FUNCTION_CALL(command)(fragment);
210
211            if (tokens.size() == 1)
212            {
213                std::map<std::string, std::map<std::string, ConsoleCommand*> >::const_iterator it_group = ConsoleCommand::getCommands().find(tokens[0]);
214                if (it_group != ConsoleCommand::getCommands().end())
215                    return detail::_subcommands(fragment, tokens[0], true);
216                else
217                    return detail::_groupsandcommands(fragment, true);
218            }
219
220            if (ConsoleCommand::getCommandLC(getLowercase(tokens[0]), getLowercase(tokens[1])))
221                return ARGUMENT_COMPLETION_FUNCTION_CALL(command)(fragment);
222
223            return ArgumentCompletionList();
224        }
225
226        /**
227            @brief Returns possible files and directories and also supports files in arbitrary deeply nested subdirectories.
228
229            This function returns files and directories in the given path. This allows to
230            navigate iteratively through the file system. The first argument @a fragment
231            is used to get the current path.
232        */
233        ARGUMENT_COMPLETION_FUNCTION_IMPLEMENTATION(files)(const std::string& fragment)
234        {
235            ArgumentCompletionList dirlist;
236            ArgumentCompletionList filelist;
237
238            try
239            {
240                boost::filesystem::path input(fragment);
241                boost::filesystem::path startdirectory(input.branch_path());
242
243                if (!boost::filesystem::exists(startdirectory))
244                {
245                    startdirectory = ".";
246                }
247#ifdef ORXONOX_PLATFORM_WINDOWS
248                else
249                {
250                    const std::string& dir = startdirectory.BF_GENERIC_STRING();
251                    if (dir.size() > 0 && dir[dir.size() - 1] == ':')
252                        startdirectory = dir + '/';
253                }
254#endif
255
256                boost::filesystem::directory_iterator file(startdirectory);
257                boost::filesystem::directory_iterator end;
258
259                while (file != end)
260                {
261                    if (boost::filesystem::is_directory(*file))
262                        dirlist.push_back(ArgumentCompletionListElement(file->BF_DICTIONARY_ENTRY_NAME() + '/', getLowercase(file->BF_DICTIONARY_ENTRY_NAME()) + '/', file->BF_LEAF() + '/'));
263                    else
264                        filelist.push_back(ArgumentCompletionListElement(file->BF_DICTIONARY_ENTRY_NAME(), getLowercase(file->BF_DICTIONARY_ENTRY_NAME()), file->BF_LEAF()));
265                    ++file;
266                }
267            }
268            catch (...) {}
269
270            filelist.insert(filelist.begin(), dirlist.begin(), dirlist.end());
271            return filelist;
272        }
273
274        /**
275            @brief Returns the sections of the config file.
276        */
277        ARGUMENT_COMPLETION_FUNCTION_IMPLEMENTATION(settingssections)()
278        {
279            ArgumentCompletionList sectionList;
280
281            const std::set<std::string>& names = SettingsConfigFile::getInstance().getSectionNames();
282            for (std::set<std::string>::const_iterator it = names.begin(); it != names.end(); ++it)
283                sectionList.push_back(ArgumentCompletionListElement(*it, getLowercase(*it)));
284
285            return sectionList;
286        }
287
288        /**
289            @brief Returns the entries in a given section of the config file.
290        */
291        ARGUMENT_COMPLETION_FUNCTION_IMPLEMENTATION(settingsentries)(const std::string& fragment, const std::string& section)
292        {
293            ArgumentCompletionList entryList;
294            SettingsConfigFile& settings = SettingsConfigFile::getInstance();
295            const std::string& sectionLC = getLowercase(section);
296
297            SettingsConfigFile::ContainerMap::const_iterator upper = settings.getContainerUpperBound(sectionLC);
298            for (SettingsConfigFile::ContainerMap::const_iterator it = settings.getContainerLowerBound(sectionLC); it != upper; ++it)
299                entryList.push_back(ArgumentCompletionListElement(it->second.second->getName(), it->second.first));
300
301            return entryList;
302        }
303
304        /**
305            @brief Returns the current value of a given value in a given section of the config file.
306        */
307        ARGUMENT_COMPLETION_FUNCTION_IMPLEMENTATION(settingsvalue)(const std::string& fragment, const std::string& entry, const std::string& section)
308        {
309            ArgumentCompletionList oldValue;
310            SettingsConfigFile& settings = SettingsConfigFile::getInstance();
311            const std::string& sectionLC = getLowercase(section);
312            const std::string& entryLC = getLowercase(entry);
313
314            SettingsConfigFile::ContainerMap::const_iterator upper = settings.getContainerUpperBound(sectionLC);
315            for (SettingsConfigFile::ContainerMap::const_iterator it = settings.getContainerLowerBound(sectionLC); it != upper; ++it)
316            {
317                if (it->second.first == entryLC)
318                {
319                    const std::string& valuestring = it->second.second->toString();
320                    oldValue.push_back(ArgumentCompletionListElement(valuestring, getLowercase(valuestring), "Old value: " + valuestring));
321                }
322            }
323
324            return oldValue;
325        }
326
327        /**
328            @brief Returns a list of indexes of the available Tcl threads (see TclThreadManager).
329        */
330        ARGUMENT_COMPLETION_FUNCTION_IMPLEMENTATION(tclthreads)()
331        {
332            std::list<unsigned int> threadnumbers = TclThreadManager::getInstance().getThreadList();
333            ArgumentCompletionList threads;
334
335            for (std::list<unsigned int>::const_iterator it = threadnumbers.begin(); it != threadnumbers.end(); ++it)
336                threads.push_back(ArgumentCompletionListElement(multi_cast<std::string>(*it)));
337
338            return threads;
339        }
340    }
341}
Note: See TracBrowser for help on using the repository browser.