Warning, file /kdevelop/kdev-python/debugger/variablecontroller.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2012 Sven Brauch <svenbrauch@googlemail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "variablecontroller.h"
0008 #include "variable.h"
0009 #include "debugsession.h"
0010 #include "pdbframestackmodel.h"
0011 #include <codehelpers.h>
0012 #include <language/duchain/duchainlock.h>
0013 #include <language/duchain/declaration.h>
0014 #include <language/duchain/duchain.h>
0015 #include <interfaces/ilanguagecontroller.h>
0016 
0017 #include <debugger/variable/variablecollection.h>
0018 #include <debugger/framestack/framestackmodel.h>
0019 #include <interfaces/icore.h>
0020 #include <QStack>
0021 #include <KMessageBox>
0022 #include <KLocalizedString>
0023 
0024 #include <QDebug>
0025 #include "debuggerdebug.h"
0026 
0027 using namespace KDevelop;
0028 
0029 namespace Python {
0030 
0031 VariableController::VariableController(IDebugSession* parent) : IVariableController(parent)
0032 {
0033     m_updateTimer.setSingleShot(true);
0034     m_updateTimer.setInterval(100);
0035     QObject::connect(&m_updateTimer, &QTimer::timeout,
0036                      this, &VariableController::_update);
0037 }
0038 
0039 void VariableController::addWatch(KDevelop::Variable* variable)
0040 {
0041     variableCollection()->watches()->add(variable->expression());
0042 }
0043 
0044 void VariableController::addWatchpoint(KDevelop::Variable* /*variable*/)
0045 {
0046     qCWarning(KDEV_PYTHON_DEBUGGER) << "addWatchpoint requested (not implemented)";
0047 }
0048 
0049 void VariableController::handleEvent(IDebugSession::event_t event)
0050 {
0051     if ( event == IDebugSession::thread_or_frame_changed ) {
0052         DebugSession* s = static_cast<DebugSession*>(session());
0053         PdbFrameStackModel* model = static_cast<PdbFrameStackModel*>(s->frameStackModel());
0054         int delta = model->currentFrame() - model->debuggerAtFrame();
0055         model->setDebuggerAtFrame(model->currentFrame());
0056         bool positive = delta > 0;
0057         qCDebug(KDEV_PYTHON_DEBUGGER) << "changing frame by" << delta;
0058         for ( int i = delta; i != 0; i += ( positive ? -1 : 1 ) ) {
0059             qCDebug(KDEV_PYTHON_DEBUGGER) << ( positive ? "up" : "down" ) << model->currentFrame() << model->debuggerAtFrame();
0060             s->addSimpleInternalCommand(positive ? "up" : "down");
0061         }
0062     }
0063     KDevelop::IVariableController::handleEvent(event);
0064 }
0065 
0066 KDevelop::Variable* VariableController::createVariable(KDevelop::TreeModel* model, KDevelop::TreeItem* parent, const QString& expression, const QString& display)
0067 {
0068     return new Variable(model, parent, expression, display);
0069 }
0070 
0071 KTextEditor::Range VariableController::expressionRangeUnderCursor(KTextEditor::Document* doc, const KTextEditor::Cursor& cursor)
0072 {
0073     QString prefix;
0074     DUChainReadLocker lock;
0075     if ( ! doc->isModified() ) {
0076         if ( TopDUContext* context = DUChain::self()->chainForDocument(doc->url()) ) {
0077             DUContext* contextAtCursor = context->findContextAt(CursorInRevision(cursor.line(), cursor.column()));
0078             if ( contextAtCursor && contextAtCursor->type() == DUContext::Class ) {
0079                 if ( contextAtCursor->owner() && ! contextAtCursor->owner()->identifier().isEmpty() ) {
0080                     prefix = contextAtCursor->owner()->identifier().toString() + ".";
0081                 }
0082             }
0083         }
0084     }
0085     else {
0086         qCDebug(KDEV_PYTHON_DEBUGGER) << "duchain unavailable for document" << doc->url() << "or document out of date";
0087     }
0088 
0089     TextDocumentLazyLineFetcher linefetcher(doc);
0090     KTextEditor::Cursor startCursor;
0091     auto text = prefix + CodeHelpers::expressionUnderCursor(linefetcher, cursor, startCursor);
0092     return {startCursor, startCursor + KTextEditor::Cursor{0, text.length()}};
0093 }
0094 
0095 void VariableController::localsUpdateReady(QByteArray rawData)
0096 {
0097     QRegExp formatExtract("([a-zA-Z0-9_]+) \\=\\> (.*)");
0098     QList<QByteArray> data = rawData.split('\n');
0099     data.removeAll({});
0100     qCDebug(KDEV_PYTHON_DEBUGGER) << "locals update:" << data;
0101 
0102     int i = 0;
0103     QStringList vars;
0104     QMap<QString, QString> values;
0105     while ( i < data.length() ) {
0106         QByteArray d = data.at(i);
0107         if ( formatExtract.exactMatch(d) ) {
0108             QString key = formatExtract.capturedTexts().at(1);
0109             vars << key;
0110             values[key] = formatExtract.capturedTexts().at(2);
0111         }
0112         else qCWarning(KDEV_PYTHON_DEBUGGER) << "mismatch:" << d;
0113         i++;
0114     }
0115 
0116     QList<KDevelop::Variable*> variableObjects = KDevelop::ICore::self()->debugController()->variableCollection()
0117                                                  ->locals()->updateLocals(vars);
0118     for ( int i = 0; i < variableObjects.length(); i++ ) {
0119         KDevelop::Variable* v = variableObjects[i];
0120 
0121         auto model = v->model();
0122         auto parent = model->indexForItem(v, 0);
0123         auto childCount = v->model()->rowCount(parent);
0124         qCDebug(KDEV_PYTHON_DEBUGGER) << "updating:" << v->expression() << "active children:" << childCount;
0125         for ( int j = 0; j < childCount; j++ ) {
0126             auto index = model->index(j, 0, parent);
0127             auto child = static_cast<KDevelop::TreeItem*>(index.internalPointer());
0128             if ( auto childVariable = qobject_cast<Variable*>(child) ) {
0129                 qCDebug(KDEV_PYTHON_DEBUGGER) << "   got child var:" << childVariable->expression();
0130                 v->fetchMoreChildren();
0131                 break;
0132             }
0133         }
0134 
0135         v->setValue(values[v->expression()]);
0136         v->setHasMoreInitial(true);
0137     }
0138 }
0139 
0140 void VariableController::update() {
0141     m_updateTimer.start();
0142 }
0143 
0144 void VariableController::_update()
0145 {
0146     qCDebug(KDEV_PYTHON_DEBUGGER) << " ************************* update requested";
0147     DebugSession* d = static_cast<DebugSession*>(parent());
0148     if (autoUpdate() & UpdateWatches) {
0149         variableCollection()->watches()->reinstall();
0150     }
0151 
0152    if (autoUpdate() & UpdateLocals) {
0153         // TODO find a more elegant solution for this import!
0154         InternalPdbCommand* import = new InternalPdbCommand(nullptr, nullptr, "import __kdevpython_debugger_utils\n");
0155         InternalPdbCommand* cmd = new InternalPdbCommand(this, "localsUpdateReady",
0156                                   "__kdevpython_debugger_utils.format_locals(__kdevpython_debugger_utils.__kdevpython_builtin_locals())\n");
0157         d->addCommand(import);
0158         d->addCommand(cmd);
0159    }
0160 }
0161 
0162 }
0163 
0164 #include "moc_variablecontroller.cpp"