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"