diff --git a/NEWS.md b/NEWS.md index 52d02c94..66d50f5e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,25 @@ +Version 0.10.2 For Dev-C++ 7 Beta + - fix: select by mouse can't correctly set mouse's column position + - fix: dragging out of the editor and back will cause error + - fix: dragging text from lines in the front to lines back will cause error + - fix: dragging text onto itself should do nothing + - fix:license info in the about dialog should be readonly + - enhancement: change project name in the project view + +Version 0.10.1 For Dev-C++ 7 Beta + - fix: can't correctly expand watch expression that has spaces in it + - fix: can't correctly display stl containers in watch + - fix: the last line in the debug console is not correctly displayed + - enhancement: scroll while dragging text in the editor + - fix: dragging out of the editor shouldn't reset the caret back + +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 + - fix: project's modified flag not cleared after saved + Version 0.9.4 For Dev-C++ 7 Beta - - fix: code format indent settings not correctly saved + - fix: code formatter's "indent type" option not correctly saved Version 0.9.3 For Dev-C++ 7 Beta - fix: the count in the title of issues view isn't correct diff --git a/RedPandaIDE/RedPandaIDE.pro b/RedPandaIDE/RedPandaIDE.pro index a552b31b..05cb6ca8 100644 --- a/RedPandaIDE/RedPandaIDE.pro +++ b/RedPandaIDE/RedPandaIDE.pro @@ -25,6 +25,7 @@ SOURCES += \ compiler/ojproblemcasesrunner.cpp \ compiler/projectcompiler.cpp \ compiler/runner.cpp \ + gdbmiresultparser.cpp \ platform.cpp \ compiler/compiler.cpp \ compiler/compilermanager.cpp \ @@ -134,7 +135,8 @@ SOURCES += \ widgets/qconsole.cpp \ widgets/qpatchedcombobox.cpp \ widgets/searchdialog.cpp \ - widgets/searchresultview.cpp + widgets/searchresultview.cpp \ + widgets/signalmessagedialog.cpp HEADERS += \ ConvertUTF.h \ @@ -154,6 +156,7 @@ HEADERS += \ compiler/runner.h \ compiler/stdincompiler.h \ cpprefacter.h \ + gdbmiresultparser.h \ parser/cppparser.h \ parser/cpppreprocessor.h \ parser/cpptokenizer.h \ @@ -258,7 +261,8 @@ HEADERS += \ widgets/qconsole.h \ widgets/qpatchedcombobox.h \ widgets/searchdialog.h \ - widgets/searchresultview.h + widgets/searchresultview.h \ + widgets/signalmessagedialog.h FORMS += \ settingsdialog/compilerautolinkwidget.ui \ @@ -303,7 +307,8 @@ FORMS += \ widgets/filepropertiesdialog.ui \ widgets/newprojectdialog.ui \ widgets/ojproblempropertywidget.ui \ - widgets/searchdialog.ui + widgets/searchdialog.ui \ + widgets/signalmessagedialog.ui TRANSLATIONS += \ RedPandaIDE_zh_CN.ts diff --git a/RedPandaIDE/RedPandaIDE_zh_CN.qm b/RedPandaIDE/RedPandaIDE_zh_CN.qm index 398781d0..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 c125c874..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'. @@ -891,26 +891,31 @@ Are you really want to continue? - Show debug logs in the debug console - 在调试主控台中显示调试器输出 + Show detail debug logs + Show debug logs in the debug console + 显示详细调试器日志 + + + + Show CPU Window when signal received + 程序收到信号停止时缺省打开CPU窗口 - Show full gdb annotations - 在调试主控台中显示gdb输出注解 + 在调试主控台中显示gdb输出注解 - + Autosave 自动保存 - + Autosave breakpoints 自动保存断点 - + Autosave watches 自动保存监视 @@ -947,71 +952,74 @@ 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": + Editor @@ -2857,11 +2865,11 @@ Are you really want to continue? - - - - - + + + + + Issues 编译器 @@ -2937,6 +2945,7 @@ Are you really want to continue? + Debug Console 调试主控台 @@ -3012,7 +3021,7 @@ Are you really want to continue? 工具栏2 - + New 新建 @@ -3070,8 +3079,8 @@ Are you really want to continue? - - + + Compile 编译 @@ -3117,8 +3126,8 @@ Are you really want to continue? - - + + Copy 复制 @@ -3129,7 +3138,7 @@ Are you really want to continue? - + Paste 粘贴 @@ -3140,7 +3149,7 @@ Are you really want to continue? - + Select All 选择全部 @@ -3260,14 +3269,14 @@ Are you really want to continue? - + Problem Set 试题集 - + New Problem Set 新建试题集 @@ -3286,14 +3295,14 @@ Are you really want to continue? - + Save Problem Set 保存试题集 - + Load Problem Set 载入试题集 @@ -3329,7 +3338,7 @@ Are you really want to continue? - + Problem 试题 @@ -3729,7 +3738,7 @@ Are you really want to continue? - + Rename Symbol 重命名符号 @@ -3750,13 +3759,13 @@ Are you really want to continue? - + Export As RTF 导出为RTF - + Export As HTML 导出为HTML @@ -3876,7 +3885,7 @@ Are you really want to continue? - + Open Folder 打开文件夹 @@ -3886,42 +3895,42 @@ Are you really want to continue? 运行参数... - + File Encoding 文件编码 - + Recent Files 文件历史 - - - - - - + + + + + + Debugging 正在调试 - - - - - - + + + + + + Running 正在运行 - - - - - - + + + + + + Compiling 正在编译 @@ -3930,184 +3939,189 @@ Are you really want to continue? 行:%1 列:%2 已选择:%3 总行数:%4 总长度:%5 - + Line:%1 Col:%2 Selected:%3 Lines:%4 Length:%5 Line: %1 Col: %2 Selected: %3 Lines: %4 Length: %5 行: %1 列: %2 已选择 :%3 总行数: %4 总长度: %5 - + Read Only 只读 - + Insert 插入 - + Overwrite 覆写 - + Close project 关闭项目 - + Are you sure you want to close %1? 你确定要关闭'%1'吗? - - + + Confirm 确认 - - - + + + Source file is not compiled. 源文件尚未编译。 - - + + Compile now? 现在编译? - - - + + + Source file is more recent than executable. 源文件比可执行程序新。 - + Recompile now? 重新编译? - + No compiler set 无编译器设置 - + No compiler set is configured. 没有配置编译器设置。 - + Can't start debugging. 无法启动调试器 - - + + Enable debugging 启用调试参数 - - + + You have not enabled debugging info (-g3) and/or stripped it from the executable (-s) in Compiler Options.<BR /><BR />Do you want to correct this now? 当前编译设置中未启用调试选项(-g3),或启用了信息剥除选项(-s)<br /><br/>是否纠正这一问题? - + Project not built 项目尚未构建 - + Project hasn't been built. Build it now? 项目尚未构建。是否构建? - + Host applcation missing 宿主程序不存在 - + DLL project needs a host application to run. 动态链接库(DLL)需要一个宿主程序来运行。 - + But it's missing. 但它不存在。 - + Host application not exists 宿主程序不存在 - + Host application file '%1' doesn't exist. 宿主程序'%1'不存在。 - + Recompile? 重新编译? - - + + 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 清除 - + Export 导出 - + Insert Snippet 插入代码段 - - + + Problem Set %1 试题集%1 @@ -4128,280 +4142,275 @@ Are you really want to continue? 或者选择使用其他的网络端口。 - + Red Panda Dev-C++ 小熊猫Dev-C++ - + + Rebuild Project 重新构建项目 - - + + Project has been modified, do you want to rebuild it? 项目已经被修改过,是否需要重新构建? - - Compile Project - 编译项目 - - - + 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: 描述: - Show debug logs in the debug console - 在调试主控台中显示调试器输出 + 在调试主控台中显示调试器输出 - + 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? 你真的想要做那些吗? @@ -4471,27 +4480,27 @@ Are you really want to continue? 同时从硬盘上删除文件? - + untitled 无标题 - + New Project File Name 新的项目文件名 - + File Name: 文件名: - + File Already Exists! 文件已存在! - + File '%1' already exists! 文件'%1'已经存在! @@ -4501,151 +4510,151 @@ Are you really want to continue? 添加到项目 - + 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 - - - + + - - - - - - - - - - + + + + + + + + + + + Error 错误 - + Recent Projects 项目历史 - + 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): 输入监视表达式 @@ -5495,7 +5504,7 @@ Are you really want to continue? QApplication - + Error 错误 @@ -5565,7 +5574,7 @@ Are you really want to continue? 无法写入配置文件夹"%1" - + Can't load autolink settings 无法载入自动链接设置 @@ -6177,19 +6186,22 @@ Are you really want to continue? RegisterModel - + Register 寄存器 - - Value(Hex) - 值(HEX) + + Value + + + + Value(Hex) + 值(HEX) - Value(Dec) - 值(DEC) + 值(DEC) @@ -6586,7 +6598,7 @@ Are you really want to continue? 自动链接 - + @@ -6662,7 +6674,7 @@ Are you really want to continue? 杂项 - + Program Runner @@ -6806,6 +6818,24 @@ Are you really want to continue? 写入快捷键配置文件失败'%1'。 + + SignalMessageDialog + + + Signal Received + 收到信号 + + + + TextLabel + + + + + Open CPU Info Dialog + 打开CPU信息窗口 + + StdinCompiler @@ -7057,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/codesnippetsmanager.h b/RedPandaIDE/codesnippetsmanager.h index bad5222a..a66c7914 100644 --- a/RedPandaIDE/codesnippetsmanager.h +++ b/RedPandaIDE/codesnippetsmanager.h @@ -49,8 +49,6 @@ public: const QString &newFileTemplate() const; void setNewFileTemplate(const QString &newNewFileTemplate); -signals: - private: void loadSnippets(); void saveSnippets(); diff --git a/RedPandaIDE/compiler/executablerunner.cpp b/RedPandaIDE/compiler/executablerunner.cpp index 72ed47c1..8c050ef9 100644 --- a/RedPandaIDE/compiler/executablerunner.cpp +++ b/RedPandaIDE/compiler/executablerunner.cpp @@ -93,7 +93,7 @@ void ExecutableRunner::run() process.start(); process.waitForStarted(5000); if (process.state()==QProcess::Running && redirectInput()) { - process.write(ReadFileToByteArray(redirectInputFilename())); + process.write(readFileToByteArray(redirectInputFilename())); process.closeWriteChannel(); } while (true) { diff --git a/RedPandaIDE/cpprefacter.h b/RedPandaIDE/cpprefacter.h index ca9cab6f..e4caaa6d 100644 --- a/RedPandaIDE/cpprefacter.h +++ b/RedPandaIDE/cpprefacter.h @@ -19,7 +19,6 @@ public: bool findOccurence(const QString& statementFullname, SearchFileScope scope); void renameSymbol(Editor* editor, const BufferCoord& pos, const QString& word, const QString& newWord); -signals: private: void doFindOccurenceInEditor(PStatement statement, Editor* editor, const PCppParser& parser); void doFindOccurenceInProject(PStatement statement, std::shared_ptr project, const PCppParser& parser); diff --git a/RedPandaIDE/debugger.cpp b/RedPandaIDE/debugger.cpp index 8ac29c10..f4018667 100644 --- a/RedPandaIDE/debugger.cpp +++ b/RedPandaIDE/debugger.cpp @@ -12,9 +12,10 @@ #include #include #include +#include #include #include -#include +#include "widgets/signalmessagedialog.h" Debugger::Debugger(QObject *parent) : QObject(parent) { @@ -23,10 +24,12 @@ Debugger::Debugger(QObject *parent) : QObject(parent) mWatchModel = new WatchModel(this); mRegisterModel = new RegisterModel(this); mExecuting = false; - mUseUTF8 = false; mReader = nullptr; mCommandChanged = false; mLeftPageIndexBackup = -1; + + connect(mWatchModel, &WatchModel::fetchChildren, + this, &Debugger::fetchVarChildren); } bool Debugger::start() @@ -58,17 +61,49 @@ 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); connect(mReader, &DebugReader::parseFinished,this,&Debugger::syncFinishedParsing,Qt::BlockingQueuedConnection); connect(mReader, &DebugReader::changeDebugConsoleLastLine,this,&Debugger::onChangeDebugConsoleLastline); - connect(this, &Debugger::localsReady,pMainWindow,&MainWindow::onLocalsReady); connect(mReader, &DebugReader::cmdStarted,pMainWindow, &MainWindow::disableDebugActions); connect(mReader, &DebugReader::cmdFinished,pMainWindow, &MainWindow::enableDebugActions); + connect(mReader, &DebugReader::inferiorStopped, pMainWindow, &MainWindow::enableDebugActions); + connect(mReader, &DebugReader::breakpointInfoGetted, mBreakpointModel, + &BreakpointModel::updateBreakpointNumber); + connect(mReader, &DebugReader::localsUpdated, pMainWindow, + &MainWindow::onLocalsReady); + connect(mReader, &DebugReader::memoryUpdated,this, + &Debugger::updateMemory); + connect(mReader, &DebugReader::evalUpdated,this, + &Debugger::updateEval); + connect(mReader, &DebugReader::disassemblyUpdate,this, + &Debugger::updateDisassembly); + connect(mReader, &DebugReader::registerNamesUpdated, this, + &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"); mReader->start(); - mReader->mStartSemaphore.acquire(1); + mReader->waitStart(); pMainWindow->updateAppTitle(); @@ -89,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(); } @@ -108,14 +139,24 @@ void Debugger::clearUpReader() mBacktraceModel->clear(); - for(PWatchVar var:mWatchModel->watchVars()) { - invalidateWatchVar(var); - } + mWatchModel->clearAllVarInfos(); + + mBreakpointModel->invalidateAllBreakpointNumbers(); pMainWindow->updateEditorActions(); } } +void Debugger::updateRegisterNames(const QStringList ®isterNames) +{ + mRegisterModel->updateNames(registerNames); +} + +void Debugger::updateRegisterValues(const QHash &values) +{ + mRegisterModel->updateValues(values); +} + RegisterModel *Debugger::registerModel() const { return mRegisterModel; @@ -126,10 +167,10 @@ WatchModel *Debugger::watchModel() const return mWatchModel; } -void Debugger::sendCommand(const QString &command, const QString ¶ms, bool updateWatch, bool showInConsole, DebugCommandSource source) +void Debugger::sendCommand(const QString &command, const QString ¶ms, DebugCommandSource source) { if (mExecuting && mReader) { - mReader->postCommand(command,params,updateWatch,showInConsole,source); + mReader->postCommand(command,params,source); } } @@ -141,6 +182,14 @@ bool Debugger::commandRunning() return false; } +bool Debugger::inferiorRunning() +{ + if (mExecuting && mReader) { + return mReader->inferiorRunning(); + } + return false; +} + void Debugger::addBreakpoint(int line, const Editor* editor) { addBreakpoint(line,editor->filename()); @@ -149,6 +198,7 @@ void Debugger::addBreakpoint(int line, const Editor* editor) void Debugger::addBreakpoint(int line, const QString &filename) { PBreakpoint bp=std::make_shared(); + bp->number = -1; bp->line = line; bp->filename = filename; bp->condition = ""; @@ -224,10 +274,10 @@ void Debugger::setBreakPointCondition(int index, const QString &condition) { PBreakpoint breakpoint=mBreakpointModel->setBreakPointCondition(index,condition); if (condition.isEmpty()) { - sendCommand("cond", + sendCommand("-break-condition", QString("%1").arg(breakpoint->line)); } else { - sendCommand("cond", + sendCommand("-break-condition", QString("%1 %2").arg(breakpoint->line).arg(condition)); } } @@ -239,36 +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->name = namein; + var->expression = expression; var->value = tr("Execute to evaluate"); - var->gdbIndex = -1; + 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); @@ -278,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); } } @@ -291,92 +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(); -} - -void Debugger::updateDebugInfo() -{ - sendCommand("backtrace", ""); - sendCommand("info locals", ""); - sendCommand("info args", ""); -} - -bool Debugger::useUTF8() const -{ - return mUseUTF8; -} - -void Debugger::setUseUTF8(bool useUTF8) -{ - mUseUTF8 = useUTF8; -} - BacktraceModel* Debugger::backtraceModel() { return mBacktraceModel; @@ -389,12 +398,12 @@ BreakpointModel *Debugger::breakpointModel() void Debugger::sendWatchCommand(PWatchVar var) { - sendCommand("display", var->name); + sendCommand("-var-create", var->expression); } void Debugger::sendRemoveWatchCommand(PWatchVar var) { - sendCommand("undisplay",QString("%1").arg(var->gdbIndex)); + sendCommand("-var-delete",QString("%1").arg(var->name)); } void Debugger::sendBreakpointCommand(PBreakpoint breakpoint) @@ -403,13 +412,14 @@ void Debugger::sendBreakpointCommand(PBreakpoint breakpoint) // break "filename":linenum QString condition; if (!breakpoint->condition.isEmpty()) { - condition = " if " + breakpoint->condition; + condition = " -c " + breakpoint->condition; } QString filename = breakpoint->filename; filename.replace('\\','/'); - sendCommand("break", - QString("\"%1\":%2").arg(filename) - .arg(breakpoint->line)+condition); + sendCommand("-break-insert", + QString("%1 --source \"%2\" --line %3") + .arg(condition,filename) + .arg(breakpoint->line)); } } @@ -421,13 +431,12 @@ void Debugger::sendClearBreakpointCommand(int index) void Debugger::sendClearBreakpointCommand(PBreakpoint breakpoint) { // Debugger already running? Remove it from GDB - if (breakpoint && mExecuting) { + if (breakpoint && breakpoint->number>=0 && mExecuting) { //clear "filename":linenum QString filename = breakpoint->filename; filename.replace('\\','/'); - sendCommand("clear", - QString("\"%1\":%2").arg(filename) - .arg(breakpoint->line)); + sendCommand("-break-delete", + QString("%1").arg(breakpoint->number)); } } @@ -436,7 +445,7 @@ void Debugger::syncFinishedParsing() bool spawnedcpuform = false; // GDB determined that the source code is more recent than the executable. Ask the user if he wants to rebuild. - if (mReader->doreceivedsfwarning) { + if (mReader->receivedSFWarning()) { if (QMessageBox::question(pMainWindow, tr("Compile"), tr("Source file is more recent than executable.")+"

" + tr("Recompile?"), @@ -449,89 +458,49 @@ void Debugger::syncFinishedParsing() } } + + + // show command output + if (pSettings->debugger().enableDebugConsole() ) { + if (pSettings->debugger().showDetailLog()) { + for (const QString& line:mReader->fullOutput()) { + pMainWindow->addDebugOutput(line); + } + } else { + if (mReader->currentCmd() && mReader->currentCmd()->command == "disas") { + + } else { + for (const QString& line:mReader->consoleOutput()) { + pMainWindow->addDebugOutput(line); + } + if ( + (mReader->currentCmd() + && mReader->currentCmd()->source== DebugCommandSource::Console) + || !mReader->consoleOutput().isEmpty() ) { + pMainWindow->addDebugOutput("(gdb)"); + } + } + } + } + // The program to debug has stopped. Stop the debugger - if (mReader->doprocessexited) { + if (mReader->processExited()) { stop(); return; } - // An evaluation variable has been processed. Forward the results - if (mReader->doevalready) { - //pMainWindow->updateDebugEval(mReader->mEvalValue); - emit evalValueReady(mReader->mEvalValue); - mReader->mEvalValue=""; - mReader->doevalready = false; - } - - if (mReader->doupdatememoryview) { - emit memoryExamineReady(mReader->mMemoryValue); - mReader->mMemoryValue.clear(); - mReader->doupdatememoryview=false; - } - - if (mReader->doupdatelocal) { - emit localsReady(mReader->mLocalsValue); - mReader->mLocalsValue.clear(); - mReader->doupdatelocal=false; - } - - // show command output - if (pSettings->debugger().showCommandLog() || - (mReader->mCurrentCmd && mReader->mCurrentCmd->showInConsole)) { - if (pSettings->debugger().showAnnotations()) { - QString strOutput = mReader->mOutput; - strOutput.replace(QChar(26),'>'); - pMainWindow->addDebugOutput(strOutput); - pMainWindow->addDebugOutput(""); - pMainWindow->addDebugOutput(""); - } else { - QStringList strList = TextToLines(mReader->mOutput); - QStringList outStrList; - bool addToLastLine=false; - for (int i=0;i0) { - outStrList[outStrList.size()-1]+=strOutput; - } else { - outStrList.append(strOutput); - } - addToLastLine = false; - } - } - for (const QString& line:outStrList) { - pMainWindow->addDebugOutput(line); - } - } - } - - // Some part of the CPU form has been updated - if (pMainWindow->cpuDialog()!=nullptr && !mReader->doreceivedsignal) { - if (mReader->doregistersready) { - mRegisterModel->update(mReader->mRegisters); - mReader->mRegisters.clear(); - mReader->doregistersready = false; + if (mReader->signalReceived()) { + SignalMessageDialog dialog(pMainWindow); + dialog.setOpenCPUInfo(pSettings->debugger().openCPUInfoWhenSignaled()); + dialog.setMessage( + tr("Signal \"%1\" Received: ").arg(mReader->signalName()) + + "
" + + mReader->signalMeaning()); + int result = dialog.exec(); + if (result == QDialog::Accepted && dialog.openCPUInfo()) { + pMainWindow->showCPUInfoDialog(); } - if (mReader->dodisassemblerready) { - pMainWindow->cpuDialog()->setDisassembly(mReader->mDisassembly); - mReader->mDisassembly.clear(); - mReader->dodisassemblerready = false; - } - } - - if (mReader->doupdateexecution) { - if (mReader->mCurrentCmd && mReader->mCurrentCmd->source == DebugCommandSource::Console) { - pMainWindow->setActiveBreakpoint(mReader->mBreakPointFile, mReader->mBreakPointLine,false); - } else { - pMainWindow->setActiveBreakpoint(mReader->mBreakPointFile, mReader->mBreakPointLine); - } - refreshWatchVars(); // update variable information - } - - if (mReader->doreceivedsignal) { //SignalDialog := CreateMessageDialog(fSignal, mtError, [mbOk]); //SignalCheck := TCheckBox.Create(SignalDialog); @@ -564,12 +533,29 @@ void Debugger::syncFinishedParsing() // CPU form updates itself when spawned, don't update twice! - if ((mReader->doupdatecpuwindow && !spawnedcpuform) && (pMainWindow->cpuDialog()!=nullptr)) { + if ((mReader->updateCPUInfo() && !spawnedcpuform) && (pMainWindow->cpuDialog()!=nullptr)) { pMainWindow->cpuDialog()->updateInfo(); } } -void Debugger::onChangeDebugConsoleLastline(const QString &text) +void Debugger::updateMemory(const QStringList &value) +{ + emit memoryExamineReady(value); +} + +void Debugger::updateEval(const QString &value) +{ + emit evalValueReady(value); +} + +void Debugger::updateDisassembly(const QString& file, const QString& func, const QStringList &value) +{ + if (pMainWindow->cpuDialog()) { + pMainWindow->cpuDialog()->setDisassembly(file,func,value); + } +} + +void Debugger::onChangeDebugConsoleLastline(const QString& text) { //pMainWindow->changeDebugOutputLastline(text); pMainWindow->addDebugOutput(text); @@ -595,908 +581,367 @@ DebugReader::DebugReader(Debugger* debugger, QObject *parent) : QThread(parent), { mDebugger = debugger; mProcess = nullptr; - mUseUTF8 = false; mCmdRunning = false; - mInvalidateAllVars = false; } -void DebugReader::postCommand(const QString &Command, const QString &Params, bool UpdateWatch, bool ShowInConsole, DebugCommandSource Source) +void DebugReader::postCommand(const QString &Command, const QString &Params, + DebugCommandSource Source) { QMutexLocker locker(&mCmdQueueMutex); - if (mCmdQueue.isEmpty() && UpdateWatch) { - emit pauseWatchUpdate(); - mUpdateCount++; - } PDebugCommand pCmd = std::make_shared(); pCmd->command = Command; pCmd->params = Params; - pCmd->updateWatch = UpdateWatch; - pCmd->showInConsole = ShowInConsole; pCmd->source = Source; mCmdQueue.enqueue(pCmd); // if (!mCmdRunning) -// runNextCmd(); + // runNextCmd(); +} + +void DebugReader::registerInferiorStoppedCommand(const QString &Command, const QString &Params) +{ + QMutexLocker locker(&mCmdQueueMutex); + PDebugCommand pCmd = std::make_shared(); + pCmd->command = Command; + pCmd->params = Params; + pCmd->source = DebugCommandSource::Other; + mInferiorStoppedHookCommands.append(pCmd); } void DebugReader::clearCmdQueue() { QMutexLocker locker(&mCmdQueueMutex); mCmdQueue.clear(); - - if (mUpdateCount>0) { - emit updateWatch(); - mUpdateCount=0; - } } -bool DebugReader::findAnnotation(AnnotationType annotation) +void DebugReader::processConsoleOutput(const QByteArray& line) { - AnnotationType NextAnnotation; - do { - NextAnnotation = getNextAnnotation(); - if (NextAnnotation == AnnotationType::TEOF) - return false; - } while (NextAnnotation != annotation); - - return true; -} - -AnnotationType DebugReader::getAnnotation(const QString &s) -{ - if (s == "pre-prompt") { - return AnnotationType::TPrePrompt; - } else if (s == "prompt") { - return AnnotationType::TPrompt; - } else if (s == "post-prompt") { - AnnotationType result = AnnotationType::TPostPrompt; - //hack to catch local - if ((mCurrentCmd) && (mCurrentCmd->command == "info locals")) { - result = AnnotationType::TLocal; - } else if ((mCurrentCmd) && (mCurrentCmd->command == "info args")) { - //hack to catch params - result = AnnotationType::TParam; - } else if ((mCurrentCmd) && (mCurrentCmd->command == "info") && (mCurrentCmd->params=="registers")) { - // Hack fix to catch register dump - result = AnnotationType::TInfoReg; - } else if ((mCurrentCmd) && (mCurrentCmd->command == "disas")) { - // Another hack to catch assembler - result = AnnotationType::TInfoAsm; - } else if ((mCurrentCmd) && (mCurrentCmd->command.startsWith("x/"))) { - result = AnnotationType::TMemory; - } - return result; - } else if (s == "error-begin") { - return AnnotationType::TErrorBegin; - } else if (s == "error-end") { - return AnnotationType::TErrorEnd; - } else if (s == "display-begin") { - return AnnotationType::TDisplayBegin; - } else if (s == "display-expression") { - return AnnotationType::TDisplayExpression; - } else if (s == "display-end") { - return AnnotationType::TDisplayEnd; - } else if (s == "frame-source-begin") { - return AnnotationType::TFrameSourceBegin; - } else if (s == "frame-source-file") { - return AnnotationType::TFrameSourceFile; - } else if (s == "frame-source-line") { - return AnnotationType::TFrameSourceLine; - } else if (s == "frame-function-name") { - return AnnotationType::TFrameFunctionName; - } else if (s == "frame-args") { - return AnnotationType::TFrameArgs; - } else if (s == "frame-begin") { - return AnnotationType::TFrameBegin; - } else if (s == "frame-end") { - return AnnotationType::TFrameEnd; - } else if (s == "frame-where") { - return AnnotationType::TFrameWhere; - } else if (s == "source") { - return AnnotationType::TSource; - } else if (s == "exited") { - return AnnotationType::TExit; - } else if (s == "arg-begin") { - return AnnotationType::TArgBegin; - } else if (s == "arg-name-end") { - return AnnotationType::TArgNameEnd; - } else if (s == "arg-value") { - return AnnotationType::TArgValue; - } else if (s == "arg-end") { - return AnnotationType::TArgEnd; - } else if (s == "array-section-begin") { - return AnnotationType::TArrayBegin; - } else if (s == "array-section-end") { - return AnnotationType::TArrayEnd; - } else if (s == "elt") { - return AnnotationType::TElt; - } else if (s == "elt-rep") { - return AnnotationType::TEltRep; - } else if (s == "elt-rep-end") { - return AnnotationType::TEltRepEnd; - } else if (s == "field-begin") { - return AnnotationType::TFieldBegin; - } else if (s == "field-name-end") { - return AnnotationType::TFieldNameEnd; - } else if (s == "field-value") { - return AnnotationType::TFieldValue; - } else if (s == "field-end") { - return AnnotationType::TFieldEnd; - } else if (s == "value-history-value") { - return AnnotationType::TValueHistoryValue; - } else if (s == "value-history-begin") { - return AnnotationType::TValueHistoryBegin; - } else if (s == "value-history-end") { - return AnnotationType::TValueHistoryEnd; - } else if (s == "signal") { - return AnnotationType::TSignal; - } else if (s == "signal-name") { - return AnnotationType::TSignalName; - } else if (s == "signal-name-end") { - return AnnotationType::TSignalNameEnd; - } else if (s == "signal-string") { - return AnnotationType::TSignalString; - } else if (s == "signal-string-end") { - return AnnotationType::TSignalStringEnd; - } else if (mIndex >= mOutput.length()) { - return AnnotationType::TEOF; - } else { - return AnnotationType::TUnknown;; - } -} - -AnnotationType DebugReader::getLastAnnotation(const QByteArray &text) -{ - int curpos = text.length()-1; - // Walk back until end of #26's - while ((curpos >= 0) && (text[curpos] != 26)) - curpos--; - - curpos++; - - // Tiny rewrite of GetNextWord for special purposes - QString s = ""; - while ((curpos < text.length()) && (text[curpos]>32)) { - s = s + text[curpos]; - curpos++; - } - - return getAnnotation(s); -} - -AnnotationType DebugReader::getNextAnnotation() -{ - // Skip until end of #26's, i.e. GDB formatted output - skipToAnnotation(); - - // Get part this line, after #26#26 - return getAnnotation(getNextWord()); -} - -QString DebugReader::getNextFilledLine() -{ - // Walk up to an enter sequence - while (mIndex=mOutput.length()) - return ""; - // Skip ONE enter sequence (CRLF, CR, LF, etc.) - if ((mOutput[mIndex] == '\r') && (mIndex+132) { - Result += mOutput[mIndex]; - mIndex++; - } - return Result; -} - -QString DebugReader::getRemainingLine() -{ - QString Result; - - // Return part of line still ahead of us - while (mIndexfindWatchVar(watchName); - if (watchVar) { - // Advance up to the value - if (!findAnnotation(AnnotationType::TDisplayExpression)) - return;; - // Refresh GDB index so we can undisplay this by index - watchVar->gdbIndex = s.toInt(); - mDebugger->notifyBeforeProcessWatchVar(); - processWatchOutput(watchVar); - mDebugger->notifyAfterProcessWatchVar(); - //mDebugger->notifyWatchVarUpdated(watchVar); - } -} - -void DebugReader::handleError() -{ - QString s = getNextLine(); // error text - if (s.startsWith("Cannot find bounds of current function")) { - //We have exited - handleExit(); - } else if (s.startsWith("No symbol \"")) { - int head = s.indexOf('\"'); - int tail = s.lastIndexOf('\"'); - QString watchName = s.mid(head+1, tail-head-1); - - // Update current.. - mDebugger->invalidateWatchVar(watchName); - } -} - -void DebugReader::handleExit() -{ - doprocessexited=true; -} - -void DebugReader::handleFrames() -{ - QString s = getNextLine(); - - // Is this a backtrace dump? - if (s.startsWith("#")) { - if (s.startsWith("#0")) { - mDebugger->backtraceModel()->clear(); - } - // Find function name - if (!findAnnotation(AnnotationType::TFrameFunctionName)) - return; - - PTrace trace = std::make_shared(); - trace->funcname = getNextLine(); - - // Find argument list start - if (!findAnnotation(AnnotationType::TFrameArgs)) - return; - - // Arguments are either () or detailed list - s = getNextLine(); - - while (peekNextAnnotation() == AnnotationType::TArgBegin) { - - // argument name - if (!findAnnotation(AnnotationType::TArgBegin)) - return; - - s = s + getNextLine(); - - // = - if (!findAnnotation(AnnotationType::TArgNameEnd)) - return; - s = s + ' ' + getNextLine() + ' '; // should be = - - // argument value - if (!findAnnotation(AnnotationType::TArgValue)) - return; - - s = s + getNextLine(); - - // argument end - if (!findAnnotation(AnnotationType::TArgEnd)) - return; - - s = s + getNextLine(); - } - - trace->funcname = trace->funcname + s.trimmed(); - - // source info - if (peekNextAnnotation() == AnnotationType::TFrameSourceBegin) { - // Find filename - if (!findAnnotation(AnnotationType::TFrameSourceFile)) - return; - trace->filename = getNextLine(); - // find line - if (!findAnnotation(AnnotationType::TFrameSourceLine)) - return; - trace->line = getNextLine().trimmed().toInt(); - } else { - trace->filename = ""; - trace->line = 0; - } - mDebugger->backtraceModel()->addTrace(trace); - - // Skip over the remaining frame part... - if (!findAnnotation(AnnotationType::TFrameEnd)) - return; - - // Not another one coming? Done! - if (peekNextAnnotation() != AnnotationType::TFrameBegin) { - // End of stack trace dump! - dobacktraceready = true; - } - } else - doupdatecpuwindow = true; -} - -void DebugReader::handleLocalOutput() -{ - // name(spaces)hexvalue(tab)decimalvalue - QString s = getNextFilledLine(); - - bool nobreakLine = false; - QString line; - while (true) { - if (!s.startsWith("\032\032")) { - s = TrimLeft(s); - if (s == "No locals.") { - return; - } - if (s == "No arguments.") { - return; - } - //todo: update local view - if (nobreakLine && pMainWindow->txtLocals()->document()->lineCount()>0) { - line += s; -// emit addLocalWithoutLinebreak(s); + if (line.length()>3 && line.startsWith("~\"") && line.endsWith("\"")) { + QByteArray s=line.mid(2,line.length()-3); + QByteArray stringValue; + const char *p=s.data(); + while (*p!=0) { + if (*p=='\\' && *(p+1)!=0) { + p++; + switch (*p) { + case '\'': + stringValue+=0x27; + p++; + break; + case '"': + stringValue+=0x22; + p++; + break; + case '?': + stringValue+=0x3f; + p++; + break; + case '\\': + stringValue+=0x5c; + p++; + break; + case 'a': + stringValue+=0x07; + p++; + break; + case 'b': + stringValue+=0x08; + p++; + break; + case 'f': + stringValue+=0x0c; + p++; + break; + case 'n': + stringValue+=0x0a; + p++; + break; + case 'r': + stringValue+=0x0d; + p++; + break; + case 't': + stringValue+=0x09; + p++; + break; + case 'v': + stringValue+=0x0b; + p++; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + int i=0; + for (i=0;i<3;i++) { + if (*(p+i)<'0' || *(p+i)>'7') + break; + } + QByteArray numStr(p,i); + bool ok; + unsigned char ch = numStr.toInt(&ok,8); + stringValue+=ch; + p+=i; + break; + } + } } else { - mLocalsValue.append(line); - line = s; + stringValue+=*p; + p++; } - nobreakLine=false; - } else { - nobreakLine = true; } - s = getNextLine(); - if (!nobreakLine && s.isEmpty()) - break; - } - if (!line.isEmpty()) { - mLocalsValue.append(line); + mConsoleOutput.append(QString::fromLocal8Bit(stringValue)); } } -void DebugReader::handleLocals() +void DebugReader::processResult(const QByteArray &result) { - mLocalsValue.clear(); - handleLocalOutput(); + GDBMIResultParser parser; + GDBMIResultType resultType; + GDBMIResultParser::ParseObject multiValues; + if (!mCurrentCmd) + return; + bool parseOk = parser.parse(result, mCurrentCmd->command, resultType,multiValues); + if (!parseOk) + return; + switch(resultType) { + case GDBMIResultType::BreakpointTable: + case GDBMIResultType::Frame: + case GDBMIResultType::Locals: + break; + case GDBMIResultType::Breakpoint: + handleBreakpoint(multiValues["bkpt"].object()); + return; + case GDBMIResultType::FrameStack: + handleStack(multiValues["stack"].array()); + return; + case GDBMIResultType::LocalVariables: + handleLocalVariables(multiValues["variables"].array()); + return; + case GDBMIResultType::Evaluation: + handleEvaluation(multiValues["value"].value()); + return; + case GDBMIResultType::Memory: + handleMemory(multiValues["memory"].array()); + return; + case GDBMIResultType::RegisterNames: + handleRegisterNames(multiValues["register-names"].array()); + return; + 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; + } + } -void DebugReader::handleMemory() +void DebugReader::processExecAsyncRecord(const QByteArray &line) { - doupdatememoryview = true; - // name(spaces)hexvalue(tab)decimalvalue - mMemoryValue.clear(); - QString s = getNextFilledLine(); - bool isAnnotation = false; - while (true) { - if (!s.startsWith("\032\032")) { - s = s.trimmed(); - if (!s.isEmpty()) { - mMemoryValue.append(s); - } - isAnnotation = false; - } else { - isAnnotation = true; + QByteArray result; + GDBMIResultParser::ParseObject multiValues; + GDBMIResultParser parser; + if (!parser.parseAsyncResult(line,result,multiValues)) + return; + if (result == "running") { + mInferiorRunning = true; + mCurrentAddress=0; + mCurrentFile.clear(); + mCurrentLine=-1; + mCurrentFunc.clear(); + emit inferiorContinued(); + return; + } + if (result == "stopped") { + mInferiorRunning = false; + QByteArray reason = multiValues["reason"].value(); + if (reason == "exited") { + //inferior exited, gdb should terminate too + mProcessExited = true; + return; } - s = getNextLine(); - if (!isAnnotation && s.isEmpty()) - break; - } -} - -void DebugReader::handleParams(){ - handleLocalOutput(); - doupdatelocal = true; -} - -void DebugReader::handleRegisters() -{ - // name(spaces)hexvalue(tab)decimalvalue - QString s = getNextFilledLine(); - - while (true) { - PRegister reg = std::make_shared(); - // Cut name from 1 to first space - int x = s.indexOf(' '); - reg->name = s.mid(0,x); - s.remove(0,x); - // Remove spaces - s = TrimLeft(s); - - // Cut hex value from 1 to first tab - x = s.indexOf('\t'); - if (x<0) - x = s.indexOf(' '); - reg->hexValue = s.mid(0,x); - s.remove(0,x); // delete tab too - s = TrimLeft(s); - - // Remaining part contains decimal value - reg->decValue = s; - - if (!reg->name.trimmed().isEmpty()) - mRegisters.append(reg); - s = getNextLine(); - if (s.isEmpty()) - break; - } - - doregistersready = true; -} - -void DebugReader::handleSignal() -{ - mSignal = getNextFilledLine(); // Program received signal - - if (!findAnnotation(AnnotationType::TSignalName)) - return; - - mSignal = mSignal + getNextFilledLine(); // signal code - - if (!findAnnotation(AnnotationType::TSignalNameEnd)) - return; - - mSignal = mSignal + getNextFilledLine(); // comma - - if (!findAnnotation(AnnotationType::TSignalString)) - return; - - mSignal = mSignal + getNextFilledLine(); // user friendly description - - if (!findAnnotation(AnnotationType::TSignalStringEnd)) - return; - - mSignal = mSignal + getNextFilledLine(); // period - - doreceivedsignal = true; -} - -void DebugReader::handleSource() -{ - // source filename:line:offset:beg/middle/end:addr - QString s = TrimLeft(getRemainingLine()); - - // remove offset, beg/middle/end, address - for (int i=0;i<3;i++) { - int delimPos = s.lastIndexOf(':'); - if (delimPos >= 0) - s.remove(delimPos,INT_MAX); + if (reason == "exited-normally") { + //inferior exited, gdb should terminate too + mProcessExited = true; + return; + } + if (reason == "exited-signalled") { + //inferior exited, gdb should terminate too + mProcessExited = true; + mSignalReceived = true; + return; + } + mUpdateCPUInfo = true; + GDBMIResultParser::ParseValue frame(multiValues["frame"]); + if (frame.isValid()) { + GDBMIResultParser::ParseObject frameObj = frame.object(); + mCurrentAddress = frameObj["addr"].hexValue(); + mCurrentLine = frameObj["line"].intValue(); + mCurrentFile = frameObj["fullname"].pathValue(); + mCurrentFunc = frameObj["func"].value(); + } + if (reason == "signal-received") { + mSignalReceived = true; + mSignalName = multiValues["signal-name"].value(); + mSignalMeaning = multiValues["signal-meaning"].value(); + } + runInferiorStoppedHook(); + if (mCurrentCmd && mCurrentCmd->source == DebugCommandSource::Console) + emit inferiorStopped(mCurrentFile, mCurrentLine,false); else - return; // Wrong format. Don't bother to continue + emit inferiorStopped(mCurrentFile, mCurrentLine,true); } +} - // get line - int delimPos = s.lastIndexOf(':'); - if (delimPos >= 0) { - mBreakPointLine = s.mid(delimPos+1).toInt(); - s.remove(delimPos, INT_MAX); +void DebugReader::processError(const QByteArray &errorLine) +{ + mConsoleOutput.append(QString::fromLocal8Bit(errorLine)); +} + +void DebugReader::processResultRecord(const QByteArray &line) +{ + if (line.startsWith("^exit")) { + mProcessExited = true; + return; + } + if (line.startsWith("^error")) { + processError(line); + return; + } + if (line.startsWith("^done") + || line.startsWith("^running")) { + int pos = line.indexOf(','); + if (pos>=0) { + QByteArray result = line.mid(pos+1); + processResult(result); + } else if (mCurrentCmd && !(mCurrentCmd->command.startsWith('-'))) { + if (mCurrentCmd->command == "disas") { + QStringList disOutput = mConsoleOutput; + if (disOutput.length()>=3) { + disOutput.pop_back(); + disOutput.pop_front(); + disOutput.pop_front(); + } + emit disassemblyUpdate(mCurrentFile,mCurrentFunc, disOutput); + } + } + return ; + } + if (line.startsWith("^connected")) { + //TODO: connected to remote target + return; } - - // get file - mBreakPointFile = s; - - doupdateexecution = true; - doupdatecpuwindow = true; } -void DebugReader::handleValueHistoryValue() -{ - mEvalValue = processEvalOutput(); - doevalready = true; -} - -AnnotationType DebugReader::peekNextAnnotation() -{ - int indexBackup = mIndex; // do NOT modifiy curpos - AnnotationType result = getNextAnnotation(); - mIndex = indexBackup; - return result; -} - -void DebugReader::processDebugOutput() +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(); - //try + mConsoleOutput.clear(); + mFullOutput.clear(); - dobacktraceready = false; - dodisassemblerready = false; - doregistersready = false; - doevalready = false; - doupdatememoryview = false; - doupdatelocal = false; - doprocessexited = false; - doupdateexecution = false; - doreceivedsignal = false; - doupdatecpuwindow = false; - doreceivedsfwarning = false; + mSignalReceived = false; + mUpdateCPUInfo = false; + mReceivedSFWarning = false; + QList lines = splitByteArrayToLines(debugOutput); - // Global checks - if (mOutput.indexOf("warning: Source file is more recent than executable.") >= 0) - doreceivedsfwarning = true; - - mIndex = 0; - AnnotationType nextAnnotation; - do { - nextAnnotation = getNextAnnotation(); - switch(nextAnnotation) { - case AnnotationType::TValueHistoryValue: - handleValueHistoryValue(); - break; - case AnnotationType::TSignal: - handleSignal(); - break; - case AnnotationType::TExit: - handleExit(); - break; - case AnnotationType::TFrameBegin: - handleFrames(); - break; - case AnnotationType::TInfoAsm: - handleDisassembly(); - break; - case AnnotationType::TInfoReg: - handleRegisters(); - break; - case AnnotationType::TLocal: - handleLocals(); - break; - case AnnotationType::TParam: - handleParams(); - break; - case AnnotationType::TMemory: - handleMemory(); - break; - case AnnotationType::TErrorBegin: - handleError(); - break; - case AnnotationType::TDisplayBegin: - handleDisplay(); - break; - case AnnotationType::TSource: - handleSource(); - break; - default: - break; - } - } while (nextAnnotation != AnnotationType::TEOF); - - // Only update once per update at most - //finally - //WatchView.Items.EndUpdate; - //end; - - emit parseFinished(); -} - -QString DebugReader::processEvalOutput() -{ - int indent = 0; - - // First line gets special treatment - QString result = getNextLine(); - 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++; + for (int i=0;idebugger().showDetailLog()) + mFullOutput.append(line); + line = removeToken(line); + if (line.isEmpty()) { + continue; + } + switch (line[0]) { + case '~': // console stream output + processConsoleOutput(line); + break; + case '@': // target stream output + case '&': // log stream output + break; + case '^': // result record + processResultRecord(line); + break; + case '*': // exec async output + processExecAsyncRecord(line); + break; + case '+': // status async output + case '=': // notify async output + break; + } } - // add placeholder name for variable name so we can format structs using one rule + emit parseFinished(); + mConsoleOutput.clear(); + mFullOutput.clear(); +} - // 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::runInferiorStoppedHook() +{ + foreach (const PDebugCommand& cmd, mInferiorStoppedHookCommands) { + mCmdQueue.push_front(cmd); + } } void DebugReader::runNextCmd() { - bool doUpdate=false; - - auto action = finally([this,&doUpdate] { - if (doUpdate) { - emit updateWatch(); - } - }); QMutexLocker locker(&mCmdQueueMutex); - if (mCmdQueue.isEmpty()) { - if ((mCurrentCmd) && (mCurrentCmd->updateWatch)) { - doUpdate=true; - if (mUpdateCount>0) { - mUpdateCount=0; - } - emit cmdFinished(); - } - return; - } if (mCurrentCmd) { mCurrentCmd.reset(); + emit cmdFinished(); } + if (mCmdQueue.isEmpty()) + return; PDebugCommand pCmd = mCmdQueue.dequeue(); mCmdRunning = true; mCurrentCmd = pCmd; - if (mCurrentCmd->updateWatch) - emit cmdStarted(); + 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(); } // if devDebugger.ShowCommandLog or pCmd^.ShowInConsole then begin - if (pSettings->debugger().showCommandLog() || pCmd->showInConsole) { + if (pSettings->debugger().enableDebugConsole() ) { //update debug console - // if not devDebugger.ShowAnnotations then begin - if (!pSettings->debugger().showAnnotations()) { -// if MainForm.DebugOutput.Lines.Count>0 then begin -// MainForm.DebugOutput.Lines.Delete(MainForm.DebugOutput.Lines.Count-1); -// end; - emit changeDebugConsoleLastLine("(gdb)"+pCmd->command + ' ' + pCmd->params); -// MainForm.DebugOutput.Lines.Add('(gdb)'+pCmd^.Cmd + ' ' + pCmd^.params); -// MainForm.DebugOutput.Lines.Add(''); - } else { - emit changeDebugConsoleLastLine("(gdb)"+pCmd->command + ' ' + pCmd->params); -// MainForm.DebugOutput.Lines.Add(pCmd^.Cmd + ' ' + pCmd^.params); -// MainForm.DebugOutput.Lines.Add(''); + if (pSettings->debugger().showDetailLog() + && pCmd->source != DebugCommandSource::Console) { + emit changeDebugConsoleLastLine(pCmd->command + ' ' + params); } } } -void DebugReader::skipSpaces() -{ - while (mIndex < mOutput.length() && - (mOutput[mIndex]=='\t' || mOutput[mIndex]==' ')) - mIndex++; -} - -void DebugReader::skipToAnnotation() -{ - // Walk up to the next annotation - while (mIndex < mOutput.length() && - (mOutput[mIndex]!=26)) - mIndex++; - // Crawl through the remaining ->'s - while (mIndex < mOutput.length() && - (mOutput[mIndex]==26)) - mIndex++; -} - QStringList DebugReader::tokenize(const QString &s) { QStringList result; @@ -1593,14 +1038,218 @@ QStringList DebugReader::tokenize(const QString &s) return result; } -bool DebugReader::invalidateAllVars() const +bool DebugReader::outputTerminated(const QByteArray &text) { - return mInvalidateAllVars; + QStringList lines = textToLines(QString::fromUtf8(text)); + foreach (const QString& line,lines) { + if (line.trimmed() == "(gdb)") + return true; + } + return false; } -void DebugReader::setInvalidateAllVars(bool invalidateAllVars) +void DebugReader::handleBreakpoint(const GDBMIResultParser::ParseObject& breakpoint) { - mInvalidateAllVars = invalidateAllVars; + // gdb use system encoding for file path + QString filename = breakpoint["fullname"].pathValue(); + int line = breakpoint["line"].intValue(); + int number = breakpoint["number"].intValue(); + emit breakpointInfoGetted(filename, line , number); +} + +void DebugReader::handleStack(const QList & stack) +{ + mDebugger->backtraceModel()->clear(); + foreach (const GDBMIResultParser::ParseValue& frameValue, stack) { + GDBMIResultParser::ParseObject frameObject = frameValue.object(); + PTrace trace = std::make_shared(); + trace->funcname = frameObject["func"].value(); + trace->filename = frameObject["fullname"].pathValue(); + trace->line = frameObject["line"].intValue(); + trace->level = frameObject["level"].intValue(0); + trace->address = frameObject["addr"].value(); + mDebugger->backtraceModel()->addTrace(trace); + } +} + +void DebugReader::handleLocalVariables(const QList &variables) +{ + QStringList locals; + foreach (const GDBMIResultParser::ParseValue& varValue, variables) { + GDBMIResultParser::ParseObject varObject = varValue.object(); + locals.append(QString("%1 = %2") + .arg(varObject["name"].value(),varObject["value"].value())); + } + emit localsUpdated(locals); +} + +void DebugReader::handleEvaluation(const QString &value) +{ + emit evalUpdated(value); +} + +void DebugReader::handleMemory(const QList &rows) +{ + QStringList memory; + foreach (const GDBMIResultParser::ParseValue& row, rows) { + GDBMIResultParser::ParseObject rowObject = row.object(); + QList data = rowObject["data"].array(); + QStringList values; + foreach (const GDBMIResultParser::ParseValue& val, data) { + values.append(val.value()); + } + memory.append(QString("%1 %2") + .arg(rowObject["addr"].value(),values.join(" "))); + } + emit memoryUpdated(memory); +} + +void DebugReader::handleRegisterNames(const QList &names) +{ + QStringList nameList; + foreach (const GDBMIResultParser::ParseValue& nameValue, names) { + nameList.append(nameValue.value()); + } + emit registerNamesUpdated(nameList); +} + +void DebugReader::handleRegisterValue(const QList &values) +{ + QHash result; + foreach (const GDBMIResultParser::ParseValue& val, values) { + GDBMIResultParser::ParseObject obj = val.object(); + int number = obj["number"].intValue(); + QString value = obj["value"].value(); + bool ok; + long long intVal; + intVal = value.toLongLong(&ok,10); + if (ok) { + value = QString("0x%1").arg(intVal,0,16); + } + result.insert(number,value); + } + 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; + while (p'9') { + break; + } + p++; + } + if (pstart(); mProcess->waitForStarted(5000); mStartSemaphore.release(1); - while (true) { mProcess->waitForFinished(1); if (mProcess->state()!=QProcess::Running) { @@ -1680,9 +1334,9 @@ void DebugReader::run() break; readed = mProcess->readAll(); buffer += readed; - if (getLastAnnotation(buffer) == AnnotationType::TPrompt) { - mOutput = QString::fromLocal8Bit(buffer); - processDebugOutput(); + + if (readed.endsWith("\n")&& outputTerminated(buffer)) { + processDebugOutput(buffer); buffer.clear(); mCmdRunning = false; runNextCmd(); @@ -1697,8 +1351,6 @@ void DebugReader::run() } } - - BreakpointModel::BreakpointModel(QObject *parent):QAbstractTableModel(parent) { @@ -1794,6 +1446,14 @@ void BreakpointModel::removeBreakpoint(int row) endRemoveRows(); } +void BreakpointModel::invalidateAllBreakpointNumbers() +{ + foreach (PBreakpoint bp,mList) { + bp->number = -1; + } + //emit dateChanged(createIndex(0,0),) +} + PBreakpoint BreakpointModel::setBreakPointCondition(int index, const QString &condition) { PBreakpoint breakpoint = mList[index]; @@ -1873,7 +1533,17 @@ void BreakpointModel::load(const QString &filename) } } -void BreakpointModel::onFileDeleteLines(const QString &filename, int startLine, int count) +void BreakpointModel::updateBreakpointNumber(const QString& filename, int line, int number) +{ + foreach (PBreakpoint bp, mList) { + if (bp->filename == filename && bp->line == line) { + bp->number = number; + return; + } + } +} + +void BreakpointModel::onFileDeleteLines(const QString& filename, int startLine, int count) { for (int i = mList.count()-1;i>=0;i--){ PBreakpoint breakpoint = mList[i]; @@ -1889,7 +1559,7 @@ void BreakpointModel::onFileDeleteLines(const QString &filename, int startLine, } } -void BreakpointModel::onFileInsertLines(const QString &filename, int startLine, int count) +void BreakpointModel::onFileInsertLines(const QString& filename, int startLine, int count) { for (int i = mList.count()-1;i>=0;i--){ PBreakpoint breakpoint = mList[i]; @@ -2008,11 +1678,12 @@ 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->name; + return item->expression; case 1: + return item->type; + case 2: return item->value; } } @@ -2023,7 +1694,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()) { @@ -2083,42 +1753,30 @@ int WatchModel::rowCount(const QModelIndex &parent) const int WatchModel::columnCount(const QModelIndex&) const { - return 2; + return 3; } void WatchModel::addWatchVar(PWatchVar watchVar) { for (PWatchVar var:mWatchVars) { - if (watchVar->name == var->name) { + if (watchVar->expression == var->expression) { 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 &name) +void WatchModel::removeWatchVar(const QString &express) { for (int i=mWatchVars.size()-1;i>=0;i--) { PWatchVar var = mWatchVars[i]; - if (name == var->name) { - this->beginResetModel(); - //this->beginRemoveRows(QModelIndex(),i,i); - mWatchVars.removeAt(i); - //this->endRemoveRows(); - this->endResetModel(); - } - } -} - -void WatchModel::removeWatchVar(int gdbIndex) -{ - for (int i=mWatchVars.size()-1;i>=0;i--) { - PWatchVar var = mWatchVars[i]; - if (gdbIndex == var->gdbIndex) { + 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(); @@ -2130,6 +1788,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(); } @@ -2146,24 +1807,130 @@ 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(); + } + 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; + if (var->children.count()>0) { + beginRemoveRows(index(var),0,var->children.count()-1); + var->children.clear(); + endRemoveRows(); } } - return PWatchVar(); +} + +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); + bool oldHasMore = var->hasMore; + var->hasMore = hasMore; + if (newNumChildren>=0 + && var->numChild!=newNumChildren) { + var->numChild = newNumChildren; + fetchMore(idx); + } else if (!oldHasMore && hasMore) { + fetchMore(idx); + } + 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() @@ -2205,7 +1972,7 @@ void WatchModel::save(const QString &filename) QJsonArray array; foreach (const PWatchVar& watchVar, mWatchVars) { QJsonObject obj; - obj["name"]=watchVar->name; + obj["expression"]=watchVar->expression; array.append(obj); } QJsonDocument doc; @@ -2242,9 +2009,11 @@ void WatchModel::load(const QString &filename) QJsonObject obj=value.toObject(); PWatchVar var = std::make_shared(); var->parent= nullptr; - var->name = obj["name"].toString(); + var->expression = obj["expression"].toString(); var->value = tr("Execute to evaluate"); - var->gdbIndex = -1; + var->numChild = 0; + var->hasMore=false; + var->parent = nullptr; addWatchVar(var); } @@ -2254,6 +2023,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 +{ + if (!parent.isValid()) { + return false; + } + WatchVar* item = static_cast(parent.internalPointer()); + return item->numChild>item->children.count() || item->hasMore; +} + +bool WatchModel::hasChildren(const QModelIndex &parent) const +{ + if (!parent.isValid()) { + return true; + } + WatchVar* item = static_cast(parent.internalPointer()); + return item->numChild>0; +} + RegisterModel::RegisterModel(QObject *parent):QAbstractTableModel(parent) { @@ -2275,32 +2110,27 @@ RegisterModel::RegisterModel(QObject *parent):QAbstractTableModel(parent) int RegisterModel::rowCount(const QModelIndex &) const { - return mRegisters.count(); + return mRegisterNames.count(); } int RegisterModel::columnCount(const QModelIndex &) const { - return 3; + return 2; } QVariant RegisterModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); - if (index.row()<0 || index.row() >= static_cast(mRegisters.size())) - return QVariant(); - PRegister reg = mRegisters[index.row()]; - if (!reg) + if (index.row()<0 || index.row() >= static_cast(mRegisterNames.size())) return QVariant(); switch (role) { case Qt::DisplayRole: switch (index.column()) { case 0: - return reg->name; + return mRegisterNames[index.row()]; case 1: - return reg->hexValue; - case 2: - return reg->decValue; + return mRegisterValues.value(index.row(),""); default: return QVariant(); } @@ -2316,26 +2146,31 @@ QVariant RegisterModel::headerData(int section, Qt::Orientation orientation, int case 0: return tr("Register"); case 1: - return tr("Value(Hex)"); - case 2: - return tr("Value(Dec)"); + return tr("Value"); } } return QVariant(); } -void RegisterModel::update(const QList ®s) +void RegisterModel::updateNames(const QStringList ®Names) { beginResetModel(); - mRegisters.clear(); - mRegisters.append(regs); + mRegisterNames = regNames; endResetModel(); } +void RegisterModel::updateValues(const QHash registerValues) +{ + mRegisterValues= registerValues; + emit dataChanged(createIndex(0,1), + createIndex(mRegisterNames.count()-1,1)); +} + void RegisterModel::clear() { beginResetModel(); - mRegisters.clear(); + mRegisterNames.clear(); + mRegisterValues.clear(); endResetModel(); } diff --git a/RedPandaIDE/debugger.h b/RedPandaIDE/debugger.h index 5e88a14a..f08ce6e0 100644 --- a/RedPandaIDE/debugger.h +++ b/RedPandaIDE/debugger.h @@ -13,37 +13,16 @@ #include #include #include +#include "gdbmiresultparser.h" + enum class DebugCommandSource { Console, Other }; -enum class AnnotationType { - TPrePrompt, TPrompt, TPostPrompt, - TSource, - TDisplayBegin, TDisplayEnd, - TDisplayExpression, - TFrameSourceFile, TFrameSourceBegin, TFrameSourceLine, TFrameFunctionName, TFrameWhere, - TFrameArgs, - TFrameBegin, TFrameEnd, - TErrorBegin, TErrorEnd, - TArrayBegin, TArrayEnd, - TElt, TEltRep, TEltRepEnd, - TExit, - TSignal, TSignalName, TSignalNameEnd, TSignalString, TSignalStringEnd, - TValueHistoryValue, TValueHistoryBegin, TValueHistoryEnd, - TArgBegin, TArgEnd, TArgValue, TArgNameEnd, - TFieldBegin, TFieldEnd, TFieldValue, TFieldNameEnd, - TInfoReg, TInfoAsm, - TUnknown, TEOF, - TLocal, TParam, TMemory -}; - struct DebugCommand{ QString command; QString params; - bool updateWatch; - bool showInConsole; DebugCommandSource source; }; @@ -52,14 +31,19 @@ struct WatchVar; using PWatchVar = std::shared_ptr; struct WatchVar { QString name; + QString expression; + bool hasMore; QString value; - QString fullName; - int gdbIndex; + QString type; + int numChild; QList children; WatchVar * parent; //use raw point to prevent circular-reference }; struct Breakpoint { + int number; // breakpoint number + QString type; // type of the breakpoint + QString catch_type; int line; QString filename; QString condition; @@ -71,19 +55,13 @@ using PBreakpoint = std::shared_ptr; struct Trace { QString funcname; QString filename; + QString address; int line; + int level; }; using PTrace = std::shared_ptr; -struct Register { - QString name; - QString hexValue; - QString decValue; -}; - -using PRegister = std::shared_ptr; - class RegisterModel: public QAbstractTableModel { Q_OBJECT public: @@ -92,10 +70,12 @@ public: int columnCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - void update(const QList& regs); + void updateNames(const QStringList& regNames); + void updateValues(const QHash registerValues); void clear(); private: - QList mRegisters; + QStringList mRegisterNames; + QHash mRegisterValues; }; class BreakpointModel: public QAbstractTableModel { @@ -116,6 +96,8 @@ public: void save(const QString& filename); void load(const QString& filename); public slots: + void updateBreakpointNumber(const QString& filename, int line, int number); + void invalidateAllBreakpointNumbers(); // call this when gdb is stopped void onFileDeleteLines(const QString& filename, int startLine, int count); void onFileInsertLines(const QString& filename, int startLine, int count); private: @@ -149,29 +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& name); - void removeWatchVar(int gdbIndex); + 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; }; @@ -188,10 +192,9 @@ public: // Play/pause bool start(); void sendCommand(const QString& command, const QString& params, - bool updateWatch = true, - bool showInConsole = false, DebugCommandSource source = DebugCommandSource::Other); bool commandRunning(); + bool inferiorRunning(); //breakpoints void addBreakpoint(int line, const Editor* editor); @@ -208,27 +211,14 @@ public: void sendAllBreakpointsToDebugger(); //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(); - - - void updateDebugInfo(); - - bool useUTF8() const; - void setUseUTF8(bool useUTF8); BacktraceModel* backtraceModel(); BreakpointModel* breakpointModel(); @@ -257,14 +247,19 @@ private: private slots: void syncFinishedParsing(); + void updateMemory(const QStringList& value); + void updateEval(const QString& value); + void updateDisassembly(const QString& file, const QString& func,const QStringList& value); void onChangeDebugConsoleLastline(const QString& text); void clearUpReader(); - + void updateRegisterNames(const QStringList& registerNames); + void updateRegisterValues(const QHash& values); + void refreshWatchVars(); + void fetchVarChildren(const QString& varName); private: bool mExecuting; bool mCommandChanged; BreakpointModel *mBreakpointModel; - bool mUseUTF8; BacktraceModel *mBacktraceModel; WatchModel *mWatchModel; RegisterModel *mRegisterModel; @@ -277,102 +272,145 @@ class DebugReader : public QThread Q_OBJECT public: explicit DebugReader(Debugger* debugger, QObject *parent = nullptr); - void postCommand(const QString &Command, const QString &Params, - bool UpdateWatch, bool ShowInConsole, DebugCommandSource Source); + void postCommand(const QString &Command, const QString &Params, DebugCommandSource Source); + void registerInferiorStoppedCommand(const QString &Command, const QString &Params); QString debuggerPath() const; void setDebuggerPath(const QString &debuggerPath); void stopDebug(); bool commandRunning(); + void waitStart(); - bool invalidateAllVars() const; - void setInvalidateAllVars(bool invalidateAllVars); + bool inferiorPaused() const; + + bool processExited() const; + + bool signalReceived() const; + + const QStringList &consoleOutput() const; + + int breakPointLine() const; + + const QString &breakPointFile() const; + + const PDebugCommand ¤tCmd() const; + + bool updateCPUInfo() const; + + bool updateLocals() const; + + const QStringList &localsValue() const; + + bool evalReady() const; + + const QString &evalValue() const; + + bool updateMemory() const; + + const QStringList &memoryValue() const; + + bool receivedSFWarning() const; + + const QStringList &fullOutput() const; + + bool inferiorRunning() const; + + const QString &signalName() const; + + const QString &signalMeaning() const; signals: void parseStarted(); void invalidateAllVars(); void parseFinished(); void writeToDebugFailed(); - void pauseWatchUpdate(); - void updateWatch(); void processError(QProcess::ProcessError error); void changeDebugConsoleLastLine(const QString& text); void cmdStarted(); void cmdFinished(); + + void breakpointInfoGetted(const QString& filename, int line, int number); + void inferiorContinued(); + void inferiorStopped(const QString& filename, int line, bool setFocus); + void localsUpdated(const QStringList& localsValue); + void evalUpdated(const QString& value); + void memoryUpdated(const QStringList& memoryValues); + 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(); - bool findAnnotation(AnnotationType annotation); - AnnotationType getAnnotation(const QString& s); - AnnotationType getLastAnnotation(const QByteArray& text); - AnnotationType getNextAnnotation(); - QString getNextFilledLine(); - QString getNextLine(); - QString getNextWord(); - QString getRemainingLine(); - void handleDisassembly(); - void handleDisplay(); - void handleError(); - void handleExit(); - void handleFrames(); - void handleLocalOutput(); - void handleLocals(); - void handleMemory(); - void handleParams(); - void handleRegisters(); - void handleSignal(); - void handleSource(); - void handleValueHistoryValue(); - AnnotationType peekNextAnnotation(); - void processDebugOutput(); - QString processEvalOutput(); - void processWatchOutput(PWatchVar WatchVar); + void runNextCmd(); - void skipSpaces(); - void skipToAnnotation(); QStringList tokenize(const QString& s); + + bool outputTerminated(const QByteArray& text); + void handleBreakpoint(const GDBMIResultParser::ParseObject& breakpoint); + void handleStack(const QList & stack); + void handleLocalVariables(const QList & variables); + void handleEvaluation(const QString& value); + 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); + void processError(const QByteArray& errorLine); + void processResultRecord(const QByteArray& line); + void processDebugOutput(const QByteArray& debugOutput); + void runInferiorStoppedHook(); + QByteArray removeToken(const QByteArray& line); private: Debugger *mDebugger; QString mDebuggerPath; QRecursiveMutex mCmdQueueMutex; QSemaphore mStartSemaphore; QQueue mCmdQueue; - int mUpdateCount; - bool mInvalidateAllVars; //fOnInvalidateAllVars: TInvalidateAllVarsEvent; bool mCmdRunning; PDebugCommand mCurrentCmd; - QList mRegisters; - QStringList mDisassembly; - QProcess* mProcess; //fWatchView: TTreeView; - int mIndex; - int mBreakPointLine; - QString mBreakPointFile; - QString mOutput; - QString mEvalValue; - QStringList mMemoryValue; - QStringList mLocalsValue; - QString mSignal; - bool mUseUTF8; - // attempt to cut down on Synchronize calls - bool dobacktraceready; - bool dodisassemblerready; - bool doregistersready; - bool doevalready; - bool doprocessexited; - bool doupdatecpuwindow; - bool doupdateexecution; - bool doreceivedsignal; - bool doreceivedsfwarning; - bool doupdatememoryview; - bool doupdatelocal; + QString mSignalName; + QString mSignalMeaning; + // + QList mInferiorStoppedHookCommands; + bool mInferiorRunning; + bool mProcessExited; + + bool mSignalReceived; + bool mUpdateCPUInfo; + bool mReceivedSFWarning; + + int mCurrentLine; + int mCurrentAddress; + QString mCurrentFunc; + QString mCurrentFile; + QStringList mConsoleOutput; + QStringList mFullOutput; bool mStop; - friend class Debugger; // QThread interface protected: void run() override; diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index 5755af9e..ddd6f852 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -604,12 +604,12 @@ void Editor::keyPressEvent(QKeyEvent *event) insertString.append(QString(" * ")+USER_CODE_IN_INSERT_POS); insertString.append(" */"); } - insertCodeSnippet(LinesToText(insertString)); + insertCodeSnippet(linesToText(insertString)); } else if (highlighter() && caretY()>=2 && highlighter()->isLastLineCommentNotFinished( lines()->ranges(caretY()-2).state)) { - s=TrimLeft(lineText()); + s=trimLeft(lineText()); if (s.startsWith("* ")) { handled = true; int right = lines()->getString(caretY()-1).length()-caretX(); @@ -1513,7 +1513,7 @@ void Editor::onGutterClicked(Qt::MouseButton button, int , int , int line) mGutterClickedLine = line; } -void Editor::onTipEvalValueReady(const QString &value) +void Editor::onTipEvalValueReady(const QString& value) { if (mCurrentWord == mCurrentDebugTipWord) { QString newValue; @@ -2142,7 +2142,7 @@ void Editor::insertCodeSnippet(const QString &code) auto action = finally([this]{ endUpdate(); }); - QStringList sl = TextToLines(parseMacros(code)); + QStringList sl = textToLines(parseMacros(code)); int lastI=0; int spaceCount = GetLeftSpacing( leftSpaces(lineText()),true).length(); @@ -2196,7 +2196,7 @@ void Editor::insertCodeSnippet(const QString &code) } BufferCoord cursorPos = caretXY(); - QString s = LinesToText(newSl); + QString s = linesToText(newSl); // if EndsStr(#13#10,s) then // Delete(s,Length(s)-1,2) // else if EndsStr(#10, s) then @@ -2826,7 +2826,7 @@ void Editor::showDebugHint(const QString &s, int line) connect(pMainWindow->debugger(), &Debugger::evalValueReady, this, &Editor::onTipEvalValueReady); mCurrentDebugTipWord = s; - pMainWindow->debugger()->sendCommand("print",s,false); + pMainWindow->debugger()->sendCommand("-data-evaluate-expression",s); } QString Editor::getErrorHint(const PSyntaxIssue& issue) diff --git a/RedPandaIDE/gdbmiresultparser.cpp b/RedPandaIDE/gdbmiresultparser.cpp new file mode 100644 index 00000000..d6767850 --- /dev/null +++ b/RedPandaIDE/gdbmiresultparser.cpp @@ -0,0 +1,470 @@ +#include "gdbmiresultparser.h" + +#include +#include +#include + +GDBMIResultParser::GDBMIResultParser() +{ + mResultTypes.insert("-break-insert",GDBMIResultType::Breakpoint); + //mResultTypes.insert("BreakpointTable",GDBMIResultType::BreakpointTable); + mResultTypes.insert("-stack-list-frames",GDBMIResultType::FrameStack); + mResultTypes.insert("-stack-list-variables", GDBMIResultType::LocalVariables); + //mResultTypes.insert("frame",GDBMIResultType::Frame); + mResultTypes.insert("-data-disassemble",GDBMIResultType::Disassembly); + mResultTypes.insert("-data-evaluate-expression",GDBMIResultType::Evaluation); +// mResultTypes.insert("register-names",GDBMIResultType::RegisterNames); +// mResultTypes.insert("register-values",GDBMIResultType::RegisterValues); + 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) +{ + const char* p = record.data(); + bool result = parseMultiValues(p,multiValues); + if (!result) + return false; +// if (*p!=0) +// return false; + if (!mResultTypes.contains(command)) + return false; + type = mResultTypes[command]; + return true; +} + +bool GDBMIResultParser::parseAsyncResult(const QByteArray &record, QByteArray &result, ParseObject &multiValue) +{ + const char* p =record.data(); + if (*p!='*') + return false; + p++; + const char* start=p; + while (*p && *p!=',') + p++; + result = QByteArray(start,p-start); + if (*p==0) + return true; + p++; + return parseMultiValues(p,multiValue); +} + +bool GDBMIResultParser::parseMultiValues(const char* p, ParseObject &multiValue) +{ + while (*p) { + QByteArray propName; + ParseValue propValue; + bool result = parseNameAndValue(p,propName,propValue); + if (result) { + multiValue[propName]=propValue; + } else { + return false; + } + skipSpaces(p); + if (*p==0) + break; + if (*p!=',') + return false; + p++; //skip ',' + skipSpaces(p); + } + return true; +} + +bool GDBMIResultParser::parseNameAndValue(const char *&p, QByteArray &name, ParseValue &value) +{ + skipSpaces(p); + const char* nameStart =p; + while (*p!=0 && isNameChar(*p)) { + p++; + } + if (*p==0) + return false; + name = QByteArray(nameStart,p-nameStart); + skipSpaces(p); + if (*p!='=') + return false; + p++; + return parseValue(p,value); +} + +bool GDBMIResultParser::parseValue(const char *&p, ParseValue &value) +{ + skipSpaces(p); + bool result; + switch (*p) { + case '{': { + ParseObject obj; + result = parseObject(p,obj); + value = obj; + break; + } + case '[': { + QList array; + result = parseArray(p,array); + value = array; + break; + } + case '"': { + QByteArray s; + result = parseStringValue(p,s); + value = s; + break; + } + default: + return false; + } + if (!result) + return false; + skipSpaces(p); + return true; +} + +bool GDBMIResultParser::parseStringValue(const char *&p, QByteArray& stringValue) +{ + if (*p!='"') + return false; + p++; + stringValue.clear(); + while (*p!=0) { + if (*p == '"') { + break; + } else if (*p=='\\' && *(p+1)!=0) { + p++; + switch (*p) { + case '\'': + stringValue+=0x27; + p++; + break; + case '"': + stringValue+=0x22; + p++; + break; + case '?': + stringValue+=0x3f; + p++; + break; + case '\\': + stringValue+=0x5c; + p++; + break; + case 'a': + stringValue+=0x07; + p++; + break; + case 'b': + stringValue+=0x08; + p++; + break; + case 'f': + stringValue+=0x0c; + p++; + break; + case 'n': + stringValue+=0x0a; + p++; + break; + case 'r': + stringValue+=0x0d; + p++; + break; + case 't': + stringValue+=0x09; + p++; + break; + case 'v': + stringValue+=0x0b; + p++; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + int i=0; + for (i=0;i<3;i++) { + if (*(p+i)<'0' || *(p+i)>'7') + break; + } + QByteArray numStr(p,i); + bool ok; + unsigned char ch = numStr.toInt(&ok,8); + stringValue+=ch; + p+=i; + break; + } + } + } else { + stringValue+=*p; + p++; + } + } + if (*p=='"') { + p++; //skip '"' + return true; + } + return false; +} + +bool GDBMIResultParser::parseObject(const char *&p, ParseObject &obj) +{ + if (*p!='{') + return false; + p++; + + if (*p!='}') { + while (*p!=0) { + QByteArray propName; + ParseValue propValue; + bool result = parseNameAndValue(p,propName,propValue); + if (result) { + obj[propName]=propValue; + } else { + return false; + } + skipSpaces(p); + if (*p=='}') + break; + if (*p!=',') { + return false; + } + p++; //skip ',' + skipSpaces(p); + } + } + if (*p=='}') { + p++; //skip '}' + return true; + } + return false; +} + +bool GDBMIResultParser::parseArray(const char *&p, QList &array) +{ + if (*p!='[') + return false; + p++; + if (*p!=']') { + while (*p!=0) { + skipSpaces(p); + if (*p=='{' || *p=='"' || *p=='[') { + ParseValue val; + bool result = parseValue(p,val); + if (result) { + array.append(val); + } else { + return false; + } + } else { + QByteArray name; + ParseValue val; + bool result = parseNameAndValue(p,name,val); + if (result) { + array.append(val); + } else { + return false; + } + } + skipSpaces(p); + if (*p==']') + break; + if (*p!=',') + return false; + p++; //skip ',' + skipSpaces(p); + } + } + if (*p==']') { + p++; //skip ']' + return true; + } + return false; +} + +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') + return true; + return false; +} + +bool GDBMIResultParser::isSpaceChar(char ch) +{ + switch(ch) { + case ' ': + case '\t': + return true; + } + return false; +} + +void GDBMIResultParser::skipSpaces(const char *&p) +{ + while (*p!=0 && isSpaceChar(*p)) + p++; +} + +const QByteArray &GDBMIResultParser::ParseValue::value() const +{ + return mValue; +} + +const QList<::GDBMIResultParser::ParseValue> &GDBMIResultParser::ParseValue::array() const +{ + return mArray; +} + +const GDBMIResultParser::ParseObject &GDBMIResultParser::ParseValue::object() const +{ + return mObject; +} + +int GDBMIResultParser::ParseValue::intValue(int defaultValue) const +{ + Q_ASSERT(mType == ParseValueType::Value); + bool ok; + int value = QString(mValue).toInt(&ok); + if (ok) + return value; + else + return defaultValue; +} + +int GDBMIResultParser::ParseValue::hexValue(int defaultValue) const +{ + Q_ASSERT(mType == ParseValueType::Value); + bool ok; + int value = QString(mValue).toInt(&ok,16); + if (ok) + return value; + else + return defaultValue; +} + +QString GDBMIResultParser::ParseValue::pathValue() const +{ + Q_ASSERT(mType == ParseValueType::Value); + return QFileInfo(QString::fromLocal8Bit(mValue)).absoluteFilePath(); +} + +GDBMIResultParser::ParseValueType GDBMIResultParser::ParseValue::type() const +{ + return mType; +} + +bool GDBMIResultParser::ParseValue::isValid() const +{ + return mType!=ParseValueType::NotAssigned; +} + +GDBMIResultParser::ParseValue::ParseValue(): + mType(ParseValueType::NotAssigned) { + +} + +GDBMIResultParser::ParseValue::ParseValue(const QByteArray &value): + mValue(value), + mType(ParseValueType::Value) +{ +} + +GDBMIResultParser::ParseValue::ParseValue(const ParseObject &object): + mObject(object), + mType(ParseValueType::Object) +{ +} + +GDBMIResultParser::ParseValue::ParseValue(const QList &array): + mArray(array), + mType(ParseValueType::Array) +{ +} + +GDBMIResultParser::ParseValue::ParseValue(const ParseValue &value): + mValue(value.mValue), + mArray(value.mArray), + mObject(value.mObject), + mType(value.mType) +{ +} + +GDBMIResultParser::ParseValue &GDBMIResultParser::ParseValue::operator=(const GDBMIResultParser::ParseValue &value) +{ + mType = value.mType; + mValue = value.mValue; + mArray = value.mArray; + mObject = value.mObject; + return *this; +} + +GDBMIResultParser::ParseValue &GDBMIResultParser::ParseValue::operator=(const QByteArray &value) +{ + Q_ASSERT(mType == ParseValueType::NotAssigned); + mType = ParseValueType::Value; + mValue = value; + return *this; +} + +GDBMIResultParser::ParseValue &GDBMIResultParser::ParseValue::operator=(const ParseObject& object) +{ + Q_ASSERT(mType == ParseValueType::NotAssigned); + mType = ParseValueType::Object; + mObject = object; + return *this; +} + +GDBMIResultParser::ParseValue &GDBMIResultParser::ParseValue::operator=(const QList& array) +{ + Q_ASSERT(mType == ParseValueType::NotAssigned); + mType = ParseValueType::Array; + mArray = array; + return *this; +} + + +GDBMIResultParser::ParseObject::ParseObject() +{ + +} + +GDBMIResultParser::ParseObject::ParseObject(const ParseObject &object): + mProps(object.mProps) +{ + +} + +GDBMIResultParser::ParseValue GDBMIResultParser::ParseObject::operator[](const QByteArray &name) const +{ + if (mProps.contains(name)) { + ParseValue value(mProps[name]); + return value; + } + return ParseValue(); +} + +GDBMIResultParser::ParseObject &GDBMIResultParser::ParseObject::operator=(const ParseObject &object) +{ + mProps = object.mProps; + return *this; +} + +GDBMIResultParser::ParseValue &GDBMIResultParser::ParseObject::operator[](const QByteArray &name) { + if (!mProps.contains(name)) + mProps[name]=ParseValue(); + return mProps[name]; +} + diff --git a/RedPandaIDE/gdbmiresultparser.h b/RedPandaIDE/gdbmiresultparser.h new file mode 100644 index 00000000..c7742612 --- /dev/null +++ b/RedPandaIDE/gdbmiresultparser.h @@ -0,0 +1,98 @@ +#ifndef GDBMIRESULTPARSER_H +#define GDBMIRESULTPARSER_H + +#include +#include +#include +#include + + +enum class GDBMIResultType { + Breakpoint, + BreakpointTable, + FrameStack, + LocalVariables, + Locals, + Frame, + Disassembly, + Evaluation, + RegisterNames, + RegisterValues, + Memory, + CreateVar, + ListVarChildren, + UpdateVarValue +}; + + +class GDBMIResultParser +{ +public: + enum class ParseValueType { + Value, + Object, + Array, + NotAssigned + }; + + class ParseValue; + + class ParseObject { + public: + explicit ParseObject(); + ParseObject(const ParseObject& object); + ParseValue operator[](const QByteArray& name) const; + ParseValue& operator[](const QByteArray& name); + ParseObject& operator=(const ParseObject& object); + private: + QHash mProps; + }; + + class ParseValue { + public: + explicit ParseValue(); + explicit ParseValue(const QByteArray& value); + explicit ParseValue(const ParseObject &object); + explicit ParseValue(const QList& array); + ParseValue(const ParseValue& value); + const QByteArray &value() const; + const QList &array() const; + const ParseObject &object() const; + int intValue(int defaultValue=-1) const; + int hexValue(int defaultValue=-1) const; + + QString pathValue() const; + ParseValueType type() const; + bool isValid() const; + ParseValue& operator=(const QByteArray& value); + ParseValue& operator=(const ParseObject& object); + ParseValue& operator=(const QList& array); + ParseValue& operator=(const ParseValue& value); + private: + QByteArray mValue; + QList mArray; + ParseObject mObject; + ParseValueType mType; + }; + + using PParseValue = std::shared_ptr; + +public: + GDBMIResultParser(); + bool parse(const QByteArray& record, const QString& command, GDBMIResultType& type, ParseObject& multiValues); + bool parseAsyncResult(const QByteArray& record, QByteArray& result, ParseObject& multiValue); +private: + bool parseMultiValues(const char*p, ParseObject& multiValue); + bool parseNameAndValue(const char *&p,QByteArray& name, ParseValue& value); + bool parseValue(const char* &p, ParseValue& value); + bool parseStringValue(const char*&p, QByteArray& stringValue); + bool parseObject(const char*&p, ParseObject& obj); + bool parseArray(const char*&p, QList& array); + void skipSpaces(const char* &p); + bool isNameChar(char ch); + bool isSpaceChar(char ch); +private: + QHash mResultTypes; +}; + +#endif // GDBMIRESULTPARSER_H diff --git a/RedPandaIDE/icons.qrc b/RedPandaIDE/icons.qrc index 8607fe7c..4727b69d 100644 --- a/RedPandaIDE/icons.qrc +++ b/RedPandaIDE/icons.qrc @@ -489,5 +489,6 @@ images/editor/bookmark.png images/newlook24/091-openproblemanswer.png images/newlook24/092-runallproblemcases.png + images/newlook24/093-pause.png diff --git a/RedPandaIDE/iconsmanager.h b/RedPandaIDE/iconsmanager.h index e59fd4ff..5cf72a8b 100644 --- a/RedPandaIDE/iconsmanager.h +++ b/RedPandaIDE/iconsmanager.h @@ -23,7 +23,6 @@ public: const PIcon &bookmark() const; const PIcon &folder() const; -signals: private: PIcon mSyntaxError; PIcon mSyntaxWarning; diff --git a/RedPandaIDE/images/newlook24/093-pause.png b/RedPandaIDE/images/newlook24/093-pause.png new file mode 100644 index 00000000..4394cb52 Binary files /dev/null and b/RedPandaIDE/images/newlook24/093-pause.png differ diff --git a/RedPandaIDE/main.cpp b/RedPandaIDE/main.cpp index c3709e8a..64d8fd45 100644 --- a/RedPandaIDE/main.cpp +++ b/RedPandaIDE/main.cpp @@ -103,6 +103,7 @@ int main(int argc, char *argv[]) qRegisterMetaType("PCompileIssue"); qRegisterMetaType("PCompileIssue&"); qRegisterMetaType>("QVector"); + qRegisterMetaType>("QHash"); initParser(); diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index bc95b32a..f7fab347 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -49,6 +49,14 @@ #include +static int findTabIndex(QTabWidget* tabWidget , QWidget* w) { + for (int i=0;icount();i++) { + if (w==tabWidget->widget(i)) + return i; + } + return -1; +} + MainWindow* pMainWindow; MainWindow::MainWindow(QWidget *parent) @@ -733,6 +741,8 @@ void MainWindow::updateAppTitle() void MainWindow::addDebugOutput(const QString &text) { + if (!pSettings->debugger().enableDebugConsole()) + return; if (text.isEmpty()) { ui->debugConsole->addLine(""); } else { @@ -1056,6 +1066,18 @@ void MainWindow::updateDebuggerSettings() ui->debugConsole->setFont(font); ui->txtMemoryView->setFont(font); ui->txtLocals->setFont(font); + + int idx = findTabIndex(ui->debugViews,ui->tabDebugConsole); + if (idx>=0) { + if (!pSettings->debugger().enableDebugConsole()) { + ui->debugViews->removeTab(idx); + } + } else { + if (pSettings->debugger().enableDebugConsole()) { + ui->debugViews->insertTab(0, ui->tabDebugConsole, tr("Debug Console")); + } + } + } void MainWindow::checkSyntaxInBack(Editor *e) @@ -1323,12 +1345,12 @@ void MainWindow::debug() if (!mDebugger->start()) return; filePath.replace('\\','/'); - mDebugger->sendCommand("file", '"' + filePath + '"'); + mDebugger->sendCommand("-file-exec-and-symbols", '"' + filePath + '"'); if (mProject->options().type == ProjectType::DynamicLib) { QString host =mProject->options().hostApplication; host.replace('\\','/'); - mDebugger->sendCommand("exec-file", '"' + host + '"'); + mDebugger->sendCommand("-file-exec-file", '"' + host + '"'); } includeOrSkipDirs(mProject->options().includes, @@ -1398,10 +1420,9 @@ void MainWindow::debug() prepareDebugger(); - mDebugger->setUseUTF8(e->fileEncoding() == ENCODING_UTF8 || e->fileEncoding() == ENCODING_UTF8_BOM); if (!mDebugger->start()) return; - mDebugger->sendCommand("file", QString("\"%1\"").arg(debugFile.filePath().replace('\\','/'))); + mDebugger->sendCommand("-file-exec-and-symbols", QString("\"%1\"").arg(debugFile.filePath().replace('\\','/'))); } } break; @@ -1425,48 +1446,39 @@ 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 - mDebugger->sendCommand("set", "width 0"); // don't wrap output, very annoying - mDebugger->sendCommand("set", "new-console on"); - mDebugger->sendCommand("set", "confirm off"); - mDebugger->sendCommand("set", "print repeats 0"); // don't repeat elements - mDebugger->sendCommand("set", "print elements 0"); // don't limit elements - mDebugger->sendCommand("cd", excludeTrailingPathDelimiter(debugFile.path())); // restore working directory + mDebugger->sendCommand("-enable-pretty-printing",""); + mDebugger->sendCommand("-data-list-register-names",""); + mDebugger->sendCommand("-gdb-set", "width 0"); // don't wrap output, very annoying + mDebugger->sendCommand("-gdb-set", "new-console on"); + mDebugger->sendCommand("-gdb-set", "confirm off"); + mDebugger->sendCommand("-gdb-set", "print repeats 0"); // don't repeat elements + mDebugger->sendCommand("-gdb-set", "print elements 0"); // don't limit elements + mDebugger->sendCommand("-environment-cd", excludeTrailingPathDelimiter(debugFile.path())); // restore working directory if (!debugInferiorhasBreakpoint()) { - QString params; switch(getCompileTarget()) { case CompileTarget::None: return; case CompileTarget::File: - mDebugger->sendCommand("start",params); - mDebugger->updateDebugInfo(); + mDebugger->sendCommand("-exec-run", "--start"); break; case CompileTarget::Project: - params = ""; - mDebugger->sendCommand("start",params); - mDebugger->updateDebugInfo(); + mDebugger->sendCommand("-exec-run", "--start"); break; default: break; } } else { - QString params; switch(getCompileTarget()) { case CompileTarget::None: return; case CompileTarget::File: - mDebugger->sendCommand("run",params); - mDebugger->updateDebugInfo(); + mDebugger->sendCommand("-exec-run",""); break; case CompileTarget::Project: - mDebugger->sendCommand("run",params); - mDebugger->updateDebugInfo(); + mDebugger->sendCommand("-exec-run",""); break; default: break; @@ -1481,6 +1493,15 @@ void MainWindow::showSearchPanel(bool showReplace) ui->tabMessages->setCurrentWidget(ui->tabSearch); } +void MainWindow::showCPUInfoDialog() +{ + if (mCPUDialog==nullptr) { + mCPUDialog = new CPUDialog(this); + connect(mCPUDialog, &CPUDialog::closed, this, &MainWindow::cleanUpCPUDialog); + } + mCPUDialog->show(); +} + void MainWindow::openCloseBottomPanel(bool open) { // if Assigned(fReportToolWindow) then @@ -1553,7 +1574,7 @@ void MainWindow::prepareDebugger() // Clear logs ui->debugConsole->clear(); - if (!pSettings->debugger().showCommandLog()) { + if (pSettings->debugger().enableDebugConsole()) { ui->debugConsole->addLine("(gdb) "); } ui->txtEvalOutput->clear(); @@ -1661,7 +1682,7 @@ void MainWindow::includeOrSkipDirs(const QStringList &dirs, bool skip) .arg(dirName,"*.*")); } else { mDebugger->sendCommand( - "dir", + "-environment-directory", QString("\"%1\"").arg(dirName)); } } @@ -1924,13 +1945,13 @@ void MainWindow::buildContextMenus() ui->debugConsole->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->debugConsole,&QWidget::customContextMenuRequested, this, &MainWindow::onDebugConsoleContextMenu); - mDebugConsole_ShowCommandLog = createActionFor( - tr("Show debug logs in the debug console"), + mDebugConsole_ShowDetailLog = createActionFor( + tr("Show detail debug logs"), ui->debugConsole); - mDebugConsole_ShowCommandLog->setCheckable(true); - connect(mDebugConsole_ShowCommandLog, &QAction::toggled, + mDebugConsole_ShowDetailLog->setCheckable(true); + connect(mDebugConsole_ShowDetailLog, &QAction::toggled, [this]() { - pSettings->debugger().setShowCommandLog(mDebugConsole_ShowCommandLog->isChecked()); + pSettings->debugger().setShowDetailLog(mDebugConsole_ShowDetailLog->isChecked()); pSettings->debugger().save(); }); mDebugConsole_Copy=createActionFor( @@ -2612,16 +2633,16 @@ void MainWindow::onDebugConsoleContextMenu(const QPoint &pos) { QMenu menu(this); - bool oldBlock = mDebugConsole_ShowCommandLog->blockSignals(true); - mDebugConsole_ShowCommandLog->setChecked(pSettings->debugger().showCommandLog()); - mDebugConsole_ShowCommandLog->blockSignals(oldBlock); + bool oldBlock = mDebugConsole_ShowDetailLog->blockSignals(true); + mDebugConsole_ShowDetailLog->setChecked(pSettings->debugger().showDetailLog()); + mDebugConsole_ShowDetailLog->blockSignals(oldBlock); menu.addAction(mDebugConsole_Copy); menu.addAction(mDebugConsole_Paste); menu.addAction(mDebugConsole_SelectAll); menu.addAction(mDebugConsole_Clear); menu.addSeparator(); - menu.addAction(mDebugConsole_ShowCommandLog); + menu.addAction(mDebugConsole_ShowDetailLog); menu.exec(ui->debugConsole->mapToGlobal(pos)); } @@ -2898,7 +2919,7 @@ void MainWindow::onShowInsertCodeSnippetMenu() } -void MainWindow::onEditorContextMenu(const QPoint &pos) +void MainWindow::onEditorContextMenu(const QPoint& pos) { Editor * editor = mEditorList->getEditor(); if (!editor) @@ -2967,12 +2988,12 @@ void MainWindow::onEditorContextMenu(const QPoint &pos) menu.exec(editor->viewport()->mapToGlobal(pos)); } -void MainWindow::onEditorRightTabContextMenu(const QPoint &pos) +void MainWindow::onEditorRightTabContextMenu(const QPoint& pos) { onEditorTabContextMenu(ui->EditorTabsRight,pos); } -void MainWindow::onEditorLeftTabContextMenu(const QPoint &pos) +void MainWindow::onEditorLeftTabContextMenu(const QPoint& pos) { onEditorTabContextMenu(ui->EditorTabsLeft,pos); } @@ -3020,13 +3041,13 @@ void MainWindow::disableDebugActions() void MainWindow::enableDebugActions() { - ui->actionStep_Into->setEnabled(true); - ui->actionStep_Over->setEnabled(true); - ui->actionStep_Out->setEnabled(true); - ui->actionRun_To_Cursor->setEnabled(true); - ui->actionContinue->setEnabled(true); - ui->cbEvaluate->setEnabled(true); - ui->cbMemoryAddress->setEnabled(true); + ui->actionStep_Into->setEnabled(!mDebugger->inferiorRunning()); + ui->actionStep_Over->setEnabled(!mDebugger->inferiorRunning()); + ui->actionStep_Out->setEnabled(!mDebugger->inferiorRunning()); + ui->actionRun_To_Cursor->setEnabled(!mDebugger->inferiorRunning()); + ui->actionContinue->setEnabled(!mDebugger->inferiorRunning()); + ui->cbEvaluate->setEnabled(!mDebugger->inferiorRunning()); + ui->cbMemoryAddress->setEnabled(!mDebugger->inferiorRunning()); } void MainWindow::onTodoParseStarted(const QString&) @@ -3034,7 +3055,7 @@ void MainWindow::onTodoParseStarted(const QString&) mTodoModel.clear(); } -void MainWindow::onTodoParsing(const QString &filename, int lineNo, int ch, const QString &line) +void MainWindow::onTodoParsing(const QString& filename, int lineNo, int ch, const QString& line) { mTodoModel.addItem(filename,lineNo,ch,line); } @@ -3488,7 +3509,7 @@ void MainWindow::onCompilerSetChanged(int index) pSettings->compilerSets().saveDefaultIndex(); } -void MainWindow::onCompileLog(const QString &msg) +void MainWindow::onCompileLog(const QString& msg) { ui->txtCompilerOutput->appendPlainText(msg); ui->txtCompilerOutput->moveCursor(QTextCursor::End); @@ -3629,12 +3650,12 @@ void MainWindow::onCompileFinished(bool isCheckSyntax) updateAppTitle(); } -void MainWindow::onCompileErrorOccured(const QString &reason) +void MainWindow::onCompileErrorOccured(const QString& reason) { QMessageBox::critical(this,tr("Compile Failed"),reason); } -void MainWindow::onRunErrorOccured(const QString &reason) +void MainWindow::onRunErrorOccured(const QString& reason) { mCompilerManager->stopRun(); QMessageBox::critical(this,tr("Run Failed"),reason); @@ -3669,7 +3690,7 @@ void MainWindow::onOJProblemCaseStarted(const QString& id,int current, int total } } -void MainWindow::onOJProblemCaseFinished(const QString &id, int current, int total) +void MainWindow::onOJProblemCaseFinished(const QString& id, int current, int total) { int row = mOJProblemModel.getCaseIndexById(id); if (row>=0) { @@ -3698,10 +3719,10 @@ void MainWindow::cleanUpCPUDialog() ptr->deleteLater(); } -void MainWindow::onDebugCommandInput(const QString &command) +void MainWindow::onDebugCommandInput(const QString& command) { if (mDebugger->executing()) { - mDebugger->sendCommand(command,"",true,true); + mDebugger->sendCommand(command,"", DebugCommandSource::Console); } } @@ -3979,10 +4000,7 @@ void MainWindow::on_actionStep_Over_triggered() { if (mDebugger->executing()) { //WatchView.Items.BeginUpdate(); - mDebugger->invalidateAllVars(); - mDebugger->sendCommand("next", ""); - mDebugger->updateDebugInfo(); - mDebugger->refreshWatchVars(); + mDebugger->sendCommand("-exec-next", ""); } } @@ -3990,10 +4008,7 @@ void MainWindow::on_actionStep_Into_triggered() { if (mDebugger->executing()) { //WatchView.Items.BeginUpdate(); - mDebugger->invalidateAllVars(); - mDebugger->sendCommand("step", ""); - mDebugger->updateDebugInfo(); - mDebugger->refreshWatchVars(); + mDebugger->sendCommand("-exec-step", ""); } } @@ -4002,10 +4017,7 @@ void MainWindow::on_actionStep_Out_triggered() { if (mDebugger->executing()) { //WatchView.Items.BeginUpdate(); - mDebugger->invalidateAllVars(); - mDebugger->sendCommand("finish", ""); - mDebugger->updateDebugInfo(); - mDebugger->refreshWatchVars(); + mDebugger->sendCommand("-exec-finish", ""); } } @@ -4016,11 +4028,9 @@ void MainWindow::on_actionRun_To_Cursor_triggered() Editor *e=mEditorList->getEditor(); if (e!=nullptr) { //WatchView.Items.BeginUpdate(); - mDebugger->invalidateAllVars(); - mDebugger->sendCommand("tbreak", QString(" %1").arg(e->caretY())); - mDebugger->sendCommand("continue", ""); - mDebugger->updateDebugInfo(); - mDebugger->refreshWatchVars(); + mDebugger->sendCommand("-exec-until", QString("\"%1\":%2") + .arg(e->filename()) + .arg(e->caretY())); } } @@ -4030,10 +4040,7 @@ void MainWindow::on_actionContinue_triggered() { if (mDebugger->executing()) { //WatchView.Items.BeginUpdate(); - mDebugger->invalidateAllVars(); - mDebugger->sendCommand("continue", ""); - mDebugger->updateDebugInfo(); - mDebugger->refreshWatchVars(); + mDebugger->sendCommand("-exec-continue", ""); } } @@ -4064,11 +4071,7 @@ void MainWindow::on_actionAdd_Watch_triggered() void MainWindow::on_actionView_CPU_Window_triggered() { - if (mCPUDialog==nullptr) { - mCPUDialog = new CPUDialog(this); - connect(mCPUDialog, &CPUDialog::closed, this, &MainWindow::cleanUpCPUDialog); - } - mCPUDialog->show(); + showCPUInfoDialog(); } void MainWindow::on_actionExit_triggered() @@ -4082,7 +4085,7 @@ void MainWindow::onDebugEvaluateInput() if (!s.isEmpty()) { connect(mDebugger, &Debugger::evalValueReady, this, &MainWindow::onEvalValueReady); - mDebugger->sendCommand("print",s,false); + mDebugger->sendCommand("-data-evaluate-expression",s); } } @@ -4092,7 +4095,7 @@ void MainWindow::onDebugMemoryAddressInput() if (!s.isEmpty()) { connect(mDebugger, &Debugger::memoryExamineReady, this, &MainWindow::onMemoryExamineReady); - mDebugger->sendCommand("x/64bx",s,false); + mDebugger->sendCommand("-data-read-memory",QString("%1 x 1 8 8 ").arg(s)); } } @@ -4140,14 +4143,14 @@ void MainWindow::onEndParsing(int total, int) } } -void MainWindow::onEvalValueReady(const QString &value) +void MainWindow::onEvalValueReady(const QString& value) { updateDebugEval(value); disconnect(mDebugger, &Debugger::evalValueReady, this, &MainWindow::onEvalValueReady); } -void MainWindow::onMemoryExamineReady(const QStringList &value) +void MainWindow::onMemoryExamineReady(const QStringList& value) { ui->txtMemoryView->clear(); foreach (QString s, value) { @@ -4159,7 +4162,7 @@ void MainWindow::onMemoryExamineReady(const QStringList &value) this, &MainWindow::onMemoryExamineReady); } -void MainWindow::onLocalsReady(const QStringList &value) +void MainWindow::onLocalsReady(const QStringList& value) { ui->txtLocals->clear(); foreach (QString s, value) { @@ -4864,14 +4867,6 @@ void MainWindow::updateEditorHideTime(QTabWidget* tabWidget) { } } -static int findTabIndex(QTabWidget* tabWidget , QWidget* w) { - for (int i=0;icount();i++) { - if (w==tabWidget->widget(i)) - return i; - } - return -1; -} - void MainWindow::showHideInfosTab(QWidget *widget, bool show) { int idx = findTabIndex(ui->tabInfos,widget); @@ -5166,8 +5161,8 @@ void MainWindow::updateProblemCaseOutput(POJProblemCase problemCase) ui->txtProblemCaseOutput->clear(); ui->txtProblemCaseOutput->setText(problemCase->output); if (problemCase->testState == ProblemCaseTestState::Failed) { - QStringList output = TextToLines(problemCase->output); - QStringList expected = TextToLines(problemCase->expected); + QStringList output = textToLines(problemCase->output); + QStringList expected = textToLines(problemCase->expected); for (int i=0;i=expected.count() || output[i]!=expected[i]) { QTextBlock block = ui->txtProblemCaseOutput->document()->findBlockByLineNumber(i); @@ -5747,7 +5742,6 @@ void MainWindow::on_actionDelete_to_EOL_triggered() } } - void MainWindow::on_actionDelete_to_BOL_triggered() { Editor *e=mEditorList->getEditor(); @@ -5755,4 +5749,3 @@ void MainWindow::on_actionDelete_to_BOL_triggered() e->deleteToBOL(); } } - diff --git a/RedPandaIDE/mainwindow.h b/RedPandaIDE/mainwindow.h index 4e0383b4..75408571 100644 --- a/RedPandaIDE/mainwindow.h +++ b/RedPandaIDE/mainwindow.h @@ -95,13 +95,13 @@ public: void runExecutable(RunType runType = RunType::Normal); void debug(); void showSearchPanel(bool showReplace = false); + void showCPUInfoDialog(); void applySettings(); void applyUISettings(); QFileSystemWatcher* fileSystemWatcher(); void removeActiveBreakpoints(); - void setActiveBreakpoint(QString FileName, int Line, bool setFocus=true); void updateAppTitle(); void addDebugOutput(const QString& text); void changeDebugOutputLastline(const QString& text); @@ -193,6 +193,7 @@ public slots: void onTodoParseStarted(const QString& filename); void onTodoParsing(const QString& filename, int lineNo, int ch, const QString& line); void onTodoParseFinished(); + void setActiveBreakpoint(QString FileName, int Line, bool setFocus); private: void prepareProjectForCompile(); @@ -632,7 +633,7 @@ private: QWidget * mFilesViewToolbar; //action for debug console - QAction * mDebugConsole_ShowCommandLog; + QAction * mDebugConsole_ShowDetailLog; QAction * mDebugConsole_Clear; QAction * mDebugConsole_Copy; QAction * mDebugConsole_Paste; diff --git a/RedPandaIDE/mainwindow.ui b/RedPandaIDE/mainwindow.ui index d45c3e17..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 @@ -506,7 +506,7 @@ QTabWidget::South - 0 + 2 diff --git a/RedPandaIDE/parser/cpppreprocessor.cpp b/RedPandaIDE/parser/cpppreprocessor.cpp index b45b1fbb..fc13cb1b 100644 --- a/RedPandaIDE/parser/cpppreprocessor.cpp +++ b/RedPandaIDE/parser/cpppreprocessor.cpp @@ -680,7 +680,7 @@ void CppPreprocessor::openInclude(const QString &fileName, QStringList bufferedT if (!bufferedText.isEmpty()) { parsedFile->buffer = bufferedText; } else { - parsedFile->buffer = ReadFileToLines(fileName); + parsedFile->buffer = readFileToLines(fileName); } } } else { diff --git a/RedPandaIDE/parser/cpppreprocessor.h b/RedPandaIDE/parser/cpppreprocessor.h index 1addf7ba..85ab0c49 100644 --- a/RedPandaIDE/parser/cpppreprocessor.h +++ b/RedPandaIDE/parser/cpppreprocessor.h @@ -74,9 +74,6 @@ public: const QList &includePathList() const; const QList &projectIncludePathList() const; - -signals: - private: void preprocessBuffer(); void skipToEndOfPreprocessor(); diff --git a/RedPandaIDE/parser/cpptokenizer.h b/RedPandaIDE/parser/cpptokenizer.h index 4f275984..a7c219c7 100644 --- a/RedPandaIDE/parser/cpptokenizer.h +++ b/RedPandaIDE/parser/cpptokenizer.h @@ -21,7 +21,6 @@ public: const TokenList& tokens(); PToken operator[](int i); int tokenCount(); -signals: private: void addToken(const QString& sText, int iLine); void advance(); diff --git a/RedPandaIDE/parser/statementmodel.h b/RedPandaIDE/parser/statementmodel.h index 3077b568..1608b592 100644 --- a/RedPandaIDE/parser/statementmodel.h +++ b/RedPandaIDE/parser/statementmodel.h @@ -22,8 +22,6 @@ public: #ifdef QT_DEBUG void dumpAll(const QString& logFile); #endif -signals: - private: void addMember(StatementMap& map, const PStatement& statement); int deleteMember(StatementMap& map, const PStatement& statement); diff --git a/RedPandaIDE/problems/problemcasevalidator.cpp b/RedPandaIDE/problems/problemcasevalidator.cpp index b3a70552..112d97a3 100644 --- a/RedPandaIDE/problems/problemcasevalidator.cpp +++ b/RedPandaIDE/problems/problemcasevalidator.cpp @@ -10,8 +10,8 @@ bool ProblemCaseValidator::validate(POJProblemCase problemCase) { if (!problemCase) return false; - QStringList output = TextToLines(problemCase->output); - QStringList expected = TextToLines(problemCase->expected); + QStringList output = textToLines(problemCase->output); + QStringList expected = textToLines(problemCase->expected); if (output.count()!=expected.count()) return false; for (int i=0;imodified()) + if (unit->modified()) { return true; + } } return false; } @@ -184,10 +185,7 @@ void Project::setFileName(QString value) void Project::setModified(bool value) { - QFile file(mFilename); - // only mark modified if *not* read-only - if (!file.exists() - || (file.exists() && file.isWritable())) { + if (mModified!=value) { mModified=value; emit modifyChanged(mModified); } @@ -1032,7 +1030,7 @@ void Project::buildPrivateResource(bool forceSave) rcFile = QDir(directory()).absoluteFilePath(rcFile); if (contents.count() > 3) { - StringsToFile(contents,rcFile); + stringsToFile(contents,rcFile); mOptions.privateResource = extractRelativePath(directory(), rcFile); } else { if (fileExists(rcFile)) @@ -1073,7 +1071,7 @@ void Project::buildPrivateResource(bool forceSave) content.append(" "); content.append(""); content.append(""); - StringsToFile(content,executable() + ".Manifest"); + stringsToFile(content,executable() + ".Manifest"); } else if (fileExists(executable() + ".Manifest")) QFile::remove(executable() + ".Manifest"); @@ -1119,7 +1117,7 @@ void Project::buildPrivateResource(bool forceSave) .arg(mOptions.versionInfo.productVersion)); contents.append(""); contents.append("#endif /*" + def + "*/"); - StringsToFile(contents,hFile); + stringsToFile(contents,hFile); } void Project::checkProjectFileForUpdate(SimpleIni &ini) @@ -1599,6 +1597,7 @@ void Project::setName(const QString &newName) if (newName != mName) { mName = newName; mNode->text = newName; + setModified(true); } } @@ -1772,7 +1771,7 @@ bool ProjectUnit::save() if (!mEditor && !fileExists(mFileName)) { // file is neither open, nor saved QStringList temp; - StringsToFile(temp,mFileName); + stringsToFile(temp,mFileName); } else if (mEditor && mEditor->modified()) { result = mEditor->save(); } @@ -1885,7 +1884,7 @@ Qt::ItemFlags ProjectModel::flags(const QModelIndex &index) const if (!p) return Qt::NoItemFlags; if (p==mProject->node().get()) - return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled; + return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable; Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled; if (p->unitIndex<0) { flags.setFlag(Qt::ItemIsDropEnabled); @@ -1903,8 +1902,13 @@ bool ProjectModel::setData(const QModelIndex &index, const QVariant &value, int if (!node) return false; if (role == Qt::EditRole) { - if (node == mProject->node()) - return false; + if (node == mProject->node()) { + QString newName = value.toString().trimmed(); + if (newName.isEmpty()) + return false; + mProject->setName(newName); + return true; + } int idx = node->unitIndex; if (idx >= 0) { //change unit name diff --git a/RedPandaIDE/project.h b/RedPandaIDE/project.h index e5f6f392..bcd04b6e 100644 --- a/RedPandaIDE/project.h +++ b/RedPandaIDE/project.h @@ -2,8 +2,6 @@ #define PROJECT_H #include -#include -#include #include #include "projectoptions.h" #include "utils.h" diff --git a/RedPandaIDE/projecttemplate.h b/RedPandaIDE/projecttemplate.h index bc360319..314c728f 100644 --- a/RedPandaIDE/projecttemplate.h +++ b/RedPandaIDE/projecttemplate.h @@ -54,8 +54,6 @@ private: QString mIcon; // icon in project form PSimpleIni mIni; int mVersion; -signals: - }; using PProjectTemplate = std::shared_ptr; diff --git a/RedPandaIDE/qsynedit/SynEdit.cpp b/RedPandaIDE/qsynedit/SynEdit.cpp index 29f3c88d..9c733be6 100644 --- a/RedPandaIDE/qsynedit/SynEdit.cpp +++ b/RedPandaIDE/qsynedit/SynEdit.cpp @@ -123,7 +123,7 @@ SynEdit::SynEdit(QWidget *parent) : QAbstractScrollArea(parent) | eoHideShowScrollbars ; mScrollTimer = new QTimer(this); - mScrollTimer->setInterval(100); + //mScrollTimer->setInterval(100); connect(mScrollTimer, &QTimer::timeout,this, &SynEdit::onScrollTimeout); mScrollHintColor = QColorConstants::Yellow; @@ -666,9 +666,9 @@ DisplayCoord SynEdit::pixelsToNearestRowColumn(int aX, int aY) const // don't return a partially visible last line if (aY >= mLinesInWindow * mTextHeight) { aY = mLinesInWindow * mTextHeight - 1; - if (aY < 0) - aY = 0; } + if (aY < 0) + aY = 0; return { std::max(1, (int)(leftChar() + round(f))), std::max(1, mTopLine + (aY / mTextHeight)) @@ -1763,6 +1763,52 @@ void SynEdit::doToggleComment() doComment(); } +void SynEdit::doMouseScroll(bool isDragging) +{ + QPoint iMousePos; + DisplayCoord C; + int X, Y; + + iMousePos = QCursor::pos(); + iMousePos = mapFromGlobal(iMousePos); + C = pixelsToRowColumn(iMousePos.x(), iMousePos.y()); + C.Row = minMax(C.Row, 1, displayLineCount()); + if (mScrollDeltaX != 0) { + setLeftChar(leftChar() + mScrollDeltaX); + X = leftChar(); + if (mScrollDeltaX > 0) // scrolling right? + X+=charsInWindow(); + C.Column = X; + } + if (mScrollDeltaY != 0) { + if (QApplication::queryKeyboardModifiers().testFlag(Qt::ShiftModifier)) + setTopLine(mTopLine + mScrollDeltaY * mLinesInWindow); + else + setTopLine(mTopLine + mScrollDeltaY); + Y = mTopLine; + if (mScrollDeltaY > 0) // scrolling down? + Y+=mLinesInWindow - 1; + C.Row = minMax(Y, 1, displayLineCount()); + } + BufferCoord vCaret = displayToBufferPos(C); + if ((caretX() != vCaret.Char) || (caretY() != vCaret.Line)) { + // changes to line / column in one go + incPaintLock(); + auto action = finally([this]{ + decPaintLock(); + }); + internalSetCaretXY(vCaret); + + // if MouseCapture is True we're changing selection. otherwise we're dragging + if (isDragging) { + setBlockBegin(mDragSelBeginSave); + setBlockEnd(mDragSelEndSave); + } else + setBlockEnd(caretXY()); + } + computeScroll(iMousePos.x(), iMousePos.y(),isDragging); +} + void SynEdit::doDeleteLastChar() { if (mReadOnly) @@ -1819,7 +1865,7 @@ void SynEdit::doDeleteLastChar() mLines->deleteAt(mCaretY); doLinesDeleted(mCaretY+1, 1); if (mOptions.testFlag(eoTrimTrailingSpaces)) - Temp = TrimRight(Temp); + Temp = trimRight(Temp); setLineText(lineText() + Temp); helper = lineBreak(); //"/r/n" } @@ -2153,7 +2199,7 @@ void SynEdit::insertLine(bool moveCaret) rightLineText,mOptions.testFlag(eoAutoIndent) && notInComment); if (mOptions.testFlag(eoAutoIndent)) { - rightLineText=TrimLeft(rightLineText); + rightLineText=trimLeft(rightLineText); } QString indentSpacesForRightLineText = GetLeftSpacing(indentSpaces,true); mLines->insert(mCaretY, indentSpacesForRightLineText+rightLineText); @@ -2480,17 +2526,25 @@ void SynEdit::computeCaret(int X, int Y) setInternalDisplayXY(vCaretNearestPos); } -void SynEdit::computeScroll(int X, int Y) +void SynEdit::computeScroll(int X, int Y, bool isDragging) { + if (!isDragging) { + Qt::MouseButtons buttons = qApp->mouseButtons(); + if (!buttons.testFlag(Qt::LeftButton)) + return; + } QRect iScrollBounds; // relative to the client area - // don't scroll if dragging text from other control -// if (not MouseCapture) and (not Dragging) then begin -// fScrollTimer.Enabled := False; -// Exit; -// end; - - iScrollBounds = QRect(mGutterWidth+this->frameWidth(), this->frameWidth(), mCharsInWindow * mCharWidth, - mLinesInWindow * mTextHeight); + int dispX=2,dispY = 2; + if (isDragging) { + dispX = mCharWidth / 2 -1; + dispY = mTextHeight/ 2 -1; + } + int left = mGutterWidth+frameWidth()+dispX; + int top = frameWidth()+dispY; + iScrollBounds = QRect(left, + top, + clientWidth()-left-dispX, + clientHeight()-top-dispY); if (X < iScrollBounds.left()) mScrollDeltaX = (X - iScrollBounds.left()) / mCharWidth - 1; @@ -2499,6 +2553,10 @@ void SynEdit::computeScroll(int X, int Y) else mScrollDeltaX = 0; + if (isDragging && (X<0 || X>clientRect().width())) { + mScrollDeltaX = 0; + } + if (Y < iScrollBounds.top()) mScrollDeltaY = (Y - iScrollBounds.top()) / mTextHeight - 1; else if (Y >= iScrollBounds.bottom()) @@ -2506,8 +2564,17 @@ void SynEdit::computeScroll(int X, int Y) else mScrollDeltaY = 0; - if (mScrollDeltaX!=0 || mScrollDeltaY!=0) - mScrollTimer->start(); + if (isDragging && (Y<0 || Y>clientRect().height())) { + mScrollDeltaY = 0; + } + + if (mScrollDeltaX!=0 || mScrollDeltaY!=0) { + if (isDragging) { + mScrollTimer->singleShot(100,this,&SynEdit::onDraggingScrollTimeout); + } else { + mScrollTimer->singleShot(100,this,&SynEdit::onScrollTimeout); + } + } } void SynEdit::doBlockIndent() @@ -2670,7 +2737,7 @@ void SynEdit::doAddChar(QChar AChar) if (line.length() < oldCaretX) { int indentSpaces = calcIndentSpaces(oldCaretY,line+":", true); if (indentSpaces != leftSpaces(line)) { - QString newLine = GetLeftSpacing(indentSpaces,true) + TrimLeft(line); + QString newLine = GetLeftSpacing(indentSpaces,true) + trimLeft(line); int i = newLine.length(); mLines->putString(oldCaretY-1,newLine); internalSetCaretXY(BufferCoord{i+1,oldCaretY}); @@ -2841,11 +2908,6 @@ void SynEdit::decPaintLock() } } -bool SynEdit::mouseCapture() -{ - return hasMouseTracking(); -} - int SynEdit::clientWidth() { return viewport()->size().width(); @@ -4965,7 +5027,7 @@ void SynEdit::doLinesInserted(int firstLine, int count) void SynEdit::properSetLine(int ALine, const QString &ALineText, bool notify) { if (mOptions.testFlag(eoTrimTrailingSpaces)) { - mLines->putString(ALine,TrimRight(ALineText),notify); + mLines->putString(ALine,trimRight(ALineText),notify); } else { mLines->putString(ALine,ALineText,notify); } @@ -5077,7 +5139,7 @@ int SynEdit::insertTextByNormalMode(const QString &Value) int startLine = mCaretY; sLeftSide = lineText().mid(0, mCaretX - 1); if (mCaretX - 1 > sLeftSide.length()) { - if (StringIsBlank(sLeftSide)) + if (stringIsBlank(sLeftSide)) sLeftSide = GetLeftSpacing(displayX() - 1, true); else sLeftSide += QString(mCaretX - 1 - sLeftSide.length(),' '); @@ -5093,7 +5155,7 @@ int SynEdit::insertTextByNormalMode(const QString &Value) Start = 0; P = GetEOL(Value,Start); if (P= mGutterWidth + 2) @@ -5985,10 +6047,10 @@ void SynEdit::mouseReleaseEvent(QMouseEvent *event) processGutterClick(event); } - mScrollTimer->stop(); + //mScrollTimer->stop(); // if ((button = ) and (Shift = [ssRight]) and Assigned(PopupMenu) then // exit; - setMouseTracking(false); + //setMouseTracking(false); if (mStateFlags.testFlag(SynStateFlag::sfWaitForDragging) && !mStateFlags.testFlag(SynStateFlag::sfDblClicked)) { @@ -6008,9 +6070,6 @@ void SynEdit::mouseMoveEvent(QMouseEvent *event) Qt::MouseButtons buttons = event->buttons(); int X=event->pos().x(); int Y=event->pos().y(); -// if (!hasMouseTracking()) -// return; - if ((mStateFlags.testFlag(SynStateFlag::sfWaitForDragging))) { if ( ( event->pos() - mMouseDownPos).manhattanLength()>=QApplication::startDragDistance()) { mStateFlags.setFlag(SynStateFlag::sfWaitForDragging,false); @@ -6024,18 +6083,17 @@ void SynEdit::mouseMoveEvent(QMouseEvent *event) //drag->setPixmap(iconPixmap); //BeginDrag(false); } -// } else if ((buttons == Qt::LeftButton) && (X > mGutterWidth)) { } else if ((buttons == Qt::LeftButton)) { - // should we begin scrolling? - computeScroll(X, Y); - DisplayCoord P = pixelsToNearestRowColumn(X, Y); - P.Row = minMax(P.Row, 1, displayLineCount()); - if (mScrollDeltaX != 0) - P.Column = displayX(); - if (mScrollDeltaY != 0) - P.Row = displayY(); - internalSetCaretXY(displayToBufferPos(P)); - setBlockEnd(caretXY()); + // should we begin scrolling? + computeScroll(X, Y,false); + DisplayCoord P = pixelsToNearestRowColumn(X, Y); + P.Row = minMax(P.Row, 1, displayLineCount()); + if (mScrollDeltaX != 0) + P.Column = displayX(); + if (mScrollDeltaY != 0) + P.Row = displayY(); + internalSetCaretXY(displayToBufferPos(P)); + setBlockEnd(caretXY()); } else if (buttons == Qt::NoButton) { updateMouseCursor(); } @@ -6144,20 +6202,61 @@ void SynEdit::dragEnterEvent(QDragEnterEvent *event) void SynEdit::dropEvent(QDropEvent *event) { - mUndoList->BeginBlock(); - auto action = finally([this] { - mUndoList->EndBlock(); - }); - if (event->proposedAction() == Qt::DropAction::MoveAction) { - setBlockBegin(mDragSelBeginSave); - setBlockEnd(mDragSelEndSave); - setSelText(""); - } + //mScrollTimer->stop(); + BufferCoord coord = displayToBufferPos(pixelsToNearestRowColumn(event->pos().x(), event->pos().y())); setCaretXY(coord); - setSelText(event->mimeData()->text()); + if (coord>=mDragSelBeginSave && coord<=mDragSelEndSave) { + //do nothing if drag onto itself + } else if (event->proposedAction() == Qt::DropAction::CopyAction) { + //just copy it + setSelText(event->mimeData()->text()); + } else if (event->proposedAction() == Qt::DropAction::MoveAction) { + int topLine = mTopLine; + int leftChar = mLeftChar; + mUndoList->BeginBlock(); + if (coord < mDragSelBeginSave ) { + //delete old + setBlockBegin(mDragSelBeginSave); + setBlockEnd(mDragSelEndSave); + setSelText(""); + //paste to new position + setTopLine(topLine); + setLeftChar(leftChar); + setCaretXY(coord); + setSelText(event->mimeData()->text()); + } else { + //paste to new position + setTopLine(topLine); + setLeftChar(leftChar); + setCaretXY(coord); + setSelText(event->mimeData()->text()); + //delete old + setBlockBegin(mDragSelBeginSave); + setBlockEnd(mDragSelEndSave); + setSelText(""); + //set caret to right pos + if (mDragSelBeginSave.Line == mDragSelEndSave.Line) { + if (coord.Line == mDragSelEndSave.Line) { + coord.Char -= mDragSelEndSave.Char-mDragSelBeginSave.Char; + } + } else { + if (coord.Line == mDragSelEndSave.Line) { + coord.Char -= mDragSelEndSave.Char-1; + } else { + coord.Line -= mDragSelEndSave.Line-mDragSelBeginSave.Line; + topLine -= mDragSelEndSave.Line-mDragSelBeginSave.Line; + } + } + setTopLine(topLine); + setLeftChar(leftChar); + setCaretXY(coord); + } + mUndoList->EndBlock(); + } event->acceptProposedAction(); + } void SynEdit::dragMoveEvent(QDragMoveEvent *event) @@ -6167,9 +6266,13 @@ void SynEdit::dragMoveEvent(QDragMoveEvent *event) } else { event->setDropAction(Qt::MoveAction); } + // should we begin scrolling? + computeScroll(event->pos().x(), + event->pos().y(),true); + BufferCoord coord = displayToBufferPos(pixelsToNearestRowColumn(event->pos().x(), event->pos().y())); - setCaretXY(coord); + internalSetCaretXY(coord); setBlockBegin(mDragSelBeginSave); setBlockEnd(mDragSelEndSave); showCaret(); @@ -6177,10 +6280,10 @@ void SynEdit::dragMoveEvent(QDragMoveEvent *event) void SynEdit::dragLeaveEvent(QDragLeaveEvent *) { - setCaretXY(mDragCaretSave); - setBlockBegin(mDragSelBeginSave); - setBlockEnd(mDragSelEndSave); - showCaret(); +// setCaretXY(mDragCaretSave); +// setBlockBegin(mDragSelBeginSave); +// setBlockEnd(mDragSelEndSave); +// showCaret(); } int SynEdit::maxScrollHeight() const @@ -6556,43 +6659,10 @@ void SynEdit::onGutterChanged() void SynEdit::onScrollTimeout() { - QPoint iMousePos; - DisplayCoord C; - int X, Y; - - iMousePos = QCursor::pos(); - iMousePos = mapFromGlobal(iMousePos); - C = pixelsToRowColumn(iMousePos.x(), iMousePos.y()); - C.Row = minMax(C.Row, 1, displayLineCount()); - if (mScrollDeltaX != 0) { - setLeftChar(leftChar() + mScrollDeltaX); - X = leftChar(); - if (mScrollDeltaX > 0) // scrolling right? - X+=charsInWindow(); - C.Column = X; - } - if (mScrollDeltaY != 0) { - if (QApplication::queryKeyboardModifiers().testFlag(Qt::ShiftModifier)) - setTopLine(mTopLine + mScrollDeltaY * mLinesInWindow); - else - setTopLine(mTopLine + mScrollDeltaY); - Y = mTopLine; - if (mScrollDeltaY > 0) // scrolling down? - Y+=mLinesInWindow - 1; - C.Row = minMax(Y, 1, displayLineCount()); - } - BufferCoord vCaret = displayToBufferPos(C); - if ((caretX() != vCaret.Char) || (caretY() != vCaret.Line)) { - // changes to line / column in one go - incPaintLock(); - auto action = finally([this]{ - decPaintLock(); - }); - internalSetCaretXY(vCaret); - - // if MouseCapture is True we're changing selection. otherwise we're dragging -// if (mouseCapture()) - setBlockEnd(caretXY()); - } - computeScroll(iMousePos.x(), iMousePos.y()); + doMouseScroll(false); +} + +void SynEdit::onDraggingScrollTimeout() +{ + doMouseScroll(true); } diff --git a/RedPandaIDE/qsynedit/SynEdit.h b/RedPandaIDE/qsynedit/SynEdit.h index 596bdc63..da0571d0 100644 --- a/RedPandaIDE/qsynedit/SynEdit.h +++ b/RedPandaIDE/qsynedit/SynEdit.h @@ -432,11 +432,10 @@ protected: private: void clearAreaList(SynEditingAreaList areaList); void computeCaret(int X, int Y); - void computeScroll(int X, int Y); + void computeScroll(int X, int Y, bool isDragging); void incPaintLock(); void decPaintLock(); - bool mouseCapture(); int clientWidth(); int clientHeight(); int clientTop(); @@ -562,6 +561,7 @@ private: void doComment(); void doUncomment(); void doToggleComment(); + void doMouseScroll(bool isDragging); private slots: @@ -575,6 +575,7 @@ private slots: void onLinesPutted(int index, int count); void onRedoAdded(); void onScrollTimeout(); + void onDraggingScrollTimeout(); void onUndoAdded(); void onSizeOrFontChanged(bool bFont); void onChanged(); @@ -701,6 +702,7 @@ private: BufferCoord mDragCaretSave; BufferCoord mDragSelBeginSave; BufferCoord mDragSelEndSave; + bool mDragging; friend class SynEditTextPainter; diff --git a/RedPandaIDE/qsynedit/TextBuffer.cpp b/RedPandaIDE/qsynedit/TextBuffer.cpp index 9c74a3df..f94ef389 100644 --- a/RedPandaIDE/qsynedit/TextBuffer.cpp +++ b/RedPandaIDE/qsynedit/TextBuffer.cpp @@ -493,7 +493,7 @@ void SynEditStringList::insertText(int Index, const QString &NewText) } if (NewText.isEmpty()) return; - QStringList lines = TextToLines(NewText); + QStringList lines = textToLines(NewText); insertStrings(Index,lines); } @@ -540,14 +540,14 @@ void SynEditStringList::loadFromFile(const QString& filename, const QByteArray& allAscii = isTextAllAscii(line); } if (allAscii) { - addItem(TrimRight(QString::fromLatin1(line))); + addItem(trimRight(QString::fromLatin1(line))); } else { QString newLine = codec->toUnicode(line.constData(),line.length(),&state); if (state.invalidChars>0) { needReread = true; break; } - addItem(TrimRight(newLine)); + addItem(trimRight(newLine)); } if (file.atEnd()){ break; @@ -580,7 +580,7 @@ void SynEditStringList::loadFromFile(const QString& filename, const QByteArray& QString line; internalClear(); while (textStream.readLineInto(&line)) { - addItem(TrimRight(line)); + addItem(trimRight(line)); } emit inserted(0,mList.count()); } diff --git a/RedPandaIDE/qsynedit/Types.cpp b/RedPandaIDE/qsynedit/Types.cpp index e4e985eb..0de4c4bf 100644 --- a/RedPandaIDE/qsynedit/Types.cpp +++ b/RedPandaIDE/qsynedit/Types.cpp @@ -239,3 +239,32 @@ bool BufferCoord::operator==(const BufferCoord &coord) { return coord.Char == Char && coord.Line == Line; } + +bool BufferCoord::operator>=(const BufferCoord &coord) +{ + return (Line > coord.Line) + || (Line == coord.Line && Char >= coord.Char); +} + +bool BufferCoord::operator>(const BufferCoord &coord) +{ + return (Line > coord.Line) + || (Line == coord.Line && Char > coord.Char); +} + +bool BufferCoord::operator<(const BufferCoord &coord) +{ + return (Line < coord.Line) + || (Line == coord.Line && Char < coord.Char); +} + +bool BufferCoord::operator<=(const BufferCoord &coord) +{ + return (Line < coord.Line) + || (Line == coord.Line && Char <= coord.Char); +} + +bool BufferCoord::operator!=(const BufferCoord &coord) +{ + return coord.Char != Char || coord.Line != Line; +} diff --git a/RedPandaIDE/qsynedit/Types.h b/RedPandaIDE/qsynedit/Types.h index ce7fe313..5df31c40 100644 --- a/RedPandaIDE/qsynedit/Types.h +++ b/RedPandaIDE/qsynedit/Types.h @@ -11,6 +11,11 @@ struct BufferCoord { int Char; int Line; bool operator==(const BufferCoord& coord); + bool operator>=(const BufferCoord& coord); + bool operator>(const BufferCoord& coord); + bool operator<(const BufferCoord& coord); + bool operator<=(const BufferCoord& coord); + bool operator!=(const BufferCoord& coord); }; class SynEdit; diff --git a/RedPandaIDE/settings.cpp b/RedPandaIDE/settings.cpp index 29adba9e..b3896e40 100644 --- a/RedPandaIDE/settings.cpp +++ b/RedPandaIDE/settings.cpp @@ -2924,24 +2924,24 @@ Settings::Debugger::Debugger(Settings *settings):_Base(settings, SETTING_DEBUGGE } -bool Settings::Debugger::showCommandLog() const +bool Settings::Debugger::enableDebugConsole() const { - return mShowCommandLog; + return mEnableDebugConsole; } -void Settings::Debugger::setShowCommandLog(bool showCommandLog) +void Settings::Debugger::setEnableDebugConsole(bool showCommandLog) { - mShowCommandLog = showCommandLog; + mEnableDebugConsole = showCommandLog; } -bool Settings::Debugger::showAnnotations() const +bool Settings::Debugger::showDetailLog() const { - return mShowAnnotations; + return mShowDetailLog; } -void Settings::Debugger::setShowAnnotations(bool showAnnotations) +void Settings::Debugger::setShowDetailLog(bool showAnnotations) { - mShowAnnotations = showAnnotations; + mShowDetailLog = showAnnotations; } QString Settings::Debugger::fontName() const @@ -3004,6 +3004,16 @@ void Settings::Debugger::setAutosaveWatches(bool newAutosaveWatches) mAutosaveWatches = newAutosaveWatches; } +bool Settings::Debugger::openCPUInfoWhenSignaled() const +{ + return mOpenCPUInfoWhenSignaled; +} + +void Settings::Debugger::setOpenCPUInfoWhenSignaled(bool newOpenCPUInfoWhenSignaled) +{ + mOpenCPUInfoWhenSignaled = newOpenCPUInfoWhenSignaled; +} + bool Settings::Debugger::autosaveBreakpoints() const { return mAutosaveBreakpoints; @@ -3046,8 +3056,8 @@ void Settings::Debugger::setOnlyShowMono(bool onlyShowMono) void Settings::Debugger::doSave() { - saveValue("show_command_log", mShowCommandLog); - saveValue("show_annotations", mShowAnnotations); + saveValue("enable_debug_console", mEnableDebugConsole); + saveValue("show_detail_log", mShowDetailLog); saveValue("font_name",mFontName); saveValue("only_show_mono",mOnlyShowMono); saveValue("font_size",mFontSize); @@ -3058,13 +3068,14 @@ void Settings::Debugger::doSave() saveValue("skip_custom_lib", mSkipCustomLibraries); saveValue("autosave_breakpoints",mAutosaveBreakpoints); saveValue("autosave_watches",mAutosaveWatches); + saveValue("open_cpu_info_when_signaled",mOpenCPUInfoWhenSignaled); } void Settings::Debugger::doLoad() { - mShowCommandLog = boolValue("show_command_log",true); - mShowAnnotations = boolValue("show_annotations",false); + mEnableDebugConsole = boolValue("enable_debug_console",true); + mShowDetailLog = boolValue("show_detail_log",false); mFontName = stringValue("font_name","Consolas"); mOnlyShowMono = boolValue("only_show_mono",true); mFontSize = intValue("font_size",12); @@ -3075,6 +3086,7 @@ void Settings::Debugger::doLoad() mSkipCustomLibraries = boolValue("skip_custom_lib",false); mAutosaveBreakpoints = boolValue("autosave_breakpoints",true); mAutosaveWatches = boolValue("autosave_watches",true); + mOpenCPUInfoWhenSignaled = boolValue("open_cpu_info_when_signaled",true); } Settings::History::History(Settings *settings):_Base(settings, SETTING_HISTORY) diff --git a/RedPandaIDE/settings.h b/RedPandaIDE/settings.h index 23bfb885..3bc1450b 100644 --- a/RedPandaIDE/settings.h +++ b/RedPandaIDE/settings.h @@ -930,11 +930,11 @@ public: class Debugger: public _Base { public: explicit Debugger(Settings* settings); - bool showCommandLog() const; - void setShowCommandLog(bool showCommandLog); + bool enableDebugConsole() const; + void setEnableDebugConsole(bool showCommandLog); - bool showAnnotations() const; - void setShowAnnotations(bool showAnnotations); + bool showDetailLog() const; + void setShowDetailLog(bool showAnnotations); bool onlyShowMono() const; void setOnlyShowMono(bool onlyShowMono); @@ -964,9 +964,12 @@ public: bool autosaveWatches() const; void setAutosaveWatches(bool newAutosaveWatches); + bool openCPUInfoWhenSignaled() const; + void setOpenCPUInfoWhenSignaled(bool newOpenCPUInfoWhenSignaled); + private: - bool mShowCommandLog; - bool mShowAnnotations; + bool mEnableDebugConsole; + bool mShowDetailLog; QString mFontName; bool mOnlyShowMono; int mFontSize; @@ -977,6 +980,7 @@ public: bool mSkipCustomLibraries; bool mAutosaveBreakpoints; bool mAutosaveWatches; + bool mOpenCPUInfoWhenSignaled; // _Base interface protected: diff --git a/RedPandaIDE/settingsdialog/debuggeneralwidget.cpp b/RedPandaIDE/settingsdialog/debuggeneralwidget.cpp index b4255ed7..a14a0975 100644 --- a/RedPandaIDE/settingsdialog/debuggeneralwidget.cpp +++ b/RedPandaIDE/settingsdialog/debuggeneralwidget.cpp @@ -20,13 +20,14 @@ void DebugGeneralWidget::doLoad() ui->chkOnlyMono->setChecked(pSettings->debugger().onlyShowMono()); ui->cbFont->setCurrentFont(QFont(pSettings->debugger().fontName())); ui->sbFontSize->setValue(pSettings->debugger().fontSize()); - ui->chkShowLog->setChecked(pSettings->debugger().showCommandLog()); - ui->chkShowFullAnnotation->setChecked(pSettings->debugger().showAnnotations()); + ui->grpEnableDebugConsole->setChecked(pSettings->debugger().enableDebugConsole()); + ui->chkShowDetailLog->setChecked(pSettings->debugger().showDetailLog()); if (pSettings->debugger().useIntelStyle()) { ui->rbIntel->setChecked(true); } else { ui->rbATT->setChecked(true); } + ui->chkShowCPUWhenSignaled->setChecked(pSettings->debugger().openCPUInfoWhenSignaled()); ui->chkBlendMode->setChecked(pSettings->debugger().blendMode()); ui->chkSkipSystemLib->setChecked(pSettings->debugger().skipSystemLibraries()); ui->chkSkipProjectLib->setChecked(pSettings->debugger().skipProjectLibraries()); @@ -40,8 +41,9 @@ void DebugGeneralWidget::doSave() pSettings->debugger().setOnlyShowMono(ui->chkOnlyMono->isChecked()); pSettings->debugger().setFontName(ui->cbFont->currentFont().family()); pSettings->debugger().setFontSize(ui->sbFontSize->value()); - pSettings->debugger().setShowCommandLog(ui->chkShowLog->isChecked()); - pSettings->debugger().setShowAnnotations(ui->chkShowFullAnnotation->isChecked()); + pSettings->debugger().setEnableDebugConsole(ui->grpEnableDebugConsole->isChecked()); + pSettings->debugger().setShowDetailLog(ui->chkShowDetailLog->isChecked()); + pSettings->debugger().setOpenCPUInfoWhenSignaled(ui->chkShowCPUWhenSignaled); pSettings->debugger().setUseIntelStyle(ui->rbIntel->isChecked()); pSettings->debugger().setBlendMode(ui->chkBlendMode->isChecked()); pSettings->debugger().setSkipSystemLibraries(ui->chkSkipSystemLib->isChecked()); diff --git a/RedPandaIDE/settingsdialog/debuggeneralwidget.ui b/RedPandaIDE/settingsdialog/debuggeneralwidget.ui index 00be2fab..19a9a28a 100644 --- a/RedPandaIDE/settingsdialog/debuggeneralwidget.ui +++ b/RedPandaIDE/settingsdialog/debuggeneralwidget.ui @@ -6,7 +6,7 @@ 0 0 - 677 + 704 563 @@ -36,7 +36,7 @@ - + Debug Console @@ -143,16 +143,9 @@ - + - Show debug logs in the debug console - - - - - - - Show full gdb annotations + Show detail debug logs @@ -182,6 +175,13 @@ + + + + Show CPU Window when signal received + + + diff --git a/RedPandaIDE/settingsdialog/environmentfileassociationwidget.cpp b/RedPandaIDE/settingsdialog/environmentfileassociationwidget.cpp index 89c70630..39e007ab 100644 --- a/RedPandaIDE/settingsdialog/environmentfileassociationwidget.cpp +++ b/RedPandaIDE/settingsdialog/environmentfileassociationwidget.cpp @@ -4,7 +4,6 @@ #include "../settings.h" #include -#include #include EnvironmentFileAssociationWidget::EnvironmentFileAssociationWidget(const QString& name, const QString& group, QWidget *parent) : diff --git a/RedPandaIDE/shortcutmanager.h b/RedPandaIDE/shortcutmanager.h index 339aa989..cf4759bc 100644 --- a/RedPandaIDE/shortcutmanager.h +++ b/RedPandaIDE/shortcutmanager.h @@ -26,8 +26,6 @@ public: void setShortcuts(QList shortcuts); void applyTo(QList actions); void applyTo(QAction* action); -signals: -private: private: QMap mShortcuts; diff --git a/RedPandaIDE/symbolusagemanager.h b/RedPandaIDE/symbolusagemanager.h index b788d733..c5cac2ce 100644 --- a/RedPandaIDE/symbolusagemanager.h +++ b/RedPandaIDE/symbolusagemanager.h @@ -22,7 +22,6 @@ public: void reset(); PSymbolUsage findUsage(const QString& fullName) const; void updateUsage(const QString& symbol, int count); -signals: private: QHash mUsages; }; diff --git a/RedPandaIDE/thememanager.h b/RedPandaIDE/thememanager.h index 9dd425f3..23a8e65d 100644 --- a/RedPandaIDE/thememanager.h +++ b/RedPandaIDE/thememanager.h @@ -86,7 +86,6 @@ class ThemeManager : public QObject public: explicit ThemeManager(QObject *parent = nullptr); PAppTheme theme(const QString& themeName); -signals: }; #endif // THEMEMANAGER_H diff --git a/RedPandaIDE/todoparser.h b/RedPandaIDE/todoparser.h index 7cbf8c74..31e91f42 100644 --- a/RedPandaIDE/todoparser.h +++ b/RedPandaIDE/todoparser.h @@ -64,7 +64,6 @@ public: void parseFile(const QString& filename); bool parsing() const; -signals: private: TodoThread* mThread; QRecursiveMutex mMutex; diff --git a/RedPandaIDE/toolsmanager.h b/RedPandaIDE/toolsmanager.h index d14ebe64..9f6bc1e1 100644 --- a/RedPandaIDE/toolsmanager.h +++ b/RedPandaIDE/toolsmanager.h @@ -24,8 +24,6 @@ public: const QList &tools() const; PToolItem findTool(const QString& title); void setTools(const QList &newTools); - -signals: private: QList mTools; }; diff --git a/RedPandaIDE/utils.cpp b/RedPandaIDE/utils.cpp index 6132c124..3dab6c78 100644 --- a/RedPandaIDE/utils.cpp +++ b/RedPandaIDE/utils.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -292,25 +291,25 @@ QString toLocalPath(const QString &filename) return newPath; } -QStringList TextToLines(const QString &text) +QStringList textToLines(const QString &text) { QTextStream stream(&((QString&)text),QIODevice::ReadOnly); - return ReadStreamToLines(&stream); + return readStreamToLines(&stream); } -QStringList ReadFileToLines(const QString& fileName, QTextCodec* codec) +QStringList readFileToLines(const QString& fileName, QTextCodec* codec) { QFile file(fileName); if (file.open(QFile::ReadOnly)) { QTextStream stream(&file); stream.setCodec(codec); stream.setAutoDetectUnicode(false); - return ReadStreamToLines(&stream); + return readStreamToLines(&stream); } return QStringList(); } -QStringList ReadStreamToLines(QTextStream *stream) +QStringList readStreamToLines(QTextStream *stream) { QStringList list; QString s; @@ -320,7 +319,7 @@ QStringList ReadStreamToLines(QTextStream *stream) return list; } -void ReadStreamToLines(QTextStream *stream, +void readStreamToLines(QTextStream *stream, LineProcessFunc lineFunc) { QString s; @@ -329,20 +328,20 @@ void ReadStreamToLines(QTextStream *stream, } } -void TextToLines(const QString &text, LineProcessFunc lineFunc) +void textToLines(const QString &text, LineProcessFunc lineFunc) { QTextStream stream(&((QString&)text),QIODevice::ReadOnly); - ReadStreamToLines(&stream,lineFunc); + readStreamToLines(&stream,lineFunc); } -void ReadFileToLines(const QString &fileName, QTextCodec *codec, LineProcessFunc lineFunc) +void readFileToLines(const QString &fileName, QTextCodec *codec, LineProcessFunc lineFunc) { QFile file(fileName); if (file.open(QFile::ReadOnly)) { QTextStream stream(&file); stream.setCodec(codec); stream.setAutoDetectUnicode(false); - ReadStreamToLines(&stream, lineFunc); + readStreamToLines(&stream, lineFunc); } } @@ -402,7 +401,7 @@ void inflateRect(QRect &rect, int dx, int dy) rect.setBottom(rect.bottom()+dy); } -QString TrimRight(const QString &s) +QString trimRight(const QString &s) { if (s.isEmpty()) return s; @@ -418,7 +417,7 @@ QString TrimRight(const QString &s) } } -bool StringIsBlank(const QString &s) +bool stringIsBlank(const QString &s) { for (QChar ch:s) { if (ch != ' ' && ch != '\t') @@ -427,7 +426,7 @@ bool StringIsBlank(const QString &s) return true; } -QString TrimLeft(const QString &s) +QString trimLeft(const QString &s) { if (s.isEmpty()) return s; @@ -503,7 +502,7 @@ QString changeFileExt(const QString& filename, QString ext) } } -QStringList ReadFileToLines(const QString &fileName) +QStringList readFileToLines(const QString &fileName) { QFile file(fileName); if (file.size()<=0) @@ -540,7 +539,7 @@ QStringList ReadFileToLines(const QString &fileName) return result; } -void StringsToFile(const QStringList &list, const QString &fileName) +void stringsToFile(const QStringList &list, const QString &fileName) { QFile file(fileName); if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { @@ -749,7 +748,7 @@ QString fromByteArray(const QByteArray &s) return QString::fromLocal8Bit(s); } -QString LinesToText(const QStringList &lines) +QString linesToText(const QStringList &lines) { return lines.join("\n"); } @@ -832,7 +831,7 @@ void executeFile(const QString &fileName, const QString ¶ms, const QString & ); } -void StringToFile(const QString &str, const QString &fileName) +void stringToFile(const QString &str, const QString &fileName) { QFile file(fileName); if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { @@ -847,7 +846,7 @@ bool removeFile(const QString &filename) return file.remove(); } -QByteArray ReadFileToByteArray(const QString &fileName) +QByteArray readFileToByteArray(const QString &fileName) { QFile file(fileName); if (file.open(QFile::ReadOnly)) { @@ -894,3 +893,40 @@ bool readRegistry(HKEY key,const QByteArray& subKey, const QByteArray& name, QSt delete [] buffer; return true; } + +QList splitByteArrayToLines(const QByteArray &content) +{ + QList lines; + const char* p =content.constData(); + const char* end = p+content.length(); + const char* lineStart = p; + QByteArray line; + while (p<=end) { + char ch=*p; + switch(ch) { + case '\r': + line = QByteArray(lineStart, p-lineStart); + lines.append(line); + p++; + if (*p=='\n') + p++; + lineStart = p; + break; + case '\n': + line = QByteArray(lineStart, p-lineStart); + lines.append(line); + p++; + lineStart = p; + break; + default: + p++; + } + } + if (lineStart>end) { + lines.append(""); + } else { + line = QByteArray(lineStart, end-lineStart+1); + lines.append(line); + } + return lines; +} diff --git a/RedPandaIDE/utils.h b/RedPandaIDE/utils.h index 39fd41a5..7380e2f4 100644 --- a/RedPandaIDE/utils.h +++ b/RedPandaIDE/utils.h @@ -143,28 +143,30 @@ bool programHasConsole(const QString& filename); QString toLocalPath(const QString& filename); using LineProcessFunc = std::function; -QStringList ReadStreamToLines(QTextStream* stream); -void ReadStreamToLines(QTextStream* stream, LineProcessFunc lineFunc); +QStringList readStreamToLines(QTextStream* stream); +void readStreamToLines(QTextStream* stream, LineProcessFunc lineFunc); -QStringList TextToLines(const QString& text); -void TextToLines(const QString& text, LineProcessFunc lineFunc); -QString LinesToText(const QStringList& lines); +QStringList textToLines(const QString& text); +void textToLines(const QString& text, LineProcessFunc lineFunc); +QString linesToText(const QStringList& lines); + +QList splitByteArrayToLines(const QByteArray& content); QString parseMacros(const QString& s); -QStringList ReadFileToLines(const QString& fileName, QTextCodec* codec); -QStringList ReadFileToLines(const QString& fileName); -QByteArray ReadFileToByteArray(const QString& fileName); -void ReadFileToLines(const QString& fileName, QTextCodec* codec, LineProcessFunc lineFunc); -void StringsToFile(const QStringList& list, const QString& fileName); -void StringToFile(const QString& str, const QString& fileName); +QStringList readFileToLines(const QString& fileName, QTextCodec* codec); +QStringList readFileToLines(const QString& fileName); +QByteArray readFileToByteArray(const QString& fileName); +void readFileToLines(const QString& fileName, QTextCodec* codec, LineProcessFunc lineFunc); +void stringsToFile(const QStringList& list, const QString& fileName); +void stringToFile(const QString& str, const QString& fileName); void decodeKey(int combinedKey, int& key, Qt::KeyboardModifiers& modifiers); void inflateRect(QRect& rect, int delta); void inflateRect(QRect& rect, int dx, int dy); -QString TrimRight(const QString& s); -QString TrimLeft(const QString& s); -bool StringIsBlank(const QString& s); +QString trimRight(const QString& s); +QString trimLeft(const QString& s); +bool stringIsBlank(const QString& s); int compareFileModifiedTime(const QString& filename1, const QString& filename2); QByteArray getHTTPBody(const QByteArray& content); bool haveGoodContrast(const QColor& c1, const QColor &c2); diff --git a/RedPandaIDE/version.h b/RedPandaIDE/version.h index ddab7777..ee6dee7a 100644 --- a/RedPandaIDE/version.h +++ b/RedPandaIDE/version.h @@ -2,6 +2,6 @@ #define VERSION_H #include -#define DEVCPP_VERSION "beta.0.9.4" +#define DEVCPP_VERSION "beta.0.10.2" #endif // VERSION_H diff --git a/RedPandaIDE/widgets/aboutdialog.ui b/RedPandaIDE/widgets/aboutdialog.ui index 8722dbbb..ed260e9a 100644 --- a/RedPandaIDE/widgets/aboutdialog.ui +++ b/RedPandaIDE/widgets/aboutdialog.ui @@ -54,6 +54,9 @@ + + true + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/RedPandaIDE/widgets/cpudialog.cpp b/RedPandaIDE/widgets/cpudialog.cpp index 75d8ff4d..8494e430 100644 --- a/RedPandaIDE/widgets/cpudialog.cpp +++ b/RedPandaIDE/widgets/cpudialog.cpp @@ -57,7 +57,7 @@ void CPUDialog::updateInfo() if (pMainWindow->debugger()->executing()) { // Load the registers.. sendSyntaxCommand(); - pMainWindow->debugger()->sendCommand("info", "registers"); + pMainWindow->debugger()->sendCommand("-data-list-register-values", "N"); if (ui->chkBlendMode->isChecked()) pMainWindow->debugger()->sendCommand("disas", "/s"); else @@ -65,14 +65,12 @@ void CPUDialog::updateInfo() } } -void CPUDialog::setDisassembly(const QStringList &lines) +void CPUDialog::setDisassembly(const QString& file, const QString& funcName,const QStringList& lines) { - if (lines.size()>0) { - ui->txtFunctionName->setText(lines[0]); - } + ui->txtFunctionName->setText(QString("%1:%2").arg(file, funcName)); int activeLine = -1; ui->txtCode->lines()->clear(); - for (int i=1;i")) { activeLine = i; @@ -80,16 +78,16 @@ void CPUDialog::setDisassembly(const QStringList &lines) ui->txtCode->lines()->add(line); } if (activeLine!=-1) - ui->txtCode->setCaretXY(BufferCoord{1,activeLine}); + ui->txtCode->setCaretXYCentered(true,BufferCoord{1,activeLine}); } void CPUDialog::sendSyntaxCommand() { // Set disassembly flavor if (ui->rdIntel->isChecked()) { - pMainWindow->debugger()->sendCommand("set disassembly-flavor", "intel"); + pMainWindow->debugger()->sendCommand("-gdb-set", "disassembly-flavor intel"); } else { - pMainWindow->debugger()->sendCommand("set disassembly-flavor", "att"); + pMainWindow->debugger()->sendCommand("-gdb-set", "disassembly-flavor att"); } } diff --git a/RedPandaIDE/widgets/cpudialog.h b/RedPandaIDE/widgets/cpudialog.h index 870e2af8..6cbcbc17 100644 --- a/RedPandaIDE/widgets/cpudialog.h +++ b/RedPandaIDE/widgets/cpudialog.h @@ -15,7 +15,8 @@ public: explicit CPUDialog(QWidget *parent = nullptr); ~CPUDialog(); void updateInfo(); - void setDisassembly(const QStringList& lines); +public slots: + void setDisassembly(const QString& file, const QString& funcName,const QStringList& lines); signals: void closed(); private: diff --git a/RedPandaIDE/widgets/functiontooltipwidget.h b/RedPandaIDE/widgets/functiontooltipwidget.h index d4d8f14f..aab4ab22 100644 --- a/RedPandaIDE/widgets/functiontooltipwidget.h +++ b/RedPandaIDE/widgets/functiontooltipwidget.h @@ -37,7 +37,6 @@ public: const QString &functionFullName() const; void setFunctioFullName(const QString &newFunctioFullName); -signals: private: QStringList splitArgs(QString args); private: diff --git a/RedPandaIDE/widgets/qconsole.cpp b/RedPandaIDE/widgets/qconsole.cpp index bc7b860d..2697f339 100644 --- a/RedPandaIDE/widgets/qconsole.cpp +++ b/RedPandaIDE/widgets/qconsole.cpp @@ -43,7 +43,7 @@ QConsole::QConsole(QWidget *parent): mBlinkStatus = 0; //enable input method setAttribute(Qt::WA_InputMethodEnabled); - setMouseTracking(false); +// setMouseTracking(false); recalcCharExtent(); mScrollTimer = new QTimer(this); mScrollTimer->setInterval(100); @@ -147,7 +147,7 @@ void QConsole::addLine(const QString &line) void QConsole::addText(const QString &text) { - QStringList lst = TextToLines(text); + QStringList lst = textToLines(text); for (const QString& line:lst) { addLine(line); } @@ -276,7 +276,7 @@ void QConsole::setTopRow(int value) int QConsole::maxScrollHeight() { - return std::max(mContents.rows()-mRowsInWindow,1); + return std::max(mContents.rows()-mRowsInWindow+1,1); } void QConsole::updateScrollbars() @@ -504,7 +504,7 @@ void QConsole::mousePressEvent(QMouseEvent *event) //fKbdHandler.ExecuteMouseDown(Self, Button, Shift, X, Y); if (button == Qt::LeftButton) { - setMouseTracking(true); +// setMouseTracking(true); RowColumn mousePosRC = pixelsToNearestRowColumn(X,Y); LineChar mousePos = mContents.rowColumnToLineChar(mousePosRC); //I couldn't track down why, but sometimes (and definitely not all the time) @@ -522,7 +522,7 @@ void QConsole::mouseReleaseEvent(QMouseEvent *event) { QAbstractScrollArea::mouseReleaseEvent(event); mScrollTimer->stop(); - setMouseTracking(false); +// setMouseTracking(false); } diff --git a/RedPandaIDE/widgets/signalmessagedialog.cpp b/RedPandaIDE/widgets/signalmessagedialog.cpp new file mode 100644 index 00000000..e94acb85 --- /dev/null +++ b/RedPandaIDE/widgets/signalmessagedialog.cpp @@ -0,0 +1,29 @@ +#include "signalmessagedialog.h" +#include "ui_signalmessagedialog.h" + +SignalMessageDialog::SignalMessageDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::SignalMessageDialog) +{ + ui->setupUi(this); +} + +SignalMessageDialog::~SignalMessageDialog() +{ + delete ui; +} + +void SignalMessageDialog::setMessage(const QString &message) +{ + ui->lblMessage->setText(message); +} + +bool SignalMessageDialog::openCPUInfo() +{ + return ui->chkOpenCPUInfo->isChecked(); +} + +void SignalMessageDialog::setOpenCPUInfo(bool value) +{ + ui->chkOpenCPUInfo->setChecked(value); +} diff --git a/RedPandaIDE/widgets/signalmessagedialog.h b/RedPandaIDE/widgets/signalmessagedialog.h new file mode 100644 index 00000000..a0fd4fb6 --- /dev/null +++ b/RedPandaIDE/widgets/signalmessagedialog.h @@ -0,0 +1,25 @@ +#ifndef SIGNALMESSAGEDIALOG_H +#define SIGNALMESSAGEDIALOG_H + +#include + +namespace Ui { +class SignalMessageDialog; +} + +class SignalMessageDialog : public QDialog +{ + Q_OBJECT + +public: + explicit SignalMessageDialog(QWidget *parent = nullptr); + ~SignalMessageDialog(); + void setMessage(const QString& message); + bool openCPUInfo(); + void setOpenCPUInfo(bool value); + +private: + Ui::SignalMessageDialog *ui; +}; + +#endif // SIGNALMESSAGEDIALOG_H diff --git a/RedPandaIDE/widgets/signalmessagedialog.ui b/RedPandaIDE/widgets/signalmessagedialog.ui new file mode 100644 index 00000000..4c6deff6 --- /dev/null +++ b/RedPandaIDE/widgets/signalmessagedialog.ui @@ -0,0 +1,90 @@ + + + SignalMessageDialog + + + + 0 + 0 + 400 + 240 + + + + Signal Received + + + + + + + 0 + 0 + + + + TextLabel + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + Open CPU Info Dialog + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SignalMessageDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SignalMessageDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +