Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 11007 was 10624, checked in by landauf, 9 years ago

merged branch core7 back to trunk

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