Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/kicklib/src/libraries/core/command/ArgumentCompletionFunctions.cc @ 8066

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

added support for boost 1.46 and adjusted code to work with the 3rd version of boost::filesystem

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