实现代码编辑器

    上一次曾经发布过一篇如何实现一个代码编辑器。今年工作中得空,所以对这个编辑器进一步做了些更新,把名字改成了从CuteC改成了CEditor。主要是重写了软件的界面(最终还原朴素),重写了编辑控件语法高亮的着色方式,还有增加了一个简单的SSH客户端和SFTP文件编辑的功能。感觉基本的功能已经实现了,所以再次写点东西记录一下。并且发布一下编辑控件的源代码,有兴趣的可下载下来看看,虽然代码写得比较乱。
    上个版本:http://www.cnblogs.com/linxr/archive/2011/10/30/2229256.html
    编辑控件源码链接:https://files.cnblogs.com/linxr/LEdit.rar
    软件下载链接:https://files.cnblogs.com/linxr/CEditor.rar
    软件界面:
       


一、编辑控件
 除了上一次写到的一些内容外,主要在编辑控件的语法高亮上做了修改。
 1. 原来的颜色信息是在绘制每行时,动态分词查找关键字,形成一个颜色数组供绘制模块使用。这种方式的优点就是逻辑简单,绘制代码很容易编写。但是缺点就是,每次绘制一行,都要重新产生颜色数组,影响效率;其二,在一些场合下,高亮不是依赖于关键字,这时候这种方法就无能为力了。
 2. 考虑到上面的缺点,对编辑控件做了修改。去除了颜色数组,改用标注信息来标注颜色字体信息。所以行数据经过着色之后不再是原来的内容了。
 
    例如一行数据:
    int main( int argc, char ** argv );
    那么经过着色后,该行的数据会变成:
    \ec3,0~int\ezc~ main( \ec3,0~int\ezc~ argc, \ec3,0~char\ezc~ ** argv );
    其中,int和char被着色,标注信息为:
    \ec3,0~ 和 \ezc~
    着色信息以\e(0x1b)开始,以~结束。c表示颜色,z表示还原格式格式。
    
     着色完成后,绘制模块在进行绘制文本信息时,从头到尾,扫描字符串,根据着色信息,不断的设置还原DC的颜色信息,直到绘制完成。
 3. 标注颜色带来了一些额外的问题,主要表现在:
    a.光标位置到字符串中的位置的转换的计算。
    b.获取编辑器的内容时,要清除所有的标注信息,影响一定的性能。
    c.计算tab键的宽度时,不能用tab键在字符串中的位置来计算,要考虑标注信息。
    d.光标在屏幕中的位置的计算,要根据光标前面数据的字体来实时计算宽度。
 
二、函数列表
    对于代码编辑软件来说,函数符号列表功能是必备的,就算是纯写C的人来说,有一个函数列表会大大提高滚动查找代码的效率。我虽然写了一个C语言的解释器,对符号的解析稍作修改就可以实现,但是各种各样的语言,我就无能为力了。好在有ctags.exe,他可以支持非常的语言符号分析。我还是直接拿来用吧,然后再加上一个树形控件,就能实现简单实用的功能。
    我调用ctags.exe的代码片段,主要是调用了ctags.exe,将结果保存到一个文件,然后我们再解析这个文件:
   
 CString strParam;
 CString strTags = strFilePath + _T(".tags.txt");
 strParam.Format( _T("-f \"%s\" --language-force=C++ -n \"%s\"" ), strTags.GetBuffer(0), strFilePath.GetBuffer(0) );

 SHELLEXECUTEINFO   sei;
 ZeroMemory( &sei, sizeof(SHELLEXECUTEINFO) );
 sei.cbSize = sizeof(SHELLEXECUTEINFO);
 sei.fMask = SEE_MASK_NOCLOSEPROCESS;
 sei.hwnd = NULL;
 sei.lpVerb = NULL;
 sei.lpFile = "ctags.exe";
 sei.lpParameters = strParam.GetBuffer(0);
 sei.lpDirectory = CLxrFile::GetExecutePath().GetBuffer(0);
 sei.nShow = SW_HIDE;
 sei.hInstApp = NULL;
 ShellExecuteEx(&sei);
 WaitForSingleObject( sei.hProcess, INFINITE );
 /*
 ** 可以看到就是调用了ShellExecuteEx,但是有几个地方可以提一下:
 ** 1. sei.nShow = SW_HIDE; 这使得进程启动时不会显示控制台窗口。
 ** 2. WaitForSingleObject( sei.hProcess, INFINITE );
 **    等待进程结束,这个很重要,不然ctags启动后,我们无法同步获取结果。
 */
 
    
    ctags.exe支持的语言,可以用命令 ctags.exe --list-languages 查看:
        Asm
        Asp
        Awk
        Basic
        BETA
        C
        C++
        C#
        Cobol
        Eiffel
        Erlang
        Fortran
        HTML
        Java
        JavaScript
        Lisp
        Lua
        Make
        Pascal
        Perl
        PHP
        Python
        REXX
        Ruby
        Scheme
        Sh
        SLang
        SML
        SQL
        Tcl
        Vera
        Verilog
        Vim
        YACC
    可以看到,他几乎涵盖了所有流行的语言,而他的执行文件大小只有256kb,太强悍了,让我非常的佩服。

三、脚本管理
    让编辑软件支持脚本是必要的,不仅仅可以对常用的功能提供扩展。我实现了类C的解析执行,所以对简单的计算功能,软件的功能,都能给外部脚本提供接口函数,让脚本轻松的操作编辑器,或者做一些好玩的事情。我主要做的是将脚本直接映射到右键菜单,当添加一个脚本时,他将直接被添加进右键菜单。并且支持多级目录。
    例如,我实现了几个接口供脚本使用:
    
  int ceditor_exe_2( char * cmd, char * out );
  该函数用于执行cmd指令,out为输出结果。cmd为编辑器的的命令,形如rep_sel$hello world$。
  int ceditor_exe_4( char * cmd, char * p1, char *p2, char * out );
  该函数效果同ceditor_exe_2,但是cmd仅是命令,p1,p2分别是两个参数。
  int clear();
  该函数用于清除输出框的内容。
  int ceditor_hotkey( char * ctrlKeys, int vKey, char * scriptPath );
  该函数用于注册热键。

    C的解释器,大家可以看我以前发过的文章,代码可以在CSDN上面找到,搜索"xrc C语言解释器"就能找到,或者试试这个链接:http://download.csdn.net/download/linxren/4204728。在cnblogs上可以看看相关的实现方法,算是讲得比较清楚的吧。
   
四、数据存储
    数据存储在不同的软件中都必须用到,我这里主要是配置的存储和脚本的存储,正好我写了个key-value存储系统,所以这个直接拿来用就非常合适了,效率也不错。跟直接读写硬盘没什么区别,省去了烦人的fopen,fread,fwrite,fclose调用,直接用windows的api更是烦人,所以写这样一个简单的库,非常方便。
    http://www.cnblogs.com/linxr/p/3252541.html,在这里可以看到实现方法和下载到源代码。我觉得这个简单的key-value存储库,比我写的解释器,和这个编辑器本身更加实用,所有的软件都可以用,接口也很简单。无法就是open,set,get,close四个函数。省去了文件操作的各种麻烦。

posted @ 2013-08-13 12:37  linxr  阅读(10441)  评论(1编辑  收藏  举报