LUA调试环境(一)
LUA调试环境
QQ:282397369
起因
今年开始,折腾脚本,发现LUA确实能解决大问题,与C++配合起来,天衣无缝的感觉,处理各种业务轻松很多。
用多了,慢慢发觉有些不爽。最大的问题是,脚本没有编译过程,所有问题得等到运行时才能显现,从而导致脚本调试过程比较低效。
那就做一个IDE,先给自己用。
基本编辑工作
IDE首先得有一个编辑器。这个直接采用开源的Scintilla即可。结合消息机制,还是比较轻松的。主要工作是抄,或者说是Copy,在网上搜搜就有了。以下是一些简要的内容
LUA解析
SendEditor(SCI_SETLEXER, SCLEX_LUA); SendEditor(SCI_STYLESETFONT, SCE_LUA_IDENTIFIER, (sptr_t)"Courier New"); SendEditor(SCI_STYLESETSIZE, SCE_LUA_IDENTIFIER, fontSize); SendEditor(SCI_STYLESETFONT, SCE_LUA_COMMENTLINE, (sptr_t)"Courier New"); SendEditor(SCI_STYLESETSIZE, SCE_LUA_COMMENTLINE, fontSize); SendEditor(SCI_STYLESETFONT, SCE_LUA_WORD, (sptr_t)"Courier New"); SendEditor(SCI_STYLESETSIZE, SCE_LUA_WORD, fontSize); SendEditor(SCI_STYLESETFONT, SCE_LUA_LITERALSTRING, (sptr_t)"Courier New"); SendEditor(SCI_STYLESETSIZE, SCE_LUA_LITERALSTRING, fontSize); SendEditor(SCI_STYLESETFONT, SCE_LUA_COMMENTDOC, (sptr_t)"Courier New"); SendEditor(SCI_STYLESETSIZE, SCE_LUA_COMMENTDOC, fontSize); SendEditor(SCI_STYLESETITALIC, SCE_LUA_COMMENTLINE, true); SendEditor(SCI_STYLESETITALIC, SCE_LUA_LITERALSTRING, true); SendEditor(SCI_STYLESETITALIC, SCE_LUA_IDENTIFIER, true); SendEditor(SCI_STYLESETITALIC, SCE_LUA_COMMENTDOC, true); SendEditor(SCI_STYLESETBOLD, SCE_LUA_IDENTIFIER, TRUE); SendEditor(SCI_STYLESETBOLD, SCE_LUA_WORD, TRUE); SendEditor(SCI_STYLESETFORE, SCI_SETCODEPAGE, CP_UTF8); SendEditor(SCI_SETKEYWORDS, 0, (sptr_t)"and break do else elseif end false for function if in local nil not or repeat return then true until while"); SendEditor(SCI_STYLESETFORE, SCE_LUA_COMMENTLINE, clGreen); SendEditor(SCI_STYLESETFORE, SCE_LUA_COMMENTDOC, clGreen); SendEditor(SCI_STYLESETFORE, SCE_LUA_NUMBER, clBlue); SendEditor(SCI_STYLESETFORE, SCE_LUA_CHARACTER, clRed); SendEditor(SCI_STYLESETFORE, SCE_LUA_OPERATOR, clGreen); SendEditor(SCI_STYLESETFORE, SCE_LUA_LITERALSTRING, clGreen); SendEditor(SCI_STYLESETFORE, SCE_LUA_IDENTIFIER, clPurple); SendEditor(SCI_STYLESETFORE, SCE_LUA_WORD, clBlue); SendEditor(SCI_SETCARETLINEVISIBLE, TRUE); SendEditor(SCI_SETTABWIDTH, 4); // TAB宽度由默认的8改为4 SendEditor(SCI_SETCARETLINEBACK, RGB(226, 217, 232)); SendEditor(SCI_SETSELBACK, true, RGB(0x9f,0xbb,0xe8) );
代码折叠
现在编程序,代码可折叠是必须的,加上行号显示,成为一个简单标配
SendEditor(SCI_SETMARGINTYPEN, 0, SC_MARGIN_NUMBER); SendEditor(SCI_SETMARGINWIDTHN, 0, 40); SendEditor(SCI_SETMARGINSENSITIVEN, 0, TRUE); //响应鼠标消息 SendEditor(SCI_SETPROPERTY,(sptr_t)"fold",(sptr_t)"1"); SendEditor(SCI_SETPROPERTY,(sptr_t)"fold.compact",(sptr_t)"0"); // 这个一定要关掉!!!否则折叠样式会有问题!!! SCN_UPDATEUI; SendEditor(SCI_SETMARGINTYPEN, MARGIN_FOLD_INDEX, SC_MARGIN_SYMBOL); SendEditor(SCI_SETMARGINMASKN, MARGIN_FOLD_INDEX, SC_MASK_FOLDERS); SendEditor(SCI_SETMARGINWIDTHN, MARGIN_FOLD_INDEX, 11); SendEditor(SCI_SETMARGINSENSITIVEN, MARGIN_FOLD_INDEX, TRUE); SendEditor(SCI_MARKERDEFINEPIXMAP, SC_MARKNUM_FOLDEROPEN, (sptr_t)minus_xpm); SendEditor(SCI_MARKERDEFINEPIXMAP, SC_MARKNUM_FOLDEREND, (sptr_t)plus_xpm); SendEditor(SCI_MARKERDEFINEPIXMAP, SC_MARKNUM_FOLDEROPENMID, (sptr_t)minus_xpm); SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNERCURVE); SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE); SendEditor(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNERCURVE); SendEditor(SCI_MARKERSETBACK, SC_MARKNUM_FOLDERSUB, 0xa0a0a0); SendEditor(SCI_MARKERSETBACK, SC_MARKNUM_FOLDERMIDTAIL, 0xa0a0a0); SendEditor(SCI_MARKERSETBACK, SC_MARKNUM_FOLDERTAIL, 0xa0a0a0); SendEditor(SCI_SETFOLDFLAGS, 16|4, 0);
简单图示效果
在以上基础上,差不多就可以看到效果了。
到此具备一定的基础。
断点
断点功能折腾大半天时间,用Margin怎么试都出不来效果。都准备放弃了。
最终还是放弃采用Margin来实现,等以后有时间了再用Margin
但功能还是想要的。那就自己动手丰衣足食。直接放一个PaintBox在编辑器左侧,稍微试一下,居然有效果
FPaintBox_Assert = new TPaintBox(this); FPaintBox_Assert->Parent = this; FPaintBox_Assert->Width = 15; FPaintBox_Assert->Align = alLeft; FPaintBox_Assert->OnPaint = OnPaintBox_Assert; FPaintBox_Assert->OnMouseUp = OnPaintBox_MouseUp;
那就加上相应的事件处理,其实也就是画出与切换。
行号获取
仔细查看文档,可以取得当前行号,但我想取得显示在界面上的最顶端与最底端的行号,试了很多种方法与消息,无果。
那就,文字识别吧。毕竟OpenCV也用了这么长时间。这个文字识别应该是最简单的,标准的印刷体,标准的数字,搞不定就不好意思了。
TStrings * __fastcall TCbwSynEditor::GetLineNumbers() { cv::Mat mat = CvHelper::MatFromHWND(hEditor, TRect(0, 0, 40, FPaintBox_Assert->Height - 25)); CbwXmlNode * result = new CbwXmlNode("number"); GlobalQuickOcr->OcrNumber(mat, L"Scintilla", true); result->Assign(GlobalQuickOcr->OcrPositionNode); TStrings * lines = new TStringList; for(int i = 0; i < result->ElementNumber; ++i) { UnicodeString text = result->Elements(i)->AttributeValueByName(L"text"); UnicodeString id = THelper::String::GetRegMatchAt(text, L"\\d+"); if(id.Length()) lines->Add(id.ToInt()); } delete result; return lines; }
切换断点
这个主要在PaintBox的点击事件中处理,直接用其MouseUp事件。
void __fastcall TCbwSynEditor::OnPaintBox_MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { int textHeight = GetTextHeight(); int row = Y / textHeight; TStrings * lines = GetLineNumbers(); if(IS_IN_RANGE(row, 0, lines->Count - 2)) { int destLine = lines->Strings[row].ToInt(); int nextLine = lines->Strings[row + 1].ToInt(); if(nextLine == destLine + 1) { ToggleBreakpoint(destLine); FPaintBox_Assert->Repaint(); } else SendEditor(SCI_TOGGLEFOLD, destLine, 0); } delete lines; }
其中的GetTextHeight是取得文字高度,感觉在编辑的时候,应该是一致的。先试了一下,也不知道是否正确,但我是够用的了。
int __fastcall TCbwSynEditor::GetTextHeight() { int result = SendEditor(SCI_TEXTHEIGHT, 1); return result; }
为了兼容后续的工程项目,即多文件,简单设计一个结构:
typedef struct tagBreakPoints { UnicodeString fileName; vector<int> lineNumbers; } TBreakPoints;
那现在的切换操作,也主要是针对内存数据的更新处理
void __fastcall TCbwSynEditor::ToggleBreakpoint(int lineNumber) { TBreakPoints * destItems = NULL; CBW_ITERATOR(vector<TBreakPoints *>, FBreakpoints) { if((*it)->fileName == FFileName) destItems = *it; } if(!destItems) { destItems = new TBreakPoints; destItems->fileName = FFileName; FBreakpoints.push_back(destItems); } int index = -1; CBW_ITERATOR(vector<int>, destItems->lineNumbers) { if(*it == lineNumber) { index = it - destItems->lineNumbers.begin(); break; } } if(index == -1) destItems->lineNumbers.push_back(lineNumber); else destItems->lineNumbers.erase(destItems->lineNumbers.begin() + index); THelper::Debug::AddLog(THelper::FormatString(L"切换第 %d 行 -> %s", lineNumber, GetBreakpointHint()), clBlue); }
断点这块就只剩下显示了。
显示断点
不求专业美观,先解决有无问题。
显示的时候,考虑到代码折叠,那就自己提个小需求,如果断点行被显示出来,就用红点,如果断点行被折叠,那就用暗红点。
void __fastcall TCbwSynEditor::OnPaintBox_Assert(TObject* Sender) { THelper::Graphics::FillCanvas(FPaintBox_Assert->Canvas, TColor(0xFFEFEF), TColor(0xFFEFEF)); TCanvas * canvas = FPaintBox_Assert->Canvas; canvas->Rectangle(0, 0, FPaintBox_Assert->Width, FPaintBox_Assert->Height); int textHeight = GetTextHeight(); int radius = (std::min(FPaintBox_Assert->Width, textHeight) - 5) / 2; TStrings * lines = GetLineNumbers(); for(int i = 0; i < lines->Count; ++i) { int destLineNumber = lines->Strings[i].ToInt(); TColor color = clBlack; if(IsBreakpoint(destLineNumber)) color = clRed; else if(i < lines->Count - 1) { int nextLineNumber = lines->Strings[i + 1].ToInt(); if( (nextLineNumber > destLineNumber + 1) && ContainBreakPoint(destLineNumber, nextLineNumber)) color = TColor(0x0000D0); } if(color != clBlack) { THelper::Graphics::FillCanvas(FPaintBox_Assert->Canvas, color, color); canvas->Ellipse(FPaintBox_Assert->Width / 2 - radius, i * textHeight + textHeight / 2 - radius, FPaintBox_Assert->Width / 2 + radius, i * textHeight + textHeight / 2 + radius); } } delete lines; }
断点显示效果
初步达到预期效果。
下一步再处理调试功能,比如单步运行等。需要再在网上搜罗一下,看多长时间能解决。
- lua 5.3开发调试环境搭建
- 如何在vs (visual studio)调试环境下查看lua的调用栈、变量信息
- Lua开发环境和调试工具
- LUA调试环境(三)
- LUA调试环境(二)
- 【有用】Lua cocos2dx (quick cocos2d x ) Lua调试开发环境搭建资源总结
- lua 5.3开发调试环境搭建
- lua的VS或者VC环境的搭建调试
- 如何在vs (visual studio)调试环境下查看lua的调用栈、变量信息
- Cocos2d-x lua 3.x VS集成Babelua 环境搭建与代码调试
- [Lua] Lua学习笔记(一) 安装调试环境
- vs2010和zbStudio远程调试c和lua开发环境搭建
- Lua cocos2dx (quick cocos2d x ) Lua调试开发环境搭建资源总结
- Windows下lua+redis调试环境搭建
- cocos2dx 3.10 lua环境配置与代码调试
- Cocos2d-Lua VS调试环境
- cocos2dx 3.12 lua环境配置与代码调试_02
- VS2013调试lua环境搭建
- cocos2dx 3.10 lua环境配置与代码调试
- 初识 love2d. Hello World & lua 调试 & iOS 环境运行