Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7669 was 7401, checked in by landauf, 14 years ago

merged doc branch back to trunk

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