相关文章推荐
乐观的皮带  ·  java ...·  1 年前    · 
豁达的丝瓜  ·  Fix issue with ...·  1 年前    · 
玩命的火腿肠  ·  为什么 Android 和 iOS ...·  1 年前    · 

今年开始,折腾脚本,发现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();
			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);
		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调试环境起因基本编辑工作LUA解析代码折叠简单图示效果断点行号获取切换断点显示断点断点显示效果QQ:282397369起因今年开始,折腾脚本,发现LUA确实能解决大问题,与C++配合起来,天衣无缝的感觉,处理各种业务轻松很多。用多了,慢慢发觉有些不爽。最大的问题是,脚本没有编译过程,所有问题得等到运行时才能显现,从而导致脚本调试过程比较低效。那就做一个IDE,先给自己用。基本编辑...
由于本系统是win7,很多网上的软件都安装不了,经过一天的时间尝试,终于把lua搭建成功,并可以成功编译,调试,运行lua代码。 文件附有部署步骤,以及win7/xp 都能正常运行的lua编译器。 网上介绍的LuaForWindows_v5.1.4-45.exe 安装失败,提示**.dll不存在、Lua Devloper Tools 能安装,但安装后不会使用,网上资料特别少,还有其他一些开发工具,都提示**.dll不存在,请重新安装。
require'cv.videoio'--Videostream require'cv.imgproc'--Imageprocessing(resize,crop,drawtext,...) require'nn' localcapture=cv.VideoCapture{device=0} ifnotcapture:isOpened()then print("Failedtoopenthedefaultcamera") os.exit(-1)...
LUA脚本插上图像识别翅膀前言准备知识思路LUA端类实现LUA端调用C++端实现实例调用测试用图测试用LUA代码运行结果总结 DrGraph QQ:282397369 这个春节一直猫在家,不给政府添乱。今天是元宵节,正想出去一趟,微信群看到一条信息,立马就不动了:今天千万不要外出,不然会被病毒笑话的:原来你们躲得过初一,躲不过十五。 那就先把这个十五躲过去,继续宅。 废话少说,其实我用LU...
Lua 调用 Opencv 的方法   最近想用 Lua 调用 Opencv 进行相关像素级操作,如:bitwise_and 或者 bitwise_or,从而完成图像 IoU 的计算。   那么,怎么用 Lua 调用 Opencv 呢?   查了 Torch 的官方文档,发现只有这么几个可以调用的包:   链接:https://github.com/torch/...
findContours(image, mode, method, contours=None, hierarchy=None, offset=None) image:输入的二值图像。 mode:定义轮廓的检索模式,可选项为...