source: trunk/src/scripttools/debugging/qscriptcompletiontask.cpp@ 561

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 10.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtSCriptTools module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qscriptcompletiontask_p.h"
43#include "qscriptcompletiontaskinterface_p_p.h"
44#include "qscriptdebuggerconsole_p.h"
45#include "qscriptdebuggerconsolecommand_p.h"
46#include "qscriptdebuggerconsolecommandmanager_p.h"
47#include "qscriptdebuggercommandschedulerjob_p.h"
48#include "qscriptdebuggercommandschedulerfrontend_p.h"
49#include "qscriptdebuggerjobschedulerinterface_p.h"
50#include "qscriptdebuggerresponse_p.h"
51
52#include "private/qobject_p.h"
53
54#include <QtCore/qset.h>
55#include <QtCore/qdebug.h>
56
57QT_BEGIN_NAMESPACE
58
59class QScriptCompletionTaskPrivate
60 : public QScriptCompletionTaskInterfacePrivate
61{
62 Q_DECLARE_PUBLIC(QScriptCompletionTask)
63public:
64 QScriptCompletionTaskPrivate();
65 ~QScriptCompletionTaskPrivate();
66
67 void completeScriptExpression();
68 void emitFinished();
69
70 QString contents;
71 int cursorPosition;
72 int frameIndex;
73 QScriptDebuggerCommandSchedulerInterface *commandScheduler;
74 QScriptDebuggerJobSchedulerInterface *jobScheduler;
75 QScriptDebuggerConsole *console;
76};
77
78QScriptCompletionTaskPrivate::QScriptCompletionTaskPrivate()
79 : cursorPosition(0), frameIndex(0), commandScheduler(0),
80 jobScheduler(0), console(0)
81{
82}
83
84QScriptCompletionTaskPrivate::~QScriptCompletionTaskPrivate()
85{
86}
87
88class QScriptCompleteExpressionJob : public QScriptDebuggerCommandSchedulerJob
89{
90public:
91 QScriptCompleteExpressionJob(int frameIndex, const QStringList &path,
92 QScriptCompletionTaskPrivate *task,
93 QScriptDebuggerCommandSchedulerInterface *scheduler)
94 : QScriptDebuggerCommandSchedulerJob(scheduler),
95 m_frameIndex(frameIndex), m_path(path), m_task(task)
96 {}
97
98 void start()
99 {
100 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
101 frontend.scheduleGetCompletions(m_frameIndex, m_path);
102 }
103 void handleResponse(const QScriptDebuggerResponse &response, int /*commandId*/)
104 {
105 m_task->results = response.result().toStringList();
106 m_task->emitFinished();
107 finish();
108 }
109
110private:
111 int m_frameIndex;
112 QStringList m_path;
113 QScriptCompletionTaskPrivate *m_task;
114};
115
116namespace {
117
118static bool isIdentChar(const QChar &ch)
119{
120 static QChar underscore = QLatin1Char('_');
121 return ch.isLetter() || (ch == underscore);
122}
123
124static bool isPrefixOf(const QString &prefix, const QString &what)
125{
126 return ((what.length() > prefix.length())
127 && what.startsWith(prefix));
128}
129
130} // namespace
131
132class QScriptCompleteScriptsJob : public QScriptDebuggerCommandSchedulerJob
133{
134public:
135 QScriptCompleteScriptsJob(const QString &prefix, QScriptCompletionTaskPrivate *task,
136 QScriptDebuggerCommandSchedulerInterface *scheduler)
137 : QScriptDebuggerCommandSchedulerJob(scheduler),
138 m_prefix(prefix), m_task(task)
139 {}
140
141 void start()
142 {
143 QScriptDebuggerCommandSchedulerFrontend frontend(commandScheduler(), this);
144 frontend.scheduleGetScripts();
145 }
146 void handleResponse(const QScriptDebuggerResponse &response, int /*commandId*/)
147 {
148 QScriptScriptMap scripts = response.resultAsScripts();
149 QScriptScriptMap::const_iterator it;
150 for (it = scripts.constBegin(); it != scripts.constEnd(); ++it) {
151 QString fileName = it.value().fileName();
152 if (isPrefixOf(m_prefix, fileName))
153 m_task->results.append(fileName);
154 }
155 m_task->emitFinished();
156 finish();
157 }
158private:
159 QString m_prefix;
160 QScriptCompletionTaskPrivate *m_task;
161};
162
163void QScriptCompletionTaskPrivate::completeScriptExpression()
164{
165 int pos = cursorPosition;
166 if ((pos > 0) && contents.at(pos-1).isNumber()) {
167 // completion of numbers is pointless
168 emitFinished();
169 return;
170 }
171
172 while ((pos > 0) && isIdentChar(contents.at(pos-1)))
173 --pos;
174 int pos2 = cursorPosition - 1;
175 while ((pos2 < contents.size()-1) && isIdentChar(contents.at(pos2+1)))
176 ++pos2;
177 QString ident = contents.mid(pos, pos2 - pos + 1);
178 position = pos;
179
180 QStringList path;
181 path.append(ident);
182 while ((pos > 0) && (contents.at(pos-1) == QLatin1Char('.'))) {
183 --pos;
184 pos2 = pos;
185 while ((pos > 0) && isIdentChar(contents.at(pos-1)))
186 --pos;
187 path.prepend(contents.mid(pos, pos2 - pos));
188 }
189
190 length = path.last().length();
191 type = QScriptCompletionTask::ScriptIdentifierCompletion;
192
193 QScriptDebuggerJob *job = new QScriptCompleteExpressionJob(frameIndex, path, this, commandScheduler);
194 jobScheduler->scheduleJob(job);
195}
196
197void QScriptCompletionTaskPrivate::emitFinished()
198{
199 emit q_func()->finished();
200}
201
202QScriptCompletionTask::QScriptCompletionTask(
203 const QString &contents, int cursorPosition, int frameIndex,
204 QScriptDebuggerCommandSchedulerInterface *commandScheduler,
205 QScriptDebuggerJobSchedulerInterface *jobScheduler,
206 QScriptDebuggerConsole *console,
207 QObject *parent)
208 : QScriptCompletionTaskInterface(
209 *new QScriptCompletionTaskPrivate, parent)
210{
211 Q_D(QScriptCompletionTask);
212 d->contents = contents;
213 d->cursorPosition = cursorPosition;
214 if ((frameIndex == -1) && console)
215 d->frameIndex = console->currentFrameIndex();
216 else
217 d->frameIndex = frameIndex;
218 d->commandScheduler = commandScheduler;
219 d->jobScheduler = jobScheduler;
220 d->console = console;
221}
222
223QScriptCompletionTask::~QScriptCompletionTask()
224{
225}
226
227void QScriptCompletionTask::start()
228{
229 Q_D(QScriptCompletionTask);
230 d->type = NoCompletion;
231 // see if we're typing a command
232 // ### don't hardcode the command prefix
233 QRegExp cmdRx(QString::fromLatin1("^\\s*\\.([a-zA-Z]*)"));
234 int cmdIndex = cmdRx.indexIn(d->contents);
235 if ((cmdIndex != -1) && d->console) {
236 int len = cmdRx.matchedLength();
237 QString prefix = cmdRx.capturedTexts().at(1);
238 if ((d->cursorPosition >= cmdIndex) && (d->cursorPosition <= (cmdIndex+len))) {
239 // editing command --> get command completions
240 d->results = d->console->commandManager()->completions(prefix);
241 d->position = cmdRx.pos(1);
242 d->length = prefix.length();
243 d->type = CommandNameCompletion;
244 d->appendix = QString::fromLatin1(" ");
245 emit finished();
246 } else {
247 QScriptDebuggerConsoleCommand *cmd = d->console->commandManager()->findCommand(prefix);
248 if (!cmd) {
249 emit finished();
250 return;
251 }
252 // editing an argument
253 int argNum = 0;
254 QString arg;
255 int pos = cmdIndex + len;
256 while (pos < d->contents.size()) {
257 while ((pos < d->contents.size()) && d->contents.at(pos).isSpace())
258 ++pos;
259 if (pos < d->contents.size()) {
260 int pos2 = pos + 1;
261 while ((pos2 < d->contents.size()) && !d->contents.at(pos2).isSpace())
262 ++pos2;
263 if ((d->cursorPosition >= pos) && (d->cursorPosition <= pos2)) {
264 arg = d->contents.mid(pos, pos2 - pos);
265 break;
266 }
267 pos = pos2;
268 ++argNum;
269 }
270 }
271 QString argType = cmd->argumentTypes().value(argNum);
272 if (!argType.isEmpty()) {
273 if (argType == QLatin1String("command-or-group-name")) {
274 d->results = d->console->commandManager()->completions(arg);
275 } else if (argType == QLatin1String("script-filename")) {
276 d->position = pos;
277 d->length = arg.length();
278 d->type = CommandArgumentCompletion;
279 QScriptDebuggerJob *job = new QScriptCompleteScriptsJob(arg, d, d->commandScheduler);
280 d->jobScheduler->scheduleJob(job);
281 } else if (argType == QLatin1String("subcommand-name")) {
282 for (int i = 0; i < cmd->subCommands().size(); ++i) {
283 QString name = cmd->subCommands().at(i);
284 if (isPrefixOf(arg, name))
285 d->results.append(name);
286 }
287 qStableSort(d->results);
288 } else if (argType == QLatin1String("script")) {
289 d->completeScriptExpression();
290 } else {
291 emit finished();
292 }
293 if ((d->type == NoCompletion) && !d->results.isEmpty()) {
294 d->position = pos;
295 d->length = arg.length();
296 d->type = CommandArgumentCompletion;
297 emit finished();
298 }
299 }
300 }
301 } else {
302 // assume it's an eval expression
303 d->completeScriptExpression();
304 }
305}
306
307QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.