src/scripttools/debugging/qscriptdebuggerconsole.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scripttools/debugging/qscriptdebuggerconsole.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,386 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtSCriptTools module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qscriptdebuggerconsole_p.h"
+#include "qscriptdebuggerconsolecommandjob_p.h"
+#include "qscriptdebuggerconsolecommandmanager_p.h"
+#include "qscriptdebuggerscriptedconsolecommand_p.h"
+#include "qscriptmessagehandlerinterface_p.h"
+
+#include <QtCore/qdir.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdebug.h>
+#include <QtScript/qscriptengine.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+  \since 4.5
+  \class QScriptDebuggerConsole
+  \internal
+
+  \brief The QScriptDebuggerConsole class provides the core functionality of a debugger console.
+*/
+
+class QScriptDebuggerConsolePrivate
+{
+    Q_DECLARE_PUBLIC(QScriptDebuggerConsole)
+public:
+    QScriptDebuggerConsolePrivate(QScriptDebuggerConsole*);
+    ~QScriptDebuggerConsolePrivate();
+
+    void loadScriptedCommands(const QString &scriptsPath,
+                              QScriptMessageHandlerInterface *messageHandler);
+    QScriptDebuggerConsoleCommandJob *createJob(
+        const QString &command,
+        QScriptMessageHandlerInterface *messageHandler,
+        QScriptDebuggerCommandSchedulerInterface *commandScheduler);
+
+    QScriptDebuggerConsoleCommandManager *commandManager;
+    QString commandPrefix;
+    QString input;
+    QStringList commandHistory;
+    int currentFrameIndex;
+    qint64 currentScriptId;
+    int currentLineNumber;
+    int evaluateAction;
+    qint64 sessionId;
+
+    QScriptDebuggerConsole *q_ptr;
+};
+
+QScriptDebuggerConsolePrivate::QScriptDebuggerConsolePrivate(QScriptDebuggerConsole* parent)
+    : q_ptr(parent)
+{
+    sessionId = 0;
+    currentFrameIndex = 0;
+    currentScriptId = -1;
+    currentLineNumber = -1;
+    evaluateAction = 0;
+    commandPrefix = QLatin1String(".");
+    commandManager = new QScriptDebuggerConsoleCommandManager();
+}
+
+QScriptDebuggerConsolePrivate::~QScriptDebuggerConsolePrivate()
+{
+    delete commandManager;
+}
+
+/*!
+  Loads command definitions from scripts located in the given \a scriptsPath.
+*/
+void QScriptDebuggerConsolePrivate::loadScriptedCommands(
+    const QString &scriptsPath,
+    QScriptMessageHandlerInterface *messageHandler)
+{
+    QDir dir(scriptsPath);
+    QFileInfoList entries = dir.entryInfoList(QStringList()
+                                              << QLatin1String("*.qs"));
+    for (int i = 0; i < entries.size(); ++i) {
+        const QFileInfo &fi = entries.at(i);
+        QString fileName = fi.fileName();
+        QFile file(scriptsPath + QLatin1Char('/') + fileName);
+        if (!file.open(QIODevice::ReadOnly))
+            continue;
+        QTextStream stream(&file);
+        QString program = stream.readAll();
+        QScriptDebuggerScriptedConsoleCommand *command;
+        command = QScriptDebuggerScriptedConsoleCommand::parse(
+            program, fileName, messageHandler);
+        if (!command)
+            continue;
+        commandManager->addCommand(command);
+    }
+}
+
+
+/*!
+  Creates a job that will execute the given debugger \a command.
+  Returns the new job, or 0 if the command is undefined.
+*/
+QScriptDebuggerConsoleCommandJob *QScriptDebuggerConsolePrivate::createJob(
+    const QString &command, QScriptMessageHandlerInterface *messageHandler,
+    QScriptDebuggerCommandSchedulerInterface *commandScheduler)
+{
+    QString name;
+    int i = command.indexOf(QLatin1Char(' '));
+    if (i == -1) {
+        name = command;
+        i = name.size();
+    } else {
+        name = command.left(i);
+    }
+    if (name.isEmpty())
+        return 0;
+    QScriptDebuggerConsoleCommand *cmd = commandManager->findCommand(name);
+    if (!cmd) {
+        // try to auto-complete
+        QStringList completions = commandManager->completions(name);
+        if (!completions.isEmpty()) {
+            if (completions.size() > 1) {
+                QString msg;
+                msg.append(QString::fromLatin1("Ambiguous command \"%0\": ")
+                           .arg(name));
+                for (int j = 0; j < completions.size(); ++j) {
+                    if (j > 0)
+                        msg.append(QLatin1String(", "));
+                    msg.append(completions.at(j));
+                }
+                msg.append(QLatin1Char('.'));
+                messageHandler->message(QtWarningMsg, msg);
+                return 0;
+            }
+            cmd = commandManager->findCommand(completions.at(0));
+            Q_ASSERT(cmd != 0);
+        }
+        if (!cmd) {
+            messageHandler->message(
+                QtWarningMsg,
+                QString::fromLatin1("Undefined command \"%0\". Try \"help\".")
+                .arg(name));
+            return 0;
+        }
+    }
+    QStringList args;
+    QString tmp = command.mid(i+1);
+    if (cmd->argumentTypes().contains(QString::fromLatin1("script"))) {
+        if (!tmp.isEmpty())
+            args.append(tmp);
+    } else {
+        args = tmp.split(QLatin1Char(' '), QString::SkipEmptyParts);
+    }
+    return cmd->createJob(args, q_func(), messageHandler, commandScheduler);
+}
+
+QScriptDebuggerConsole::QScriptDebuggerConsole()
+    : d_ptr(new QScriptDebuggerConsolePrivate(this))
+{
+}
+
+QScriptDebuggerConsole::~QScriptDebuggerConsole()
+{
+}
+
+void QScriptDebuggerConsole::loadScriptedCommands(const QString &scriptsPath,
+                                                  QScriptMessageHandlerInterface *messageHandler)
+{
+    Q_D(QScriptDebuggerConsole);
+    d->loadScriptedCommands(scriptsPath, messageHandler);
+}
+
+QScriptDebuggerConsoleCommandManager *QScriptDebuggerConsole::commandManager() const
+{
+    Q_D(const QScriptDebuggerConsole);
+    return d->commandManager;
+}
+
+bool QScriptDebuggerConsole::hasIncompleteInput() const
+{
+    Q_D(const QScriptDebuggerConsole);
+    return !d->input.isEmpty();
+}
+
+QString QScriptDebuggerConsole::incompleteInput() const
+{
+    Q_D(const QScriptDebuggerConsole);
+    return d->input;
+}
+
+void QScriptDebuggerConsole::setIncompleteInput(const QString &input)
+{
+    Q_D(QScriptDebuggerConsole);
+    d->input = input;
+}
+
+QString QScriptDebuggerConsole::commandPrefix() const
+{
+    Q_D(const QScriptDebuggerConsole);
+    return d->commandPrefix;
+}
+
+/*!
+  Consumes the given line of \a input.  If the input starts with the
+  command prefix, it is regarded as a debugger command; otherwise the
+  input is evaluated as a plain script.
+*/
+QScriptDebuggerConsoleCommandJob *QScriptDebuggerConsole::consumeInput(
+    const QString &input, QScriptMessageHandlerInterface *messageHandler,
+    QScriptDebuggerCommandSchedulerInterface *commandScheduler)
+{
+    Q_D(QScriptDebuggerConsole);
+    static const int maximumHistoryCount = 100;
+    QString cmd;
+    if (d->input.isEmpty() && input.isEmpty()) {
+        if (d->commandHistory.isEmpty())
+            return 0;
+        cmd = d->commandHistory.first();
+    } else {
+        cmd = input;
+    }
+    if (d->input.isEmpty() && cmd.startsWith(d->commandPrefix)) {
+        if (!input.isEmpty()) {
+            d->commandHistory.prepend(cmd);
+            if (d->commandHistory.size() > maximumHistoryCount)
+                d->commandHistory.removeLast();
+        }
+        cmd.remove(0, d->commandPrefix.length());
+        return d->createJob(cmd, messageHandler, commandScheduler);
+    }
+    d->input += cmd;
+    d->input += QLatin1Char('\n');
+    QScriptSyntaxCheckResult check = QScriptEngine::checkSyntax(d->input);
+    if (check.state() == QScriptSyntaxCheckResult::Intermediate)
+        return false;
+    d->input.chop(1); // remove the last \n
+    cmd = QString();
+    cmd.append(d->commandPrefix);
+    cmd.append(QString::fromLatin1("eval "));
+    cmd.append(d->input);
+    d->commandHistory.prepend(cmd);
+    if (d->commandHistory.size() > maximumHistoryCount)
+        d->commandHistory.removeLast();
+    d->input.clear();
+    cmd.remove(0, d->commandPrefix.length());
+    return d->createJob(cmd, messageHandler, commandScheduler);
+}
+
+int QScriptDebuggerConsole::currentFrameIndex() const
+{
+    Q_D(const QScriptDebuggerConsole);
+    return d->currentFrameIndex;
+}
+
+void QScriptDebuggerConsole::setCurrentFrameIndex(int index)
+{
+    Q_D(QScriptDebuggerConsole);
+    d->currentFrameIndex = index;
+}
+
+qint64 QScriptDebuggerConsole::currentScriptId() const
+{
+    Q_D(const QScriptDebuggerConsole);
+    return d->currentScriptId;
+}
+
+void QScriptDebuggerConsole::setCurrentScriptId(qint64 id)
+{
+    Q_D(QScriptDebuggerConsole);
+    d->currentScriptId = id;
+}
+
+int QScriptDebuggerConsole::currentLineNumber() const
+{
+    Q_D(const QScriptDebuggerConsole);
+    return d->currentLineNumber;
+}
+
+void QScriptDebuggerConsole::setCurrentLineNumber(int lineNumber)
+{
+    Q_D(QScriptDebuggerConsole);
+    d->currentLineNumber = lineNumber;
+}
+
+int QScriptDebuggerConsole::evaluateAction() const
+{
+    Q_D(const QScriptDebuggerConsole);
+    return d->evaluateAction;
+}
+
+void QScriptDebuggerConsole::setEvaluateAction(int action)
+{
+    Q_D(QScriptDebuggerConsole);
+    d->evaluateAction = action;
+}
+
+qint64 QScriptDebuggerConsole::sessionId() const
+{
+    Q_D(const QScriptDebuggerConsole);
+    return d->sessionId;
+}
+
+void QScriptDebuggerConsole::bumpSessionId()
+{
+    Q_D(QScriptDebuggerConsole);
+    ++d->sessionId;
+}
+
+void QScriptDebuggerConsole::showDebuggerInfoMessage(
+    QScriptMessageHandlerInterface *messageHandler)
+{
+    messageHandler->message(
+        QtDebugMsg,
+        QString::fromLatin1(
+            "Welcome to the Qt Script debugger.\n"
+            "Debugger commands start with a . (period).\n"
+            "Any other input will be evaluated by the script interpreter.\n"
+            "Type \".help\" for help.\n"));
+}
+
+/*!
+  \reimp
+*/
+int QScriptDebuggerConsole::historyCount() const
+{
+    Q_D(const QScriptDebuggerConsole);
+    return d->commandHistory.size();
+}
+
+/*!
+  \reimp
+*/
+QString QScriptDebuggerConsole::historyAt(int index) const
+{
+    Q_D(const QScriptDebuggerConsole);
+    return d->commandHistory.value(index);
+}
+
+/*!
+  \reimp
+*/
+void QScriptDebuggerConsole::changeHistoryAt(int index, const QString &newHistory)
+{
+    Q_D(QScriptDebuggerConsole);
+    d->commandHistory[index] = newHistory;
+}
+
+QT_END_NAMESPACE