diff --git a/NEWS.md b/NEWS.md index 0a9732f6..9fce4961 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +Version 0.10.0 For Dev-C++ 7 Beta + - enhancement: use gdb/mi interface to communicate with gdb debug session + - enhancement: better display of watch vars + Version 0.9.3 For Dev-C++ 7 Beta - fix: the count in the title of issues view isn't correct - fix: columns calculation not correct when paint lines containing chinese characters diff --git a/RedPandaIDE/RedPandaIDE_zh_CN.qm b/RedPandaIDE/RedPandaIDE_zh_CN.qm index 751c4090..18a0af6e 100644 Binary files a/RedPandaIDE/RedPandaIDE_zh_CN.qm and b/RedPandaIDE/RedPandaIDE_zh_CN.qm differ diff --git a/RedPandaIDE/RedPandaIDE_zh_CN.ts b/RedPandaIDE/RedPandaIDE_zh_CN.ts index dd35d1e5..239e2e49 100644 --- a/RedPandaIDE/RedPandaIDE_zh_CN.ts +++ b/RedPandaIDE/RedPandaIDE_zh_CN.ts @@ -95,17 +95,17 @@ BacktraceModel - + Function 函数 - + Filename 文件名 - + Line @@ -151,37 +151,37 @@ BreakpointModel - + Filename 文件名 - + Line - + Condition 条件 - + Save file '%1' failed. 保存文件'%1'失败。 - + Can't open file '%1' for write. 无法写入文件'%1'. - + Error in json file '%1':%2 : %3 JSON文件'%1':%2中存在错误:%3 - + Can't open file '%1' for read. 无法读取文件'%1'. @@ -952,73 +952,71 @@ Are you really want to continue? Debugger - + No compiler set 无编译器设置 - + No compiler set is configured. 没有配置编译器设置。 - + Can't start debugging. 无法启动调试器 - + Debugger path error 调试路径错误 - + Debugger's path "%1" contains non-ascii characters. 调试路径"%1"中包含非ASCII字符(如,中文字符) - + This prevents it from executing. 这会导致调试器无法启动。 - + Debugger not exists 找不到调试器 - + Can''t find debugger in : "%1" 找不到调试器程序"%1" - - + Execute to evaluate 执行以求值 - Not found in current context - 不在当前语境中 + 不在当前语境中 - + Compile 编译 - + Source file is more recent than executable. 源文件比程序文件新。 - + Recompile? 重新编译? - + Signal "%1" Received: 收到信号"%1": @@ -2867,11 +2865,11 @@ Are you really want to continue? - + + - - - + + Issues 编译器 @@ -3128,8 +3126,8 @@ Are you really want to continue? - - + + Copy 复制 @@ -3140,7 +3138,7 @@ Are you really want to continue? - + Paste 粘贴 @@ -3151,7 +3149,7 @@ Are you really want to continue? - + Select All 选择全部 @@ -3278,7 +3276,7 @@ Are you really want to continue? - + New Problem Set 新建试题集 @@ -3297,14 +3295,14 @@ Are you really want to continue? - + Save Problem Set 保存试题集 - + Load Problem Set 载入试题集 @@ -3639,7 +3637,7 @@ Are you really want to continue? - + Clear all breakpoints 删除所有断点 @@ -3740,7 +3738,7 @@ Are you really want to continue? - + Rename Symbol 重命名符号 @@ -3761,13 +3759,13 @@ Are you really want to continue? - + Export As RTF 导出为RTF - + Export As HTML 导出为HTML @@ -3887,7 +3885,7 @@ Are you really want to continue? - + Open Folder 打开文件夹 @@ -3897,7 +3895,7 @@ Are you really want to continue? 运行参数... - + File Encoding 文件编码 @@ -4070,44 +4068,44 @@ Are you really want to continue? 重新编译? - - + + Save last open info error 保存上次打开信息失败 - + Can't remove old last open information file '%1' 无法删除旧上次打开信息文件'%1' - + Can't save last open info file '%1' 无法保存上次打开信息文件'%1' - + Load last open info error 载入上次打开信息失败 - + Can't load last open info file '%1' 无法载入上次打开信息文件'%1' - + Show detail debug logs 显示详细调试器日志 - + Copy all 全部复制 - - + + Clear 清除 @@ -4123,7 +4121,7 @@ Are you really want to continue? - + Problem Set %1 试题集%1 @@ -4161,56 +4159,56 @@ Are you really want to continue? 项目已经被修改过,是否需要重新构建? - + Auto Save Error 自动保存出错 - + Auto save "%1" to "%2" failed:%3 自动保存"%1"到"%2"失败:%3 - + Properties... 试题属性... - + Set Problem Set Name 设置试题集名称 - + Problem Set Name: 试题集名称: - + Remove 删除 - + Remove All Bookmarks 删除全部书签 - + Modify Description 修改描述 - - - + + + Bookmark Description 书签描述 - - - + + + Description: 描述: @@ -4219,363 +4217,363 @@ Are you really want to continue? 在调试主控台中显示调试器输出 - + Remove this search 清除这次搜索 - + Clear all searches 删除所有搜索 - + Breakpoint condition... 断点条件... - + Break point condition 断点条件 - + Enter the condition of the breakpoint: 输入当前断点的生效条件: - + Remove All Breakpoints Remove all breakpoints 删除所有断点 - + Remove Breakpoint 删除当前断点 - + Rename File 重命名文件 - - + + Add Folder 添加文件夹 - + New folder 新文件夹 - + Folder name: 文件夹: - + Rename Folder 重命名 - + Remove Folder 删除文件夹 - + Sort By Type 按类型排序 - + Sort alphabetically 按名称排序 - + Show inherited members 显示继承的成员 - + Goto declaration 跳转到声明处 - + Goto definition 跳转到定义处 - + Open in Editor 在编辑器中打开 - + Open in External Program 使用外部程序打开 - + Open in Terminal 在终端中打开 - + Open in Windows Explorer 在Windows浏览器中打开 - + Character sets 字符集 - + %1 files autosaved 已自动保存%1个文件 - + Set answer to... 设置答案源代码... - + select other file... 选择其他文件... - + Select Answer Source File 选择答案源代码文件 - + C/C++Source Files (*.c *.cpp *.cc *.cxx) C/C++Source Files (*.c *.cpp *.cc *.cxx C/C++源代码文件 (*.c *.cpp *.cc *.cxx) - + Save project 保存项目 - + The project '%1' has modifications. 项目'%1'有改动。 - - + + Do you want to save it? 需要保存吗? - - + + File Changed 文件已发生变化 - + New Project File? 新建项目文件? - + Do you want to add the new file to the project? 您是否要将新建的文件加入项目? - - - - + + + + Save Error 保存失败 - + Change Project Compiler Set 改变项目编译器配置集 - + Change the project's compiler set will lose all custom compiler set options. 改变项目的编译器配置集会导致所有的自定义编译器选项被重置。 - + Do you really want to do that? 你真的想要做那些吗? - + Do you really want to clear all breakpoints in this file? 您真的要清除该文件的所有断点吗? - + New project 新建项目 - + Close %1 and start new project? 关闭'%1'以打开新项目? - + Folder not exist 文件夹不存在 - + Folder '%1' doesn't exist. Create it now? 文件夹'%1'不存在。是否创建? - + Can't create folder 无法创建文件夹 - + Failed to create folder '%1'. 创建文件夹'%1'失败。 - + Save new project as - + Red panda Dev-C++ project file (*.dev) 小熊猫Dev-C++项目文件 (*.dev) - + New project fail 新建项目失败 - + Can't assign project template 无法使用模板创建项目 - + Remove file 删除文件 - + Remove the file from disk? 同时从硬盘上删除文件? - + untitled 无标题 - + New Project File Name 新的项目文件名 - + File Name: 文件名: - + File Already Exists! 文件已存在! - + File '%1' already exists! 文件'%1'已经存在! - + Add to project 添加到项目 - + Rename Error 重命名出错 - + Symbol '%1' is defined in system header. 符号'%1'在系统头文件中定义,无法修改。 - + New Name 新名称 - - + + Replace Error 替换出错 - + Can't open file '%1' for replace! 无法打开文件'%1'进行替换! - + Contents has changed since last search! 内容和上次查找时不一致。 - + Rich Text Format Files (*.rtf) RTF格式文件 (*.rtf) - + HTML Files (*.html) HTML文件 (*.html) - + The current problem set is not empty. 当前的试题集不是空的。 - + Problem %1 试题%1 - - + + Problem Set Files (*.pbs) 试题集文件 (*.pbs) - + Load Error 载入失败 - - + + Problem Case %1 试题案例%1 @@ -4587,14 +4585,14 @@ Are you really want to continue? - - - - - - - - + + + + + + + + Error 错误 @@ -4604,75 +4602,75 @@ Are you really want to continue? 项目历史 - + File '%1' was changed. 磁盘文件'%1'已被修改。 - + Reload its content from disk? 是否重新读取它的内容? - + File '%1' was removed. 磁盘文件'%1'已被删除。 - + Keep it open? 是否保持它在小熊猫C++中打开的编辑窗口? - + Open 打开 - + Compile Failed 编译失败 - + Run Failed 运行失败 - - + + Confirm Convertion 确认转换 - - + + The editing file will be saved using %1 encoding. <br />This operation can't be reverted. <br />Are you sure to continue? 当前编辑器中的文件将会使用%1编码保存。<br />这项操作无法被撤回。<br />你确定要继续吗? - + New Watch Expression 新监视表达式 - + Enter Watch Expression (it is recommended to use 'this->' for class members): 输入监视表达式 - + Parsing file %1 of %2: "%3" (%1/%2)正在解析文件"%3" - - + + Done parsing %1 files in %2 seconds 完成%1个文件的解析,用时%2秒 - + (%1 files per second) (每秒%1个文件) @@ -6188,12 +6186,12 @@ Are you really want to continue? RegisterModel - + Register 寄存器 - + Value @@ -6600,7 +6598,7 @@ Are you really want to continue? 自动链接 - + @@ -6676,7 +6674,7 @@ Are you really want to continue? 杂项 - + Program Runner @@ -7089,37 +7087,48 @@ Are you really want to continue? WatchModel - + Save file '%1' failed. 保存文件'%1'失败。 - + Can't open file '%1' for write. 无法写入文件'%1'. - + Error in json file '%1':%2 : %3 JSON文件'%1':%2中存在错误:%3 - + + Execute to evaluate 执行以求值 - + + Not Valid + 在当前作用域中无效 + + + Can't open file '%1' for read. 无法读取文件'%1'. - + Expression 表达式 - + + Type + 类型 + + + Value diff --git a/RedPandaIDE/debugger.cpp b/RedPandaIDE/debugger.cpp index f371f8c7..06f6ae10 100644 --- a/RedPandaIDE/debugger.cpp +++ b/RedPandaIDE/debugger.cpp @@ -27,6 +27,9 @@ Debugger::Debugger(QObject *parent) : QObject(parent) mReader = nullptr; mCommandChanged = false; mLeftPageIndexBackup = -1; + + connect(mWatchModel, &WatchModel::fetchChildren, + this, &Debugger::fetchVarChildren); } bool Debugger::start() @@ -58,6 +61,7 @@ bool Debugger::start() tr("Can''t find debugger in : \"%1\"").arg(debuggerPath)); return false; } + mWatchModel->resetAllVarInfos(); mReader = new DebugReader(this); mReader->setDebuggerPath(debuggerPath); connect(mReader, &QThread::finished,this,&Debugger::clearUpReader); @@ -81,10 +85,20 @@ bool Debugger::start() &Debugger::updateRegisterNames); connect(mReader, &DebugReader::registerValuesUpdated, this, &Debugger::updateRegisterValues); + connect(mReader, &DebugReader::varCreated,mWatchModel, + &WatchModel::updateVarInfo); + connect(mReader, &DebugReader::prepareVarChildren,mWatchModel, + &WatchModel::prepareVarChildren); + connect(mReader, &DebugReader::addVarChild,mWatchModel, + &WatchModel::addVarChild); + connect(mReader, &DebugReader::varValueUpdated,mWatchModel, + &WatchModel::updateVarValue); connect(mReader, &DebugReader::inferiorContinued,pMainWindow, &MainWindow::removeActiveBreakpoints); connect(mReader, &DebugReader::inferiorStopped,pMainWindow, &MainWindow::setActiveBreakpoint); + connect(mReader, &DebugReader::inferiorStopped,this, + &Debugger::refreshWatchVars); mReader->registerInferiorStoppedCommand("-stack-list-frames",""); mReader->registerInferiorStoppedCommand("-stack-list-variables", "--all-values"); @@ -110,10 +124,6 @@ void Debugger::clearUpReader() mReader->deleteLater(); mReader=nullptr; -// if WatchVarList.Count = 0 then // nothing worth showing, restore view -// MainForm.LeftPageControl.ActivePageIndex := LeftPageIndexBackup; - -// // Close CPU window if (pMainWindow->cpuDialog()!=nullptr) { pMainWindow->cpuDialog()->close(); } @@ -129,9 +139,9 @@ void Debugger::clearUpReader() mBacktraceModel->clear(); - for(PWatchVar var:mWatchModel->watchVars()) { - invalidateWatchVar(var); - } + mWatchModel->clearAllVarInfos(); + + mBreakpointModel->invalidateAllBreakpointNumbers(); pMainWindow->updateEditorActions(); } @@ -279,37 +289,43 @@ void Debugger::sendAllBreakpointsToDebugger() } } -void Debugger::addWatchVar(const QString &namein) +void Debugger::addWatchVar(const QString &expression) { // Don't allow duplicates... - PWatchVar oldVar = mWatchModel->findWatchVar(namein); + PWatchVar oldVar = mWatchModel->findWatchVar(expression); if (oldVar) return; PWatchVar var = std::make_shared(); var->parent= nullptr; - var->expression = namein; + var->expression = expression; var->value = tr("Execute to evaluate"); var->numChild = 0; var->hasMore = false; + var->parent = nullptr; mWatchModel->addWatchVar(var); sendWatchCommand(var); } -void Debugger::renameWatchVar(const QString &oldname, const QString &newname) +void Debugger::modifyWatchVarExpression(const QString &oldExpr, const QString &newExpr) { // check if name already exists; - PWatchVar var = mWatchModel->findWatchVar(newname); + PWatchVar var = mWatchModel->findWatchVar(newExpr); if (var) return; - var = mWatchModel->findWatchVar(oldname); + var = mWatchModel->findWatchVar(oldExpr); if (var) { - var->name = newname; - if (mExecuting && var->gdbIndex!=-1) + if (mExecuting && !var->expression.isEmpty()) sendRemoveWatchCommand(var); - invalidateWatchVar(var); + var->expression = newExpr; + var->type.clear(); + var->value.clear(); + var->hasMore = false; + var->numChild=0; + var->name.clear(); + var->children.clear(); if (mExecuting) { sendWatchCommand(var); @@ -319,9 +335,16 @@ void Debugger::renameWatchVar(const QString &oldname, const QString &newname) void Debugger::refreshWatchVars() { - for (PWatchVar var:mWatchModel->watchVars()) { - if (var->gdbIndex == -1) - sendWatchCommand(var); + if (mExecuting) { + sendAllWatchVarsToDebugger(); + sendCommand("-var-update"," --all-values *"); + } +} + +void Debugger::fetchVarChildren(const QString &varName) +{ + if (mExecuting) { + sendCommand("-var-list-children",varName); } } @@ -332,75 +355,37 @@ void Debugger::removeWatchVars(bool deleteparent) } else { for(const PWatchVar& var:mWatchModel->watchVars()) { sendRemoveWatchCommand(var); - invalidateWatchVar(var); } + mWatchModel->clearAllVarInfos(); } } void Debugger::removeWatchVar(const QModelIndex &index) { + PWatchVar var = mWatchModel->findWatchVar(index); + if (!var) + return; + sendRemoveWatchCommand(var); mWatchModel->removeWatchVar(index); } -void Debugger::invalidateAllVars() -{ - mReader->setInvalidateAllVars(true); -} - -void Debugger::sendAllWatchvarsToDebugger() +void Debugger::sendAllWatchVarsToDebugger() { for (PWatchVar var:mWatchModel->watchVars()) { - sendWatchCommand(var); + if (var->name.isEmpty()) + sendWatchCommand(var); } } -void Debugger::invalidateWatchVar(const QString &name) +PWatchVar Debugger::findWatchVar(const QString &expression) { - PWatchVar var = mWatchModel->findWatchVar(name); - if (var) { - invalidateWatchVar(var); - } -} - -void Debugger::invalidateWatchVar(PWatchVar var) -{ - var->gdbIndex = -1; - QString value; - if (mExecuting) { - value = tr("Not found in current context"); - } else { - value = tr("Execute to evaluate"); - } - var->value = value; - if (var->children.isEmpty()) { - mWatchModel->notifyUpdated(var); - } else { - mWatchModel->beginUpdate(); - var->children.clear(); - mWatchModel->endUpdate(); - } -} - -PWatchVar Debugger::findWatchVar(const QString &name) -{ - return mWatchModel->findWatchVar(name); + return mWatchModel->findWatchVar(expression); } //void Debugger::notifyWatchVarUpdated(PWatchVar var) //{ // mWatchModel->notifyUpdated(var); //} - -void Debugger::notifyBeforeProcessWatchVar() -{ - mWatchModel->beginUpdate(); -} - -void Debugger::notifyAfterProcessWatchVar() -{ - mWatchModel->endUpdate(); -} - BacktraceModel* Debugger::backtraceModel() { return mBacktraceModel; @@ -413,7 +398,7 @@ BreakpointModel *Debugger::breakpointModel() void Debugger::sendWatchCommand(PWatchVar var) { - sendCommand("-var-carete", QString(" - %1").arg(var->expression)); + sendCommand("-var-create", var->expression); } void Debugger::sendRemoveWatchCommand(PWatchVar var) @@ -587,7 +572,6 @@ DebugReader::DebugReader(Debugger* debugger, QObject *parent) : QThread(parent), mDebugger = debugger; mProcess = nullptr; mCmdRunning = false; - mInvalidateAllVars = false; } void DebugReader::postCommand(const QString &Command, const QString &Params, @@ -740,6 +724,15 @@ void DebugReader::processResult(const QByteArray &result) case GDBMIResultType::RegisterValues: handleRegisterValue(multiValues["register-values"].array()); return; + case GDBMIResultType::CreateVar: + handleCreateVar(multiValues); + return; + case GDBMIResultType::ListVarChildren: + handleListVarChildren(multiValues); + return; + case GDBMIResultType::UpdateVarValue: + handleUpdateVarValue(multiValues["changelist"].array()); + return; } } @@ -846,12 +839,6 @@ void DebugReader::processDebugOutput(const QByteArray& debugOutput) // Only update once per update at most //WatchView.Items.BeginUpdate; - if (mInvalidateAllVars) { - //invalidate all vars when there's first output - mDebugger->removeWatchVars(false); - mInvalidateAllVars = false; - } - emit parseStarted(); mConsoleOutput.clear(); @@ -899,190 +886,6 @@ void DebugReader::runInferiorStoppedHook() } } -QString DebugReader::processEvalOutput() -{ - int indent = 0; - - // First line gets special treatment - QString result =""; - if (result.startsWith('{')) - indent+=4; - - // Collect all data, add formatting in between -// AnnotationType nextAnnotation; -// QString nextLine; -// bool shouldExit = false; -// do { -// nextAnnotation = getNextAnnotation(); -// nextLine = getNextLine(); -// switch(nextAnnotation) { -// // Change indent if { or } is found -// case AnnotationType::TFieldBegin: -// result += "\r\n" + QString(4,' '); -// break; -// case AnnotationType::TFieldValue: -// if (nextLine.startsWith('{') && (peekNextAnnotation() != -// AnnotationType::TArrayBegin)) -// indent+=4; -// break; -// case AnnotationType::TFieldEnd: -// if (nextLine.endsWith('}')) { -// indent-=4; -// result += "\r\n" + QString(4,' '); -// } -// break; -// case AnnotationType::TEOF: -// case AnnotationType::TValueHistoryEnd: -// case AnnotationType::TDisplayEnd: -// shouldExit = true; -// default: -// break; -// } -// result += nextLine; -// } while (!shouldExit); - return result; -} - -void DebugReader::processWatchOutput(PWatchVar watchVar) -{ -// // Expand if it was expanded or if it didn't have any children -// bool ParentWasExpanded = false; - - // Do not remove root node of watch variable - - watchVar->children.clear(); - watchVar->value = ""; - // Process output parsed by ProcessEvalStruct - QString s = processEvalOutput(); - - QStringList tokens = tokenize(s); - PWatchVar parentVar = watchVar; - PWatchVar currentVar = watchVar; - - QVector varStack; - int i=0; - while (i='a' && ch<='z') - || (ch>='A' && ch<='Z') || (ch>127)) { - //is identifier,create new child node - PWatchVar newVar = std::make_shared(); - newVar->parent = parentVar.get(); - newVar->name = token; - newVar->fullName = parentVar->fullName + '.'+token; - newVar->value = ""; - newVar->gdbIndex = -1; - parentVar->children.append(newVar); - currentVar = newVar; - } else if (ch == '{') { - if (parentVar->value.isEmpty()) { - parentVar->value = "{"; - } else { - PWatchVar newVar = std::make_shared(); - newVar->parent = parentVar.get(); - if (parentVar) { - int count = parentVar->children.count(); - newVar->name = QString("[%1]").arg(count); - newVar->fullName = parentVar->fullName + newVar->name; - } else { - newVar->name = QString("[0]"); - newVar->fullName = newVar->name; - } - newVar->value = "{"; - parentVar->children.append(newVar); - varStack.push_back(parentVar); - parentVar = newVar; - } - currentVar = nullptr; - } else if (ch == '}') { - currentVar = nullptr; - PWatchVar newVar = std::make_shared(); - newVar->parent = parentVar.get(); - newVar->name = ""; - newVar->value = "}"; - newVar->gdbIndex = -1; - parentVar->children.append(newVar); - if (!varStack.isEmpty()) { - parentVar = varStack.back(); - varStack.pop_back(); - } - } else if (ch == '=') { - // just skip it - } else if (ch == ',') { - currentVar = nullptr; - } else { - if (currentVar) { - if (currentVar->value.isEmpty()) { - currentVar->value = token; - } else { - currentVar->value += " "+token; - } - } else { - PWatchVar newVar = std::make_shared(); - newVar->parent = parentVar.get(); - newVar->name = QString("[%1]") - .arg(parentVar->children.count()); - newVar->fullName = parentVar->fullName + newVar->name; - newVar->value = token; - newVar->gdbIndex = -1; - parentVar->children.append(newVar); - } - } - i++; - } - // add placeholder name for variable name so we can format structs using one rule - - // Add children based on indent -// QStringList lines = TextToLines(s); - -// for (const QString& line:lines) { -// // Format node text. Remove trailing comma -// QString nodeText = line.trimmed(); -// if (nodeText.endsWith(',')) { -// nodeText.remove(nodeText.length()-1,1); -// } - -// if (nodeText.endsWith('{')) { // new member struct -// if (parentVar->text.isEmpty()) { // root node, replace text only -// parentVar->text = nodeText; -// } else { -// PWatchVar newVar = std::make_shared(); -// newVar->parent = parentVar.get(); -// newVar->name = ""; -// newVar->text = nodeText; -// newVar->gdbIndex = -1; -// parentVar->children.append(newVar); -// varStack.push_back(parentVar); -// parentVar = newVar; -// } -// } else if (nodeText.startsWith('}')) { // end of struct, change parent -// PWatchVar newVar = std::make_shared(); -// newVar->parent = parentVar.get(); -// newVar->name = ""; -// newVar->text = "}"; -// newVar->gdbIndex = -1; -// parentVar->children.append(newVar); -// if (!varStack.isEmpty()) { -// parentVar = varStack.back(); -// varStack.pop_back(); -// } -// } else { // next parent member/child -// if (parentVar->text.isEmpty()) { // root node, replace text only -// parentVar->text = nodeText; -// } else { -// PWatchVar newVar = std::make_shared(); -// newVar->parent = parentVar.get(); -// newVar->name = ""; -// newVar->text = nodeText; -// newVar->gdbIndex = -1; -// parentVar->children.append(newVar); -// } -// } -// } - // TODO: remember expansion state -} - void DebugReader::runNextCmd() { QMutexLocker locker(&mCmdQueueMutex); @@ -1100,10 +903,19 @@ void DebugReader::runNextCmd() emit cmdStarted(); QByteArray s; + QByteArray params; s=pCmd->command.toLocal8Bit(); if (!pCmd->params.isEmpty()) { - s+= ' '+pCmd->params.toLocal8Bit(); + params = pCmd->params.toLocal8Bit(); } + if (pCmd->command == "-var-create") { + //hack for variable creation,to easy remember var expression + params = " - @ "+params; + } else if (pCmd->command == "-var-list-children") { + //hack for list variable children,to easy remember var expression + params = " --all-values " + params; + } + s+=" "+params; s+= "\n"; if (mProcess->write(s)<0) { emit writeToDebugFailed(); @@ -1113,9 +925,9 @@ void DebugReader::runNextCmd() if (pSettings->debugger().enableDebugConsole() ) { //update debug console if (!pSettings->debugger().showDetailLog()) { - emit changeDebugConsoleLastLine(pCmd->command + ' ' + pCmd->params); + emit changeDebugConsoleLastLine(pCmd->command + ' ' + params); } else { - emit changeDebugConsoleLastLine(pCmd->command + ' ' + pCmd->params); + emit changeDebugConsoleLastLine(pCmd->command + ' ' + params); } } } @@ -1309,6 +1121,62 @@ void DebugReader::handleRegisterValue(const QList emit registerValuesUpdated(result); } +void DebugReader::handleCreateVar(const GDBMIResultParser::ParseObject &multiVars) +{ + if (!mCurrentCmd) + return; + QString expression = mCurrentCmd->params; + QString name = multiVars["name"].value(); + int numChild = multiVars["numchild"].intValue(0); + QString value = multiVars["value"].value(); + QString type = multiVars["type"].value(); + bool hasMore = multiVars["has_more"].value() != "0"; + emit varCreated(expression,name,numChild,value,type,hasMore); +} + +void DebugReader::handleListVarChildren(const GDBMIResultParser::ParseObject &multiVars) +{ + if (!mCurrentCmd) + return; + QString parentName = mCurrentCmd->params; + int parentNumChild = multiVars["numchild"].intValue(0); + QList children = multiVars["children"].array(); + bool hasMore = multiVars["has_more"].value()!="0"; + emit prepareVarChildren(parentName,parentNumChild,hasMore); + foreach(const GDBMIResultParser::ParseValue& child, children) { + GDBMIResultParser::ParseObject childObj = child.object(); + QString name = childObj["name"].value(); + QString exp = childObj["exp"].value(); + int numChild = childObj["numchild"].intValue(0); + QString value = childObj["value"].value(); + QString type = childObj["type"].value(); + bool hasMore = childObj["has_more"].value() != "0"; + emit addVarChild(parentName, + name, + exp, + numChild, + value, + type, + hasMore); + } +} + +void DebugReader::handleUpdateVarValue(const QList &changes) +{ + foreach (const GDBMIResultParser::ParseValue& value, changes) { + GDBMIResultParser::ParseObject obj = value.object(); + QString name = obj["name"].value(); + QString val = obj["value"].value(); + QString inScope = obj["in_scope"].value(); + bool typeChanged = (obj["type_changed"].value()=="true"); + QString newType = obj["new_type"].value(); + int newNumChildren = obj["new_num_children"].intValue(-1); + bool hasMore = (obj["has_more"].value() == "1"); + emit varValueUpdated(name,val,inScope,typeChanged,newType,newNumChildren, + hasMore); + } +} + QByteArray DebugReader::removeToken(const QByteArray &line) { int p=0; @@ -1374,16 +1242,6 @@ bool DebugReader::processExited() const return mProcessExited; } -bool DebugReader::invalidateAllVars() const -{ - return mInvalidateAllVars; -} - -void DebugReader::setInvalidateAllVars(bool invalidateAllVars) -{ - mInvalidateAllVars = invalidateAllVars; -} - QString DebugReader::debuggerPath() const { return mDebuggerPath; @@ -1810,7 +1668,6 @@ QVariant WatchModel::data(const QModelIndex &index, int role) const WatchVar* item = static_cast(index.internalPointer()); switch (role) { case Qt::DisplayRole: - //qDebug()<<"item->text:"<text; switch(index.column()) { case 0: return item->expression; @@ -1827,7 +1684,6 @@ QModelIndex WatchModel::index(int row, int column, const QModelIndex &parent) co { if (!hasIndex(row,column,parent)) return QModelIndex(); - WatchVar* parentItem; PWatchVar pChild; if (!parent.isValid()) { @@ -1897,9 +1753,9 @@ void WatchModel::addWatchVar(PWatchVar watchVar) return; } } - this->beginInsertRows(QModelIndex(),mWatchVars.size(),mWatchVars.size()); + beginInsertRows(QModelIndex(),mWatchVars.count(),mWatchVars.count()); mWatchVars.append(watchVar); - this->endInsertRows(); + endInsertRows(); } void WatchModel::removeWatchVar(const QString &express) @@ -1909,6 +1765,8 @@ void WatchModel::removeWatchVar(const QString &express) if (express == var->expression) { this->beginResetModel(); //this->beginRemoveRows(QModelIndex(),i,i); + if (mVarIndex.contains(var->name)) + mVarIndex.remove(var->name); mWatchVars.removeAt(i); //this->endRemoveRows(); this->endResetModel(); @@ -1920,6 +1778,9 @@ void WatchModel::removeWatchVar(const QModelIndex &index) { int r=index.row(); this->beginRemoveRows(QModelIndex(),r,r); + PWatchVar var = mWatchVars[r]; + if (mVarIndex.contains(var->name)) + mVarIndex.remove(var->name); mWatchVars.removeAt(r); this->endRemoveRows(); } @@ -1936,24 +1797,124 @@ const QList &WatchModel::watchVars() return mWatchVars; } -PWatchVar WatchModel::findWatchVar(const QString &name) +PWatchVar WatchModel::findWatchVar(const QModelIndex &index) +{ + if (!index.isValid()) + return PWatchVar(); + int r=index.row(); + return mWatchVars[r]; +} + +PWatchVar WatchModel::findWatchVar(const QString &expr) { for (PWatchVar var:mWatchVars) { - if (name == var->name) { + if (expr == var->expression) { return var; } } return PWatchVar(); } -PWatchVar WatchModel::findWatchVar(int gdbIndex) +void WatchModel::resetAllVarInfos() { - for (PWatchVar var:mWatchVars) { - if (gdbIndex == var->gdbIndex) { - return var; - } + beginResetModel(); + foreach (PWatchVar var, mWatchVars) { + var->name.clear(); + var->value = tr("Not Valid"); + var->numChild = 0; + var->hasMore = false; + var->type.clear(); + var->children.clear(); } - return PWatchVar(); + mVarIndex.clear(); + endResetModel(); +} + +void WatchModel::updateVarInfo(const QString &expression, const QString &name, int numChild, const QString &value, const QString &type, bool hasMore) +{ + PWatchVar var = findWatchVar(expression); + if (!var) + return; + var->name = name; + var->value = value; + var->numChild = numChild; + var->hasMore = hasMore; + var->type = type; + mVarIndex.insert(name,var); + QModelIndex idx = index(var); + if (!idx.isValid()) + return; + emit dataChanged(idx,createIndex(idx.row(),2,var.get())); +} + +void WatchModel::prepareVarChildren(const QString &parentName, int numChild, bool hasMore) +{ + PWatchVar var = mVarIndex.value(parentName,PWatchVar()); + if (var) { + var->numChild = numChild; + var->hasMore = hasMore; + } +} + +void WatchModel::addVarChild(const QString &parentName, const QString &name, + const QString &exp, int numChild, const QString &value, + const QString &type, bool hasMore) +{ + PWatchVar var = mVarIndex.value(parentName,PWatchVar()); + if (!var) + return; + beginInsertRows(index(var),var->children.count(),var->children.count()); + PWatchVar child = std::make_shared(); + child->name = name; + child->expression = exp; + child->numChild = numChild; + child->value = value; + child->type = type; + child->hasMore = hasMore; + child->parent = var.get(); + var->children.append(child); + endInsertRows(); + mVarIndex.insert(name,child); +} + +void WatchModel::updateVarValue(const QString &name, const QString &val, const QString &inScope, bool typeChanged, const QString &newType, int newNumChildren, bool hasMore) +{ + PWatchVar var = mVarIndex.value(name,PWatchVar()); + if (!var) + return; + if (inScope == "true") { + var->value = val; + } else{ + var->value = tr("Not Valid"); + } + if (typeChanged) { + var->type = newType; + } + QModelIndex idx = index(var); + if (newNumChildren>=0 + && var->numChild!=newNumChildren) { + beginRemoveRows(idx,0,var->children.count()); + var->children.clear(); + endRemoveRows(); + var->numChild = newNumChildren; + } + var->hasMore = hasMore; + emit dataChanged(idx,createIndex(idx.row(),2,var.get())); +} + +void WatchModel::clearAllVarInfos() +{ + beginResetModel(); + foreach (PWatchVar var, mWatchVars) { + var->name.clear(); + var->value = tr("Execute to evaluate"); + var->numChild = 0; + var->hasMore = false; + var->type.clear(); + var->children.clear(); + } + mVarIndex.clear(); + endResetModel(); } void WatchModel::beginUpdate() @@ -2036,6 +1997,7 @@ void WatchModel::load(const QString &filename) var->value = tr("Execute to evaluate"); var->numChild = 0; var->hasMore=false; + var->parent = nullptr; addWatchVar(var); } @@ -2045,6 +2007,41 @@ void WatchModel::load(const QString &filename) } } +QModelIndex WatchModel::index(PWatchVar var) const +{ + if (!var) + return QModelIndex(); + return index(var.get()); +} + +QModelIndex WatchModel::index(WatchVar* pVar) const { + if (pVar==nullptr) + return QModelIndex(); + if (pVar->parent) { + int row=-1; + for (int i=0;iparent->children.count();i++) { + if (pVar->parent->children[i].get() == pVar) { + row = i; + break; + } + } + if (row<0) + return QModelIndex(); + return createIndex(row,0,pVar); + } else { + int row=-1; + for (int i=0;i(parent.internalPointer()); + item->hasMore = false; + item->numChild = item->children.count(); + emit fetchChildren(item->name); } bool WatchModel::canFetchMore(const QModelIndex &parent) const @@ -2072,13 +2075,13 @@ bool WatchModel::canFetchMore(const QModelIndex &parent) const return false; } WatchVar* item = static_cast(parent.internalPointer()); - return item->numChild>item->children.count(); + return item->numChild>item->children.count() || item->hasMore; } bool WatchModel::hasChildren(const QModelIndex &parent) const { if (!parent.isValid()) { - return false; + return true; } WatchVar* item = static_cast(parent.internalPointer()); return item->numChild>0; diff --git a/RedPandaIDE/debugger.h b/RedPandaIDE/debugger.h index 345a6093..f08ce6e0 100644 --- a/RedPandaIDE/debugger.h +++ b/RedPandaIDE/debugger.h @@ -131,34 +131,51 @@ public: QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &index) const override; - + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + void fetchMore(const QModelIndex &parent) override; + bool canFetchMore(const QModelIndex &parent) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; + bool hasChildren(const QModelIndex &parent) const override; void addWatchVar(PWatchVar watchVar); void removeWatchVar(const QString& expression); void removeWatchVar(const QModelIndex& index); void clear(); const QList& watchVars(); - PWatchVar findWatchVar(const QString& name); - PWatchVar findWatchVar(int gdbIndex); + PWatchVar findWatchVar(const QModelIndex& index); + PWatchVar findWatchVar(const QString& expr); + void resetAllVarInfos(); + void clearAllVarInfos(); void beginUpdate(); void endUpdate(); void notifyUpdated(PWatchVar var); void save(const QString& filename); void load(const QString& filename); +public slots: + void updateVarInfo(const QString& expression, + const QString& name, + int numChild, + const QString& value, + const QString& type, + bool hasMore); + void prepareVarChildren(const QString& parentName, int numChild, bool hasMore); + void addVarChild(const QString& parentName, const QString& name, + const QString& exp, int numChild, + const QString& value, const QString& type, + bool hasMore); + void updateVarValue(const QString& name, const QString& val, + const QString& inScope, bool typeChanged, + const QString& newType, int newNumChildren, + bool hasMore); +signals: + void fetchChildren(const QString& name); +private: + QModelIndex index(PWatchVar var) const; + QModelIndex index(WatchVar* pVar) const; private: QList mWatchVars; + QHash mVarIndex; int mUpdateCount; - - // QAbstractItemModel interface -public: - QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - void fetchMore(const QModelIndex &parent); - bool canFetchMore(const QModelIndex &parent) const; - - // QAbstractItemModel interface -public: - bool hasChildren(const QModelIndex &parent) const; }; @@ -192,25 +209,16 @@ public: PBreakpoint breakpointAt(int line, const Editor* editor, int &index); void setBreakPointCondition(int index, const QString& condition); void sendAllBreakpointsToDebugger(); - void validateBreakpoint(int line, const QString& filename, int number); - void invalidateAllBreakpoints(); //watch vars - void addWatchVar(const QString& namein); -// void removeWatchVar(nodein: TTreeNode); overload; - void renameWatchVar(const QString& oldname, const QString& newname); + void addWatchVar(const QString& expression); + void modifyWatchVarExpression(const QString& oldExpr, const QString& newExpr); - void refreshWatchVars(); void removeWatchVars(bool deleteparent); void removeWatchVar(const QModelIndex& index); - void invalidateAllVars(); - void sendAllWatchvarsToDebugger(); - void invalidateWatchVar(const QString& name); - void invalidateWatchVar(PWatchVar var); - PWatchVar findWatchVar(const QString& name); + void sendAllWatchVarsToDebugger(); + PWatchVar findWatchVar(const QString& expression); // void notifyWatchVarUpdated(PWatchVar var); - void notifyBeforeProcessWatchVar(); - void notifyAfterProcessWatchVar(); BacktraceModel* backtraceModel(); BreakpointModel* breakpointModel(); @@ -246,7 +254,8 @@ private slots: void clearUpReader(); void updateRegisterNames(const QStringList& registerNames); void updateRegisterValues(const QHash& values); - + void refreshWatchVars(); + void fetchVarChildren(const QString& varName); private: bool mExecuting; bool mCommandChanged; @@ -272,9 +281,6 @@ public: bool commandRunning(); void waitStart(); - bool invalidateAllVars() const; - void setInvalidateAllVars(bool invalidateAllVars); - bool inferiorPaused() const; bool processExited() const; @@ -332,11 +338,24 @@ signals: void disassemblyUpdate(const QString& filename, const QString& funcName, const QStringList& result); void registerNamesUpdated(const QStringList& registerNames); void registerValuesUpdated(const QHash& values); + void varCreated(const QString& expression, + const QString& name, + int numChild, + const QString& value, + const QString& type, + bool hasMore); + void prepareVarChildren(const QString& parentName,int numChild, bool hasMore); + void addVarChild(const QString& parentName, const QString& name, + const QString& exp, int numChild, + const QString& value, const QString& type, + bool hasMore); + void varValueUpdated(const QString& name, const QString& val, + const QString& inScope, bool typeChanged, + const QString& newType, int newNumChildren, + bool hasMore); private: void clearCmdQueue(); - QString processEvalOutput(); - void processWatchOutput(PWatchVar WatchVar); void runNextCmd(); QStringList tokenize(const QString& s); @@ -348,6 +367,9 @@ private: void handleMemory(const QList & rows); void handleRegisterNames(const QList & names); void handleRegisterValue(const QList & values); + void handleCreateVar(const GDBMIResultParser::ParseObject& multiVars); + void handleListVarChildren(const GDBMIResultParser::ParseObject& multiVars); + void handleUpdateVarValue(const QList &changes); void processConsoleOutput(const QByteArray& line); void processResult(const QByteArray& result); void processExecAsyncRecord(const QByteArray& line); @@ -362,7 +384,6 @@ private: QRecursiveMutex mCmdQueueMutex; QSemaphore mStartSemaphore; QQueue mCmdQueue; - bool mInvalidateAllVars; //fOnInvalidateAllVars: TInvalidateAllVarsEvent; bool mCmdRunning; diff --git a/RedPandaIDE/gdbmiresultparser.cpp b/RedPandaIDE/gdbmiresultparser.cpp index 961da48a..d6767850 100644 --- a/RedPandaIDE/gdbmiresultparser.cpp +++ b/RedPandaIDE/gdbmiresultparser.cpp @@ -18,6 +18,9 @@ GDBMIResultParser::GDBMIResultParser() mResultTypes.insert("-data-read-memory",GDBMIResultType::Memory); mResultTypes.insert("-data-list-register-names",GDBMIResultType::RegisterNames); mResultTypes.insert("-data-list-register-values",GDBMIResultType::RegisterValues); + mResultTypes.insert("-var-create",GDBMIResultType::CreateVar); + mResultTypes.insert("-var-list-children",GDBMIResultType::ListVarChildren); + mResultTypes.insert("-var-update",GDBMIResultType::UpdateVarValue); } bool GDBMIResultParser::parse(const QByteArray &record, const QString& command, GDBMIResultType &type, ParseObject& multiValues) @@ -290,6 +293,8 @@ bool GDBMIResultParser::isNameChar(char ch) { if (ch=='-') return true; + if (ch=='_') + return true; if (ch>='a' && ch<='z') return true; if (ch>='A' && ch<='Z') @@ -315,19 +320,16 @@ void GDBMIResultParser::skipSpaces(const char *&p) const QByteArray &GDBMIResultParser::ParseValue::value() const { - Q_ASSERT(mType == ParseValueType::Value); return mValue; } const QList<::GDBMIResultParser::ParseValue> &GDBMIResultParser::ParseValue::array() const { - Q_ASSERT(mType == ParseValueType::Array); return mArray; } const GDBMIResultParser::ParseObject &GDBMIResultParser::ParseValue::object() const { - Q_ASSERT(mType == ParseValueType::Object); return mObject; } diff --git a/RedPandaIDE/gdbmiresultparser.h b/RedPandaIDE/gdbmiresultparser.h index 4b0964b8..c7742612 100644 --- a/RedPandaIDE/gdbmiresultparser.h +++ b/RedPandaIDE/gdbmiresultparser.h @@ -19,8 +19,9 @@ enum class GDBMIResultType { RegisterNames, RegisterValues, Memory, - VariableInfo, - + CreateVar, + ListVarChildren, + UpdateVarValue }; diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index 7aa2184e..fb3c2d1b 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -1444,10 +1444,6 @@ void MainWindow::debug() includeOrSkipDirs(compilerSet->defaultCppIncludeDirs(),true); } - // Add breakpoints and watch vars -// for i := 0 to fDebugger.WatchVarList.Count - 1 do -// fDebugger.AddWatchVar(i); - mDebugger->sendAllWatchvarsToDebugger(); mDebugger->sendAllBreakpointsToDebugger(); // Run the debugger @@ -1677,10 +1673,10 @@ void MainWindow::includeOrSkipDirs(const QStringList &dirs, bool skip) foreach (QString dir,dirs) { QString dirName = dir.replace('\\','/'); if (skip) { -// mDebugger->sendCommand( -// "skip", -// QString("-gfi \"%1/%2\"") -// .arg(dirName,"*.*")); + mDebugger->sendCommand( + "skip", + QString("-gfi \"%1/%2\"") + .arg(dirName,"*.*")); } else { mDebugger->sendCommand( "-environment-directory", @@ -4001,7 +3997,6 @@ void MainWindow::on_actionStep_Over_triggered() { if (mDebugger->executing()) { //WatchView.Items.BeginUpdate(); - mDebugger->invalidateAllVars(); mDebugger->sendCommand("-exec-next", ""); } } @@ -4010,7 +4005,6 @@ void MainWindow::on_actionStep_Into_triggered() { if (mDebugger->executing()) { //WatchView.Items.BeginUpdate(); - mDebugger->invalidateAllVars(); mDebugger->sendCommand("-exec-step", ""); } @@ -4020,7 +4014,6 @@ void MainWindow::on_actionStep_Out_triggered() { if (mDebugger->executing()) { //WatchView.Items.BeginUpdate(); - mDebugger->invalidateAllVars(); mDebugger->sendCommand("-exec-finish", ""); } @@ -4032,7 +4025,6 @@ void MainWindow::on_actionRun_To_Cursor_triggered() Editor *e=mEditorList->getEditor(); if (e!=nullptr) { //WatchView.Items.BeginUpdate(); - mDebugger->invalidateAllVars(); mDebugger->sendCommand("-exec-until", QString("\"%1\":%2") .arg(e->filename()) .arg(e->caretY())); @@ -4045,7 +4037,6 @@ void MainWindow::on_actionContinue_triggered() { if (mDebugger->executing()) { //WatchView.Items.BeginUpdate(); - mDebugger->invalidateAllVars(); mDebugger->sendCommand("-exec-continue", ""); } } diff --git a/RedPandaIDE/mainwindow.ui b/RedPandaIDE/mainwindow.ui index e9d75868..bcef089b 100644 --- a/RedPandaIDE/mainwindow.ui +++ b/RedPandaIDE/mainwindow.ui @@ -85,7 +85,7 @@ QTabWidget::West - 3 + 1 true @@ -174,7 +174,7 @@ false - 50 + 100 diff --git a/RedPandaIDE/version.h b/RedPandaIDE/version.h index e80b2153..e8f5a828 100644 --- a/RedPandaIDE/version.h +++ b/RedPandaIDE/version.h @@ -2,6 +2,6 @@ #define VERSION_H #include -#define DEVCPP_VERSION "beta.0.9.3" +#define DEVCPP_VERSION "beta.0.10.0" #endif // VERSION_H