diff -r 000000000000 -r 1918ee327afb src/scripttools/debugging/qscriptdebuggerconsole.cpp --- /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 +#include +#include +#include +#include +#include + +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