src/scripttools/debugging/qscriptdebuggerconsole.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtSCriptTools module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qscriptdebuggerconsole_p.h"
       
    43 #include "qscriptdebuggerconsolecommandjob_p.h"
       
    44 #include "qscriptdebuggerconsolecommandmanager_p.h"
       
    45 #include "qscriptdebuggerscriptedconsolecommand_p.h"
       
    46 #include "qscriptmessagehandlerinterface_p.h"
       
    47 
       
    48 #include <QtCore/qdir.h>
       
    49 #include <QtCore/qfileinfo.h>
       
    50 #include <QtCore/qstring.h>
       
    51 #include <QtCore/qstringlist.h>
       
    52 #include <QtCore/qdebug.h>
       
    53 #include <QtScript/qscriptengine.h>
       
    54 
       
    55 QT_BEGIN_NAMESPACE
       
    56 
       
    57 /*!
       
    58   \since 4.5
       
    59   \class QScriptDebuggerConsole
       
    60   \internal
       
    61 
       
    62   \brief The QScriptDebuggerConsole class provides the core functionality of a debugger console.
       
    63 */
       
    64 
       
    65 class QScriptDebuggerConsolePrivate
       
    66 {
       
    67     Q_DECLARE_PUBLIC(QScriptDebuggerConsole)
       
    68 public:
       
    69     QScriptDebuggerConsolePrivate(QScriptDebuggerConsole*);
       
    70     ~QScriptDebuggerConsolePrivate();
       
    71 
       
    72     void loadScriptedCommands(const QString &scriptsPath,
       
    73                               QScriptMessageHandlerInterface *messageHandler);
       
    74     QScriptDebuggerConsoleCommandJob *createJob(
       
    75         const QString &command,
       
    76         QScriptMessageHandlerInterface *messageHandler,
       
    77         QScriptDebuggerCommandSchedulerInterface *commandScheduler);
       
    78 
       
    79     QScriptDebuggerConsoleCommandManager *commandManager;
       
    80     QString commandPrefix;
       
    81     QString input;
       
    82     QStringList commandHistory;
       
    83     int currentFrameIndex;
       
    84     qint64 currentScriptId;
       
    85     int currentLineNumber;
       
    86     int evaluateAction;
       
    87     qint64 sessionId;
       
    88 
       
    89     QScriptDebuggerConsole *q_ptr;
       
    90 };
       
    91 
       
    92 QScriptDebuggerConsolePrivate::QScriptDebuggerConsolePrivate(QScriptDebuggerConsole* parent)
       
    93     : q_ptr(parent)
       
    94 {
       
    95     sessionId = 0;
       
    96     currentFrameIndex = 0;
       
    97     currentScriptId = -1;
       
    98     currentLineNumber = -1;
       
    99     evaluateAction = 0;
       
   100     commandPrefix = QLatin1String(".");
       
   101     commandManager = new QScriptDebuggerConsoleCommandManager();
       
   102 }
       
   103 
       
   104 QScriptDebuggerConsolePrivate::~QScriptDebuggerConsolePrivate()
       
   105 {
       
   106     delete commandManager;
       
   107 }
       
   108 
       
   109 /*!
       
   110   Loads command definitions from scripts located in the given \a scriptsPath.
       
   111 */
       
   112 void QScriptDebuggerConsolePrivate::loadScriptedCommands(
       
   113     const QString &scriptsPath,
       
   114     QScriptMessageHandlerInterface *messageHandler)
       
   115 {
       
   116     QDir dir(scriptsPath);
       
   117     QFileInfoList entries = dir.entryInfoList(QStringList()
       
   118                                               << QLatin1String("*.qs"));
       
   119     for (int i = 0; i < entries.size(); ++i) {
       
   120         const QFileInfo &fi = entries.at(i);
       
   121         QString fileName = fi.fileName();
       
   122         QFile file(scriptsPath + QLatin1Char('/') + fileName);
       
   123         if (!file.open(QIODevice::ReadOnly))
       
   124             continue;
       
   125         QTextStream stream(&file);
       
   126         QString program = stream.readAll();
       
   127         QScriptDebuggerScriptedConsoleCommand *command;
       
   128         command = QScriptDebuggerScriptedConsoleCommand::parse(
       
   129             program, fileName, messageHandler);
       
   130         if (!command)
       
   131             continue;
       
   132         commandManager->addCommand(command);
       
   133     }
       
   134 }
       
   135 
       
   136 
       
   137 /*!
       
   138   Creates a job that will execute the given debugger \a command.
       
   139   Returns the new job, or 0 if the command is undefined.
       
   140 */
       
   141 QScriptDebuggerConsoleCommandJob *QScriptDebuggerConsolePrivate::createJob(
       
   142     const QString &command, QScriptMessageHandlerInterface *messageHandler,
       
   143     QScriptDebuggerCommandSchedulerInterface *commandScheduler)
       
   144 {
       
   145     QString name;
       
   146     int i = command.indexOf(QLatin1Char(' '));
       
   147     if (i == -1) {
       
   148         name = command;
       
   149         i = name.size();
       
   150     } else {
       
   151         name = command.left(i);
       
   152     }
       
   153     if (name.isEmpty())
       
   154         return 0;
       
   155     QScriptDebuggerConsoleCommand *cmd = commandManager->findCommand(name);
       
   156     if (!cmd) {
       
   157         // try to auto-complete
       
   158         QStringList completions = commandManager->completions(name);
       
   159         if (!completions.isEmpty()) {
       
   160             if (completions.size() > 1) {
       
   161                 QString msg;
       
   162                 msg.append(QString::fromLatin1("Ambiguous command \"%0\": ")
       
   163                            .arg(name));
       
   164                 for (int j = 0; j < completions.size(); ++j) {
       
   165                     if (j > 0)
       
   166                         msg.append(QLatin1String(", "));
       
   167                     msg.append(completions.at(j));
       
   168                 }
       
   169                 msg.append(QLatin1Char('.'));
       
   170                 messageHandler->message(QtWarningMsg, msg);
       
   171                 return 0;
       
   172             }
       
   173             cmd = commandManager->findCommand(completions.at(0));
       
   174             Q_ASSERT(cmd != 0);
       
   175         }
       
   176         if (!cmd) {
       
   177             messageHandler->message(
       
   178                 QtWarningMsg,
       
   179                 QString::fromLatin1("Undefined command \"%0\". Try \"help\".")
       
   180                 .arg(name));
       
   181             return 0;
       
   182         }
       
   183     }
       
   184     QStringList args;
       
   185     QString tmp = command.mid(i+1);
       
   186     if (cmd->argumentTypes().contains(QString::fromLatin1("script"))) {
       
   187         if (!tmp.isEmpty())
       
   188             args.append(tmp);
       
   189     } else {
       
   190         args = tmp.split(QLatin1Char(' '), QString::SkipEmptyParts);
       
   191     }
       
   192     return cmd->createJob(args, q_func(), messageHandler, commandScheduler);
       
   193 }
       
   194 
       
   195 QScriptDebuggerConsole::QScriptDebuggerConsole()
       
   196     : d_ptr(new QScriptDebuggerConsolePrivate(this))
       
   197 {
       
   198 }
       
   199 
       
   200 QScriptDebuggerConsole::~QScriptDebuggerConsole()
       
   201 {
       
   202 }
       
   203 
       
   204 void QScriptDebuggerConsole::loadScriptedCommands(const QString &scriptsPath,
       
   205                                                   QScriptMessageHandlerInterface *messageHandler)
       
   206 {
       
   207     Q_D(QScriptDebuggerConsole);
       
   208     d->loadScriptedCommands(scriptsPath, messageHandler);
       
   209 }
       
   210 
       
   211 QScriptDebuggerConsoleCommandManager *QScriptDebuggerConsole::commandManager() const
       
   212 {
       
   213     Q_D(const QScriptDebuggerConsole);
       
   214     return d->commandManager;
       
   215 }
       
   216 
       
   217 bool QScriptDebuggerConsole::hasIncompleteInput() const
       
   218 {
       
   219     Q_D(const QScriptDebuggerConsole);
       
   220     return !d->input.isEmpty();
       
   221 }
       
   222 
       
   223 QString QScriptDebuggerConsole::incompleteInput() const
       
   224 {
       
   225     Q_D(const QScriptDebuggerConsole);
       
   226     return d->input;
       
   227 }
       
   228 
       
   229 void QScriptDebuggerConsole::setIncompleteInput(const QString &input)
       
   230 {
       
   231     Q_D(QScriptDebuggerConsole);
       
   232     d->input = input;
       
   233 }
       
   234 
       
   235 QString QScriptDebuggerConsole::commandPrefix() const
       
   236 {
       
   237     Q_D(const QScriptDebuggerConsole);
       
   238     return d->commandPrefix;
       
   239 }
       
   240 
       
   241 /*!
       
   242   Consumes the given line of \a input.  If the input starts with the
       
   243   command prefix, it is regarded as a debugger command; otherwise the
       
   244   input is evaluated as a plain script.
       
   245 */
       
   246 QScriptDebuggerConsoleCommandJob *QScriptDebuggerConsole::consumeInput(
       
   247     const QString &input, QScriptMessageHandlerInterface *messageHandler,
       
   248     QScriptDebuggerCommandSchedulerInterface *commandScheduler)
       
   249 {
       
   250     Q_D(QScriptDebuggerConsole);
       
   251     static const int maximumHistoryCount = 100;
       
   252     QString cmd;
       
   253     if (d->input.isEmpty() && input.isEmpty()) {
       
   254         if (d->commandHistory.isEmpty())
       
   255             return 0;
       
   256         cmd = d->commandHistory.first();
       
   257     } else {
       
   258         cmd = input;
       
   259     }
       
   260     if (d->input.isEmpty() && cmd.startsWith(d->commandPrefix)) {
       
   261         if (!input.isEmpty()) {
       
   262             d->commandHistory.prepend(cmd);
       
   263             if (d->commandHistory.size() > maximumHistoryCount)
       
   264                 d->commandHistory.removeLast();
       
   265         }
       
   266         cmd.remove(0, d->commandPrefix.length());
       
   267         return d->createJob(cmd, messageHandler, commandScheduler);
       
   268     }
       
   269     d->input += cmd;
       
   270     d->input += QLatin1Char('\n');
       
   271     QScriptSyntaxCheckResult check = QScriptEngine::checkSyntax(d->input);
       
   272     if (check.state() == QScriptSyntaxCheckResult::Intermediate)
       
   273         return false;
       
   274     d->input.chop(1); // remove the last \n
       
   275     cmd = QString();
       
   276     cmd.append(d->commandPrefix);
       
   277     cmd.append(QString::fromLatin1("eval "));
       
   278     cmd.append(d->input);
       
   279     d->commandHistory.prepend(cmd);
       
   280     if (d->commandHistory.size() > maximumHistoryCount)
       
   281         d->commandHistory.removeLast();
       
   282     d->input.clear();
       
   283     cmd.remove(0, d->commandPrefix.length());
       
   284     return d->createJob(cmd, messageHandler, commandScheduler);
       
   285 }
       
   286 
       
   287 int QScriptDebuggerConsole::currentFrameIndex() const
       
   288 {
       
   289     Q_D(const QScriptDebuggerConsole);
       
   290     return d->currentFrameIndex;
       
   291 }
       
   292 
       
   293 void QScriptDebuggerConsole::setCurrentFrameIndex(int index)
       
   294 {
       
   295     Q_D(QScriptDebuggerConsole);
       
   296     d->currentFrameIndex = index;
       
   297 }
       
   298 
       
   299 qint64 QScriptDebuggerConsole::currentScriptId() const
       
   300 {
       
   301     Q_D(const QScriptDebuggerConsole);
       
   302     return d->currentScriptId;
       
   303 }
       
   304 
       
   305 void QScriptDebuggerConsole::setCurrentScriptId(qint64 id)
       
   306 {
       
   307     Q_D(QScriptDebuggerConsole);
       
   308     d->currentScriptId = id;
       
   309 }
       
   310 
       
   311 int QScriptDebuggerConsole::currentLineNumber() const
       
   312 {
       
   313     Q_D(const QScriptDebuggerConsole);
       
   314     return d->currentLineNumber;
       
   315 }
       
   316 
       
   317 void QScriptDebuggerConsole::setCurrentLineNumber(int lineNumber)
       
   318 {
       
   319     Q_D(QScriptDebuggerConsole);
       
   320     d->currentLineNumber = lineNumber;
       
   321 }
       
   322 
       
   323 int QScriptDebuggerConsole::evaluateAction() const
       
   324 {
       
   325     Q_D(const QScriptDebuggerConsole);
       
   326     return d->evaluateAction;
       
   327 }
       
   328 
       
   329 void QScriptDebuggerConsole::setEvaluateAction(int action)
       
   330 {
       
   331     Q_D(QScriptDebuggerConsole);
       
   332     d->evaluateAction = action;
       
   333 }
       
   334 
       
   335 qint64 QScriptDebuggerConsole::sessionId() const
       
   336 {
       
   337     Q_D(const QScriptDebuggerConsole);
       
   338     return d->sessionId;
       
   339 }
       
   340 
       
   341 void QScriptDebuggerConsole::bumpSessionId()
       
   342 {
       
   343     Q_D(QScriptDebuggerConsole);
       
   344     ++d->sessionId;
       
   345 }
       
   346 
       
   347 void QScriptDebuggerConsole::showDebuggerInfoMessage(
       
   348     QScriptMessageHandlerInterface *messageHandler)
       
   349 {
       
   350     messageHandler->message(
       
   351         QtDebugMsg,
       
   352         QString::fromLatin1(
       
   353             "Welcome to the Qt Script debugger.\n"
       
   354             "Debugger commands start with a . (period).\n"
       
   355             "Any other input will be evaluated by the script interpreter.\n"
       
   356             "Type \".help\" for help.\n"));
       
   357 }
       
   358 
       
   359 /*!
       
   360   \reimp
       
   361 */
       
   362 int QScriptDebuggerConsole::historyCount() const
       
   363 {
       
   364     Q_D(const QScriptDebuggerConsole);
       
   365     return d->commandHistory.size();
       
   366 }
       
   367 
       
   368 /*!
       
   369   \reimp
       
   370 */
       
   371 QString QScriptDebuggerConsole::historyAt(int index) const
       
   372 {
       
   373     Q_D(const QScriptDebuggerConsole);
       
   374     return d->commandHistory.value(index);
       
   375 }
       
   376 
       
   377 /*!
       
   378   \reimp
       
   379 */
       
   380 void QScriptDebuggerConsole::changeHistoryAt(int index, const QString &newHistory)
       
   381 {
       
   382     Q_D(QScriptDebuggerConsole);
       
   383     d->commandHistory[index] = newHistory;
       
   384 }
       
   385 
       
   386 QT_END_NAMESPACE