概述
编辑器杂谈之一 Scintilla(上)
HuaHope
Scintilla的相关项目很多,官方网站的related中就列举了相当多的。只是恰如有次见到一个评论中说的,自从有了Scintilla,几乎大多数的编辑器都很少自己编写“编辑器”了,完全是加个外壳,当然编辑器控件SynEdit(delphi)、CodeMax等也功不可没。
就Scite_ru、Scite Latex IDE而言,其实并不算是出众的Scintilla相关项目,而ScintillaLua虽然是这里看到了才知道新有了这个项目,也刚去下载了(可惜zip的解压失败,就下载的tgz的),但只是看看配置文件就知道了,其也只不过是Mitchell Foral的一个副产品,之前Mitchell Foral就有Scite Tools和Scite St,再加上后来的Textadept,这几个都是差不多的实现,除了补足SciTE的动态着色之外,还有一个snippet功能,不过也许ScintillaLua可能独立后实现的比以前更完善吧,没有看代码,但是lexer配置倒是丰富了很多,终于几乎实现了Scintilla的所有支持语言,另外一个最大的改进就是许可证终于换成了BSD,比Scite Tools的LGPL要更开放些,以至于SciTE_ru最新的版本就以及迫不及待地整合了ScintillaLua,实现了外部lexer的支持。不过从设计角度而言,Lexer采用外挂的lua脚本,处理能力毕竟有限,虽然使用llpeg灵活性增强了,但是效能无疑更低了,即便是luajit,估计也无法对付稍大一点的文件。Scintilla比较好的项目,Filerx算是不错,可惜很久就不更新了。其余的,就编辑器而言,都没能走出Scintilla的限制,也自然更难超越Scintilla自身的光环。
其实国内基于Scintilla的项目也很多的,但真正自己写编辑器的也有,比如已经商业化的Aptedit,还有MegaxEdit等,MegaxEdit的博客中讲了一些编辑器实现技术,比如折叠等,和Scintilla实现是类似的,只是很可惜,由于没有实物,所以无法评测其功能和性能,不过虽然上面说大多数编辑器完全拿来义不好,但是MegaxEdit完全自己写,甚至字符串查找KMP算法也自己实现,实在也太过于自力更生,看日志好像还自己实现了可配置的状态机,距离正则库也差不远了,只不知道正则库是否也自己写完了:)Megax还曾经到FlexEdit网站评论过,虽然指出没有突出优势的缺点也不算错,但从其日志上描述的技术思想中感觉块着色算法虽然比Scintilla的要好,但是还是不够完善的,比如不允许循环嵌套语言,其实这个限制并不应存在,除非刻意的构造,否则几乎所有的文件中语言再怎么嵌套都是有限的,也是可以分析着色的。另至于嵌套只允许4个子语言,对于html而言就未必够用,而且如果不独立线程,即便是块着色速度对于10万行以上的大文件也依然很慢,不过Megax从09年2月就消失了,一直到这个月才又冒出来更新日志,感觉依然对lex很纠结,估计还有一段路要走。当然还有MadEdit,也是很不错的,16进制和内码做得很好,只是大文件处理能力有限,界面也不够美观。至于国人的flexedit、notepad++等,也多半只是加个壳而已。没有太多需要说的,Notepad++的插件系统倒是不错,现在的插件也非常的多,只是其中很多没有实现界面的插件并没有太多的必要,如果Notepad++实现ScitTE中的lua脚本扩展,编写脚本即可扩展类似的功能,实在没有必要做成dll,从一种扩展走向另一种封闭,只是没有深入研究过其插件系统,感觉整体设计还是不错的,不过距离几乎完全插件化的Eclipse估计还是有所差距。
而国外的自己写编辑器模块的就要多一些,比如e texteditor,intype(早期是自己修改的Scintilla,后来好像是觉得Scintilla不够好,重新实现了自己的),sublime text editor等等,其实编辑器技术最难,也是最核心的就只是如何对内存进行Gap操作,如果完成了这个,效率足够,其余的真的很容易,Codeproject上有一些相关的教程,但估计看完的并不多。至于Komodo、XmlSpy、LuaEdit、Autoit的编辑器、Adobe的Creative Suite套件中的ExtendScript Toolkit等,由于产品定位不同,直接使用Scintilla的编辑器也无可厚非。何况Komodo、Adobe都曾对Scintilla社区有贡献过代码,比如Scintilla中的Mac代码很多都是Adobe贡献的。
至于MacOs下的Textmate也是自行实现的编辑器模块,不过没有测试过大文件性能,MacOs下的开发有个很好的优点,很多都是苹果内置实现了,而且MacOs本身就与脚本相当紧密,甚至自带了tcl、perl等,shell也很好用,所以MacOs下的编辑器都实现的比较好,比如BBEditor等,xcode使用起来也非常方便,不过很奇怪的是,xcode的snippet、自动补全等在输入代码后会用灰色字体将后续的补全,但是如果用户不想要这个,又会自动清除,重新补全,但实际使用中感觉文本晃动的不太舒服,尤其是多行补全时,也许有人喜欢这样的风格吧,不过也可能有设置可以关掉吧。
当然提到编辑器,不能不提的是Unix下的Vim和Emacs,两者各有千秋,不过也有各自的缺点,要不如果过于完美,凭近乎传奇的悠久历史,早就一统江湖了,呵呵。目前两者在windows平台都还算小众,另外,两者设计也不是绝对完美的,比如vim的键盘映射,命令的内部代码全部是硬编码,如dd删除行,以及yy等就是判断是否d或y重复而实现的,虽然新命令可以做map,也依然可完全定制键盘序列,但是如果代码实现能够将键盘序列与对应功能任意由用户绑定,或者内部使用表来绑定键盘序列和其默认功能,即更灵活些就更好了,这样修改起来也很容易就可以改进键盘绑定,而不是现在功能处理分散在代码的各个地方。UltraEdit没什么太多要说的,虽然不及Vim和Emacs悠久历史,但也再过几年就开发了二十年了,足够长的时间,也足够做很多改进了,事实也是如此,现在的实在是太庞大了,一个编辑器要几十兆,不过就功能而言,除了大和全之外,16进制还可以,列模式虽然也不错,但对于东亚等复杂文字处理还是不够完善,至于作为重要特性的大文件处理性能其实也不好,用临时文件时先要复制一个副本导致速度很慢,而且占用大量硬盘,不用,就无法撤销编辑,实在是两难。何况现代编辑器的许多理念,如自定义着色Lexer、snippet等,也是很难见到。扩展性也不够好。而就体积而言,同样庞大的Emacs就远比UltraEdit要强上非常多,可见UltraEdit之臃肿,至于提到的大文件和扩展性,EmEditor就很不错,EmEditor通过基于内存映射的框架实现了一个很好的大文件编辑功能,不过EmEditor很多都依赖于插件,未必是很好的设计。如果不像Eclipse那样,有众多的拥蹙开发插件的话,而只靠开发者本身开发的话,插件系统用处并不大。更何况虽然EmEditor的脚本扩展做得不错,好像也实现了com,但是多数插件仿佛并不是脚本实现的,这和样就无形增加了第三方开发难处。开发Visual Assist可以make money,给EmEditor开发插件,估计很少有用户这么做吧,幸好EmEditor还是卖出了不少钱的,开发者一直相当积极的升级,一次版本都能发几十个beta版,现在已经是版本9了吧,相对而言,EmEditor升级对于现代编辑器功能的关注还是不错的,9中就已经实现了snippet,比起UltraEdit经过15个版本还停留在Templates模板功能上,每次的升级只是围绕着彩色的tab页,界面配置的角色化,查找窗口中的单行编辑框变成多行编辑框,应该算是比较上进的了,不是说UltraEdit做的改进不重要,只要是用户使用到的,都是最重要的功能点,但是核心功能的改进更不可或缺,否则界面做得再好,编辑效率提不高,有什么用呢。说了这么多编辑器,也提一下Editplus,虽然功能不算突出,但设计的很简洁,很中庸型的编辑器。至于pspad,开发了很多的功能,甚至包括计算器,颜色拾取器等,确实很辛苦,但是依然不够稳定,而且比起同样是delphi编写的RJ TextEd来说,功能也并不算丰富,界面也逊色些,其实delphi的界面库很好用,换肤功能也很强,虽然也许换肤对于编辑器而言过于花哨,但是只要是会接触和使用到编辑器,而不是只知道记事本和word的,编辑器多半是最最常用的工作或学习的不可或缺的工具。因此如果拥有一套美观的默认外观对于用户使用也是很有用的,毕竟爱美之心人皆有之。
编辑器杂谈之一 Scintilla(中)
HuaHope
撇开其他非Scintilla的编辑器不谈,就Scintilla编辑器而言,最大的缺点,也是很奇怪的,就是几乎每个项目都很少会修改Scintilla内部,Mitchell Foral的Scite Tools和Scite St、Textadept、Scintillalua算是少有的另类,其余的真的很难看到做较大功能改进的,也许为了升级更新编辑器模块方便,甚至静态编译的都很少,一律的动态链接,几乎都是完全的拿来主义。说实话,如果编辑功能只是工程的一部分,那也符合重用的开发理念,但很多工程本身就是开发编辑器,也一味的用而不改进核心功能,不仅使自身无法提高层次,不利于Scintilla发展,更使得现在大多数Scintilla同质化非常严重,譬如,Scintilla的列模式几乎每个项目都在期待,但是由于Neil一直很难决定如何很好的实现virtual space,所以所有的相关项目的列模式为人诟病已经很多年,直到2.0中实现了多选区编辑和virtual space功能才算是了却了几年来的心愿,而且就目前而言,列模式还实现得并不完善,比如列模式下的粘贴文本就无法像UltraEdit一样粘贴到每一行。不过1.76之后的代码就很少跟踪了,也没有去看这个新功能代码如何实现的,其实virtual space和列模式功能要实现很简单,只要在原先选区的Anchor和current基础上增加virtual Anchor和virtual current即可。另外每个项目都知道Scintilla内存消耗是文本自身的两倍,仅仅是为了实现style,Neil在实验项目中SinkWorld虽然对此作出了改进,但是SinkWorld进展实在非常缓慢,类似于Scintilla与SciTE,展示SinkWorld的Tentacle 也很久没有更新了。而且SinkWorld中的改进是针对于Scintilla中style的8个bit位128种style无法充分支持html这种可嵌入子语言类型很多的扩展型语言的,要实现的是动态长度的Style,这样必然会带来更严重的内存问题,其实就内存而言,打开相同的文件,Vim消耗的内存是相对而言比较少的,基本上比实际文本多一些,而其他的编辑器大多也是内存消耗很多,甚至有三倍于文本自身的,但其实内存问题并不必要用现在的style实现方式的,动态数组是一个更好的方式,不仅可以做到内存占用几乎与文本自身大小接近,而且对于识别同一style的起始结束和结束都是很有益处的,复杂度甚至可以做到常量,而不是现在的线性,需要逐个byte的去比对搜索,这点对于基于代码做分析,比如识别注释、字符串等块状文本有很重要的意义。当然,Scintilla目前最大的弱势还是在于正则库,Regex实在是一个过于简单的正则引擎,虽然Scintilla在1.77版本中就实现了正则引擎的外接口,相关项目,如Programmer's Notepad也已经实现了使用Pcre和Xpressive分别用于Scintilla内部和配置的正则匹配,但是多半还是需要针对各个引擎库写迭代器的,这样就不免又造成了一定的门槛,使得现在大多数项目依然使用内置的功能很弱的正则库。而没有一个优秀的正则库作为支撑,就很难实现自由度很高的自动缩进、函数识别等,更重要的,Lexer就无法做成可配置。用户自由的实现如vim、emacs、textmate那样编写lexer扩展就无法成为可能。而缺少这些,对于现代的编辑器功能而言,不免是一个很大的遗憾和功能劣势。除此以外,对于大文件的支持也是Scintilla的弱势,由于内部的设计导致的双倍内存问题,使得大文件支持更为捉衿见肘,相关的一些功能,比如括号对匹配高亮,以目前的SciTE内部实现是搜索全部文本,这显然在大文件时会导致界面假死,而Notepad++则弥补了这个缺陷,将搜索限定在上下搜索2000行而已,但这对于大文件又显然是不够的。诸如此类的功能,对于大文件而言便不免会有所缺失,不过Neil很早就宣称,Scintilla并不是为大文件设计的,所以也无可厚非。何况大文件的需求比较特殊,并不能完全做到统一,也许Neil除了认为难以实现之外,还考虑到了大文件操作与系统是紧密相连的,比如windows的内存映射,其他平台的实现就不尽相同,因此严格意义上,就Scintilla不与具体系统捆绑的设计目标来说,这并不是Scintilla遗漏的功能,实际上,从某种意义而言,Scintilla已经提供了很好的框架,足以支撑外部项目使用系统函数和算法更好的处理大文件,不过所有的项目鲜有见到实现了大文件操作的,包括最流行的项目Notepad++。当然大文件本身就是很难做处理的,即便是宣称大文件处理比较好的EmEditor,打开普通的非着色文件还好,但一旦遇到着色的如cpp文件,也一样会很痛苦,因为着色是需要遍历每一个字符并采集属性的,因无法见到EmEditor的Lexer代码,不知道如何实现的。但是要解决着色问题,前提必然是Lexer线程独立,而非Scintilla现在的单线程,虽然Scintilla内部设计了一些位置信息,可以接续着色等,但对于大文档,依然会有明显的延迟。Vim要好些,可惜也没有去研究过其Lexer代码。上文提到的Megax的分块着色是一个好的解决方案,但是多线程依然是最终解决的不可或缺的,其实Scintilla Maillist中很早就几次提过多线程着色,但是Neil认为难度很大,也没有人提出可行的方案,也就不了了之了。与大文件类似的,缺失的还有全面支持UTF8,和16进制,vim和Emacs等早已经实现了内部完整支持Unicode,当然实际内码是UTF8,因为对于许多字符集而言,Utf8比Utf16等编码方式要节省内存,而Scintilla则由于扩展性,采取设置内码方式,虽然也可以支持UTF8,但是兼容多内码的设计带来了很多的效率问题,比如查找时,对于MBCS,就需要判断当前字符是否是leading字符,这样很显然会非常慢,这从SciTE设置内码为CP936等代码页后的搜索就可以很明显的看出与其他编辑器的速度差距,而且支持单一的UTF8可以更好的识别文本,比如中文的书名号配对《》,这是多内码设计所无法实现的,因为项目无法对每一种代码页都做分析,做出特定的表来识别,不过这个错不完全在Scintilla,外部项目本身可以弥补这些缺陷,可惜从开源的一些编辑器实现上看,并没有编辑器如此做。至于16进制,UltraEdit实现的比较好,虽然一些编辑器项目也实现了16进制,比如FlexEdit、Notepad++、Scite_RU等,但是FlexEdit是另外写的16进制编辑模块,不是用的Scintilla,Notepad++也是一样,HexEditor插件也是另外实现的基于树形列表Treelist的16进制编辑控件,而SciTE_Ru虽然是通过lua脚本实现了原生的Scintilla十六进制编辑,但是类似于Dos时的小窗口编辑实现的并不算好。很奇怪的是,1.78版本中实现的两个主要新特性之一的文本边栏Text margin就完全可以很好的实现16进制编辑时的偏移量显示,但是依然还是见不到有项目基于此自行实现的16进制编辑功能,也许一样要等到Scintilla完全实现内置16进制编辑才会普及吧。至于1.78中添加的另一个新特性注释行Annotation lines,很类似于xcode中设计的出错显示,不过也许visual studio等windows开发环境习惯于将错误输出到Output窗口,而只有要显示汇编时才混合代码和汇编一起显示,所以Annotation lines也是应用寥寥,平心而论,Scintilla就编辑功能的覆盖广度已经做得比较完备了,许多功能并不弱于vim、Emacs等超级编辑器,但是问题在于各项目组合基础功能之后的深度还不够,以至同质化严重的同时,各项目也功能平平,比如自动缩进,vim实现了四种缩进,auto、smart、c、以及indentexpr,而emacs则实现了gnu、java、linux、python、user等多种成熟的缩进风格,提过组合,在vim和emacs中几乎常见的缩进风格都很容易实现。而SciTE实现了简单的自动缩进后,大多数基本沿用,因此缩进都不够智能,而Notepad++的插件NppAutoIndent则从一定程度上改进了Notepad++的自动缩进,可见自动缩进并非是Scintilla不能支持,而是大多数项目设计使用不当。当然SciTE还展示了lua脚本扩展,以及提过windows的消息扩展等,如Filerx就是使用外部SendMessage来操作SciTE,效果很好,可以录制和重放操作,对于文本编辑器而言,lua脚本使用SciTe的库函数接口已经足够实现绝大多数文本功能扩展。但可惜的是,大多数项目没能很好的继承SciTE这种良好的扩展性,大多数项目没有实现类似的lua系统,就是有扩展性也是另起炉灶,如Notepad++自行实现了插件系统,固然设计的还不错,但却失去了脚本的灵活,而programmer's notepad等虽也自行实现了采用python等其他脚本语言的脚本扩展,可惜自由度却还是不如SciTE。当然同样可惜的是,依然有些扩展是需要有界面的,尤其是运行时需要引入参数的,而单纯的lua无法扩展界面,lua的几个界面库如iup,tckUI等也不能很好的担当大任,使得单纯的SciTE中的lua扩展使用并不是特别方便,再加上SciTE本身非界面化的配置不够友好,导致其用户并不是很多。至于lua和wxWidgets或者Qt虽然可以较好的互动,但是前提是SciTE不是采用这些库开发的,而即便有项目以这些界面库开发,使用lua来控制,估计需要做的事情依然很多,不够轻量化,也不符合现在网络化的发展趋势。
编辑器杂谈之一 Scintilla(下)
HuaHope
至于比编辑器更复杂的IDE,情况也差不多,大多数IDE现在都是Eclipse化了,另外由于Borland的黯然离开,除了微软自家的Visual Studio,考虑到跨平台,IDE多半用的不是java就是wxWidgets,如另一个与Eclipse齐名的NetBean也是java实现的。而一些小型的IDE,如Code::Blocks、Komodo等,出于开发方便,最主要的核心组件之一也很少自行开发,直接使用了Scintilla,其实,无论是从开发角度还是使用角度而言,编辑器不仅仅是IDE的基础,也同时已经具备了IDE的初步雏形,尤其是除了少数几个巨型IDE如微软的Visual Studio,Sun Java Studio,IBM Rational(基于Eclipse),以及一些CPU厂商,如Intel、Motorola的IDE等,可以有足够的实力考虑和实现包括编译器、调试器、编辑器、版本控制器等各个组件的设计开发衔接以更好的整合之外,大多数的IDE基本都是外挂式的,比如挂上GCC,SVN等等,而这些,很多编辑器其实也都可以做到,甚至包括外挂调试器,只是相对而言,由于设计目标和定位不同,IDE实现和整合的功能更多,IDE的插件系统一般也更复杂也更完善,扩展功能更容易,而这对于大多数单兵作战开发的编辑器就很少会充分的考虑到。当然类似的还有SlickEdit、UltraEdit Studio,以及以代码分析著称的Source Insight等第三方IDE,至于Emacs也可以算是IDE吧,对于此类IDE,优秀的编辑器都一样是其基础,不过就以Source Insight而言,其定位就是编辑代码文件,因此大文件操作就很少考虑,否则,以Source Insight独特的不等行高的设计,大文件的整体行高计算和显示就会是一个棘手的问题。另外SlickEdit的Slick-C,和Emacs的Lisp是比较独特的,几乎所有的功能都是用Slick-C,或者Lisp实现的,应该算是可扩展性最好的IDE设计之一。
只是Source Insight、SlickEdit、UltraEdit、Textmate、EmEditor、Visual Assist等都有商业赢利支撑,而Eclipse、NetBean等虽开源免费,但背后也都有IBM、Sun等大型技术公司做支撑,相比较之下,开源且免费的Scintilla即便相关的项目众多,几乎占据了开源编辑器项目的半壁江山,但如果所有的项目都只是提需求,缺陷,和等待使用,那么仅靠Neil一个开发者而言,虽然Scintilla已经做得足够好了,也因坚持了近十年的不断奋斗也让人由衷感慨和钦佩,但如果Scintilla想做得更好,实在将是很艰难的前行。
一时感慨,写得多了,希望对于关注或采用Scintilla的项目,以及致力于自行编写编辑器的能有所用。
编辑器杂谈之二 Snippet
很高兴没看到MegaxEdit没自行实现正则库,前段时间在MissDeer的博客中随手写的一篇“编辑器杂谈”中还提到了这个,开发应有所为有所不为,什么都自行实现且不论是否可以写得更好,也实在没有必要,当然例如Emacs的Richard Stallman样样精通的超级大牛除外。“编辑器杂谈”主要是针对Scintilla系编辑器写的,也评论了点现有知名编辑器,随附在后,希望一点心得有点小用。
不过文中有几处小错还是需要指出,估计Megax是不是没有苹果机器实际试用和深入研究过Textmate,所以不太清楚?
其一,Textmate的这个功能不是Bundle,而是Snippet,Bundle功能比这个要重要和强劲的多,Bundle构建了脚本与编辑器以及系统的关联,类似于脚本宏,MacOs上脚本体系比Windows要好很多,自带的脚本也远比Windows的JavaScript、VbScript要丰富,当然Windows的Com也异常强大,不过苹果在脚本体系的人机交互上远比Windows要好上很多。而Snippet则基本上就是文本段落辅助完成,其实Visual Studio里面就有Snippet功能,不过估计使用和研究的人更少,毕竟不是很明显的功能。Vim和Emacs也早有插件,或多或少也实现了较完整的Snippet。
其二,Oniguruma正则库,也就是鬼车是支持循环嵌套的,其自带的帮助中写得很清楚,而且还举了实例,Megax在东京呆了这么多年,即便英文的帮助没注意,日文的帮助也应该至少读一遍的。应该说,最近流行的正则库大多数都已经实现了嵌套匹配,如脚本语言Perl、PHP、开发平台.Net、Java的正则库,以及正则库Greta等都是支持嵌套的,这个在O'Reilly《精通正则表达式》一书中有详细的描述。当然1.9.0版本之后采用Oniguruma的Ruby自然也支持嵌套正则。不过也正由于Oniguruma合入了Ruby,因此现在Oniguruma的最新代码已基本合并入Ruby开发,可惜的是,Ruby加了很多专有的定义进去,使得剥离一个最新的Oniguruma已经很难了。最容易为第三方集成使用的Oniguruma也许永远都定格在5.9.1了吧。
其三,正因为Oniguruma支持嵌套正则,所以TextMate支持Snippet嵌套变量也就不足为奇了,因为TextMate的正则库正是Oniguruma的Cocoa移植版本,也许是OgreKit。当然由于Textmate商业软件的源码不可见,也不排除TextMate直接使用字符串函数进行解析,因为Snippet本身并不复杂,纯字符串解析也很容易。目前Snippet做的比较完善的除了TextMate,还有Intype一样的支持嵌套变量,但是e TextEditor就只能支持简单的文本了。
其四,写伪码时最好也要注意语法,strFind.Format( "${%d:(.*?)}", i ); 肯定编不出正则的,Escape转义字符应该写\,而不是,要不然引号就先使用转义了,再往下就自然出错。这不是TCL,TCL可以使用{}来规避,而C则不行。
不过总得来说,基本上Snippet的实现就是这样了,不过依然有两点需要改进,一是变量的顺序,其实没有必要规定顺序。当然,如果按一次处理一个序号自然会引入顺序问题,但是如果一遍先将所有编号区域全部找出存储,并记录位置信息,再行一次性替换,就可以解决顺序问题了。其二,Tab键并不是一个完美的键,无论是TextMate,还是Intype等,都只可以用Tab前进,而无法后退,这是因为Tab本是就是缩进键,此处挪作Snippet用,从而导致一个键二次定义,从用户角度上而言是不可取的,使得用户在Snippet过程中无法缩进,例如复杂点的段落,自动缩进不完美的情景下,用户就只能退出Snippet再行修改了。因此目前TextMate等多半是在编写Snippet时就预设好缩进,在Snippet时仅仅依据上一行进行整体缩进,从而一定程度上避免了这个问题。但是也因为很难做完善,所以Shift-Tab并没有用来实现Snippet的回跳,依然还是定义为减少缩进。这个问题在 Mitchell Foral 的Scite-Tools中有提及,因此Scite-Tools在Scite的基础上使用Ruby实现了Snippet时,并没有使用Tab键,而是Ctrl的组合键,这样就轻松的完成了前进和后退,如果TextMate等跳出Tab的圈子,自然一样可以轻松后退,不过如果决定权交到用户手中也许会更好。Mitchell Foral 基于Scite的后来的最新Mod作品,如TextAdept等,Snippet又用lua重新编写了。由于Snippet自身就是Ruby或Lua脚本的便利性,Mitchell的Snippet从某种意义而言应该是比TextMate更为强大,因为此时Snippet已经是具有完备功能的脚本段,有点类似于Bundle,而不再仅仅是一段字符串了。
Snippet作为一个非常便捷的编码辅助功能,也依然在不断发展,自解释应是目前的最新阶段,其代表就是Zen Coding,作为快速开发的典范,类CSS的语法,使得编写Html等网页语言非常迅捷,可惜,其作用域由于语法特殊性,估计也很难走出Html的编程范围了。
再补充一点的是,Snippet自身还可以使用正则实现镜像文本、字符大小写转换(主要是来自于Perl的正则语法U)等功能,这些Oniguruma支持并不完善,需要自行实现,另外通过自定义一些标签或脚本,可以扩展出更多的、更强大的功能,TextMate的在线帮助中有部分提及,可以自行查阅。
另外需要提一个疑惑的是:既然使用了Oniguruma正则库,Oniguruma使用文本方式匹配时,其算法就是BM算法,已然很快,实在没有必要再编写BM算法了。那又为何在2008年8月之“MegaxEdit开发最新状况”中要自行开发BM或KMP算法呢?
编辑器杂谈之三 Open Source & Lexer & Encoding(上)
HuaHope
无论是CodeProject还是SourceForge,其朝气蓬勃的发展无一不说明开源精神的可贵和价值。从某种意义而言,每个开发者的起点都是从开源起步的,因为学习的书籍、编程的帮助,大都带有源码,而且就开源本身而言,其与商业化是隔绝的,Linux一样是一个产业,其价值不在于开放的源码本身,而在于软件服务,并不是所有的开源项目被应用时都足够的时间来深入研究的,尤其对于大多数商业公司而言,软件的延续才是最重要的,毕竟没有谁希望自己的经济只能建立在一时的欢愉之上,在自行投入人力研究得不偿失的情况下,此时专业的研究开源的公司,如RedHat等,便就成了首选。目前,诸多大型软件公司,如IBM等,纷纷从软件转型服务,也清晰的表明了此种趋势。
而对于大多数中小开发者而言,开源带来的不仅仅是学习的机遇,更多的是减轻了开发强度,加快了开发效率和质量,更为重要的是,与商业功能库相比,掌控源码便可以更好的围绕着自己的目标进行改良。可惜的是,开源并不是无约束的任意拥有,每一个开源项目都有其自身的法则,这种法则便是每一个开源都会携带的Licence。
平心而论,Licence实在是多得眼花缭乱,BSD、MPL、GPL、MIT等等,再加上每一个大公司,如IBM、Microsoft、Nokia等还都有自己的开源许可,且每一种规定的权益和约束都不尽相同,其约束又大都是与法律相关的,使得透彻的理解每一种许可确实成为一个艰巨的任务,但是,对于作为最终应用开源的开发者,这并不能成为不履行义务的借口。只有每个人都索取和付出,整个开源才能更加繁荣的向前进,贪婪的索取最终只会让开源凋谢,从而让贪婪也无处可取。可惜的是,很多国人对此意识淡薄,甚至明知故犯。尤其是图像视频等领域,任意占用的案例更是层出不穷,且不提绿坝软件在美国被公诉,就是诸如腾讯之类的视听产品也对开源协议置若罔闻,这实在是不应该的。对于一些国人而言,喜欢占有权益,而不喜欢履行对法则尊崇的义务,成为了中国共享软件在海外口碑不好的一个重要原因。虽然国人开发软件,经常是一窝蜂的相互抄袭,克隆,将一类软件做烂,但相较于“偷”开源软件使用,也依然还是觉得后者的行径更为恶劣,其实,现在GPL的开源还是占主流的,而GPL的知名对于二次开发者而言,不可能不知道GPL协议的相关项目必须仍以GPL进行分发,而不能闭源,但实际中,很多共享软件中连需附上的开源库的GPL Licence都不见踪影,更遑论开源了。
也许诸如GPL的开源协议对于技术和专利制度一样,虽然对持有人的权益有了充分的保护,也能通过良性发展确保整个体系的不断发展壮大,但也并不一定对技术的发展和应用起到更为积极的作用,LGPL的引出应该就是对GPL的良性补充。但幸运的是,许多开源协议采取了更为开放的政策,应该说,在对知识和作者充分尊重的基础上,越少约束的协议越能起到更多的良好的效果。BSD、MIT等就是其中很具有代表性的协议。
更幸运的是,就编辑器而言,开源协议的宽松以及开源项目的高质量,都使得现在编辑器呈现出生机勃勃的发展,这不仅仅包括Scintilla,SynEdit等编辑控件,还有更为知名的Vim、Emacs,以及Scite、Notepad++等完善的编辑软件。而且无论是Vim的作者Bram Moolenaar、Emacs的作者RichardStallman、Scintilla的作者Neil Hodgson,都数十年如一日不求回报的默默奉献和付出,其精神远比开源本身要来的伟大和崇高,值得每一个应用,享受着成熟的、优良的开源模块的开发者向他们致以敬意。
编辑器杂谈之三 Open Source & Lexer & Encoding(下)
HuaHope
但是恰如之前已经指出的那样,高质量的开源有时也不可避免的带来一些弊端,就以Scintilla而言,随着近几年的知名度不断扩大,且编辑控件不但应用广泛,其开发技术难度对于大多数开发者又显得艰难时,不免使得大多数开发者更愿意使用而不愿意创造。诚然,合理的应用成熟的模块是开发软件必不可少的,不可能指望每一个软件的每一个功能都从头开始堆砌代码,而且非核心的业务也应该尽可能的引入成熟的模块以减少风险和加快开发进度,但是在第一篇杂谈中就已经指出,诸如Notepad++之类的以编辑为核心的专业编辑器,仅仅采用拿来主义是不够的,只有众多的开源衍生项目都有改进和创新的思想和努力,才能使得Scintilla母体更好的发展,可惜的是,目前大多数Scintilla项目还是以加壳为主,再加上一些界面和功能整合,尤其是包括一些主打专业编辑器的项目,也只是坐待Scintilla的更新。不客气的说,从技术层面看,SciTE无论是设计还是扩展性,比大多数的衍生项目都要实现的更完善,唯一的缺点只是没有一个良好的易用的界面而已。
当然,Scintilla本身的设计也不是十全十美的,Vim也是如此,Emacs源码对之兴趣不大,未曾通读过,所以不敢枉下评论。而编辑器的难点和重点除了内存的GAP之外,估计就应该是Lexer和Encoding了。
通用型的编辑器不可能像专属编辑器一样,针对每一种语言都实现一个非常完备的Lexer,目前Scintilla内置了非常多的Lexer,其优势是着色速度会很快,而缺点则是用户无法定制和扩充。而现代的编辑器,如TextMate、Vim等都可以采用正则或类似的方式自定义Lexer,应该说,这和Scintilla缺少一个很好的内置的正则库是相关的。Mitchell Foral对之用lua进行了一些改良尝试,也许功能上看起来是可以实现,但是实用性依然受限,因为只有内置,才能从根本解决效率的问题。
就语言着色而言,Lexer必须是从头开始扫描的,因为大多数语言都是具有跨行特性的,因此任何期望从中间进行分析着色的方法都是行不通的,因为无法保证当前文本不在一个多行注释或字符串之中,这也就是MegaxEdit当初尝试动态渲染当前屏为何失败的根本原因。但是Lexer依然是可以高效的,其中MegaxEdit的分次着色是有效的技术之一,不过没有实践过,仅从理论上分析,先将跨行特性的元素全部着色,再动态着色当前屏幕应该是很好的且可行的方案,而且可以做得非常的高效。另一个重要的技术就是动态构建正则,这样才能保证对于四种文法类型也都能或多或少不同程度上的支持,尤其是对于可以用巴科斯范式描述的语言能做到比较完善的解析和着色。第三个是多线程着色,只有实现了真正的多线程着色,才能从根本上解决着色耗时与用户实时操作之间的问题,而且不仅仅是着色,包括任何与编辑操作冲突的都需要独立线程,当然独立线程带来编辑器内核复杂度的剧增,是需要精心设计和慎重考虑的,Scintilla、Vim目前好像都是单线程,应该说,单线程对于绝大多数文件而言,性能都是满足的,所以并不是必不可少。更何况在编辑时,着色还有一个更重要的技巧,就是第四个,仅对需要的片区着色,片区的范围是向上搜索当用户当前编辑点所在Style的起始位置,向下一直着色到与上一次着色时类型完全相同为止,对于大多数操作而言,编辑时的动态着色几乎都只是本行内的一小段文本,着色时间甚至可以忽略不计。如MegaxEdit中打开173万行的代码进行括号匹配,插入字符,Lexer分析,依然能够基本正常操作,正是基于此。但是需要指出的是,这里隐藏着一个潜在的危险,即括号匹配,如果没有对括号进行预处理,而是临时动态搜索的话,那么假设173万行只在起始和结束位置形成一对开闭括号,估计MegaxEdit也依然会有假死的现象。而如果采用多线程,则无论用户的编辑会导致怎样复杂的着色和括号匹配,都只需要在独立线程中不断计算就行了,当然这里也暗藏一个小技巧是,如果着色线程向下着色的范围很大,那么当线程着色范围或括号匹配超出当前屏时,先依据新的着色括号匹配更新当前屏幕,然后再继续向下进行。如果同时还实现了分片匹配,则向下也只需要将跨行的元素着色,而无须全部着色,这又必然会大大加速处理进程,因此给用户的体验就将几乎是完美的。
但提到Lexer,就无法避开Style,Style其实是Lexer的存储标记,有了Style,就可以将Lexer的结果永久性的保存,而无须不断地动态着色,也算是用空间换取时间的一个典型,应该说,几乎所有的编辑器都有Style设计。但是目前Scintilla,以及MegaxEdit存在着独立Style的设计对于内存的需求稍显得多了些,几乎内存消耗都是文件自身的两倍以上,其实完全没有必要的,具体的在编辑器杂谈一中已经较详细的描述了可行的使用动态数组的解决方案,在此就不多赘述了。
至于文本处理的内核编码,目前市面上内核鲜见有UTF16的,估计Megax此处是弄错了,提及编辑器的内核Unicode化,从编译角度讲,自然是UTF16,因为大多数操作系统,比如Windows,内核就是UTF16,当然不同的操作系统,BE还是LE会有所不同,但是如果是内部处理文本的编码,则编辑器的Unicode内核指的多半是UTF8,这个虽然无法对于商业化软件Editplus、EmEditor进行内部分析得到,但可以从Vim、Emacs上很清晰的了解,Vim应该是从版本6加入UTF8支持的,也许不是很准确,这只是从Vim作者Bram Moolenaar的1999年访谈中提到,具体支持UTF8的起始版本请查询Vim的更新历史。而Emacs应该是23开始支持的。之所以不使用UTF16而是UTF8,原因在编辑器杂谈一中也提到了,对于许多字符集而言,Utf8比Utf16等编码方式要节省内存,比如Ascii直接就可以等价到UTF8中,就编辑器的功能而言,大多数用来编写程序代码,而几乎所有的程序都是Ascii编码方式,当然注释、字符串等特殊元素除外,因此,编辑器内核编码选择UTF8是必要的。UTF16将带来不必要的转换和内存消耗。而对于目前诸如Scintilla的MBCS方案,虽然一样可以处理文本,但是无法更好的识别和处理文本,尤其是非英语类的匹配符号对就无法识别,如中文的书名号《》,而且UTF8的不定长和MBCS的不定长是有很大区别的,MBCS的不定长需要通过操作系统查询对应的码表才能知道当前字节所在的位置是不是字符的Leading,以及当前字符的长度,而这个查询是非常耗时的,但是UTF8直接从当前字节的char值上就可以很容易的判定字符位置及当前字符的长度,这种判定只需要简单的与或,处理速度远非MBCS可比,比UTF16或UTF32的规则字符长度也许或有不足,但处理速度应该基本属于一个数量级,加上UTF8的诸多特性,决定了其是最适合编辑器使用的内码。当然UTF8只能满足于编辑和显示,如果保存时需要转换内码,则还是有可能会有损失的,因此从某种意义上而言,对于CP936的中文编码文件,在内核UTF8的编辑器中编辑时可以任意输入其他语言的文字,但是到保存转换回CP936时,也许并不能完全保证所有的编辑可以全部正确转换,也即不是所见即所得,这也许算是UTF8内核带来的无可奈何的副作用了。不过以exe作为举例则并不妥,因为exe是没有编码的,所以强行转换自然会导致前后不一。而从编辑器的设计角度,打开CP932的文件,无论内部什么编码,不作修改,原样保存,都必须保证前后一致性的,这是编辑器必须实现的一个最最基本的特性,否则必然会导致用户无法信任和正常使用。至于编辑器的其他内存消耗,依据编辑器实现的目标不同而有所不同,行信息一般一个16位int,或者32位long型足够使用了,也就是大约每百万行多2-4兆内存,相对于文件本身,也应该是可以忽略不计的。
与内存相关的还有文件本身,因此大文件的支持与否便成为判段编辑器是否优良的一个特性之一,对于大文件的定义很难给出标准,但是一般而言,超过本机装配内存大小的文件应该都算大文件,因为大多数情况下,编辑器都是将文本加载入内存操作的,当无法加载时,此时就需要另外的处理能力,而这种处理便是大文件处理。大文件的处理多半是通过文件映射实现的,不过这种方法的缺陷就是当系统更换映射页面时,已经脏了的数据需要写入文件,而频繁的写大文件显然性能不容忽视,另一个可行的便是Megax提到的Piece Table,其实编辑器的核心便是这个,只是这个算法深入理解不太容易,很久以前看过Scintilla的内部实现几遍也没完全看懂,再加上Scintilla内核的内存处理实现得效率很不错,因此暂未有过更新或重新编写的打算,所以也没兴趣再细看,对此也就没有了解和体会,无从分析了。如果以后实践了大文件的操作,再详细描述吧。
最后感谢Megax提供了Oniguruma更新到5.9.2的消息,国内不知为何Oniguruma的主页被屏蔽了,而且自2007年12月22日以来两年多以来一直没有更新,因此只是跟踪着Ruby中的分支,以为合并到Ruby中不再独立开发了,看到文中提到5.9.2才知道一个月前就更新了,已经下载了,只是看Change Log感觉改动不大,不知道UTF8处理上的一个内存缺陷修复了没有,需要尝试一下才能明确了。不过Oniguruma的c++ wrapper很好写,自己实现并不难。从效率和性能的角度而言,Oniguruma是一个非常优秀的正则库,相对于PCRE等来说一是支持的编码要全,二是普通文本搜索更完善,速度更快。但是与boost中的几个正则库相比,最大的缺点就是没有迭代器,使得无法很好的普遍适用于各种场合,仅仅对一段字符串进行处理对于编辑器是远远不够的,所以要完美的集成到编辑器中,是需要修改源码的,自行加上迭代器,这样就可以通过迭代器遍历整个编辑器,从而更高效的进行搜索了,否则还需要从编辑器中拷贝出字符串,效率很低下。
不过回到文首的开源讨论,如果有合适的组件和模块,在尊重并符合协议规范之下,还是应该尽可能的站在别人的基础之上进行开发的,知识就是应该分享和共用的,如果别人已经愿意分享了,那么又有什么理由拒绝别人的好意呢?但是当现有组件不适合,或者希望能够有所突破和创新时,就应该鼓足勇气,重新设计并付诸实践,只有这样,才能不断地推动知识和技术向前进步,而如有收获,也应该将收获进行分享,让更多的人来共用,这样才能创造更多,更大的价值,也才能更多的体现自身的价值,任何固步自封、或者只获取而不分享的行为都是不可取的。分享也并不一定排斥经济行为,开发出一流的产品,哪怕是商业化的软件,只要能够给用户带来便利,各取所需,谋生致富都未尝不可,毕竟社会是现实的,软件开发也依然要生存和生活,也正因此,任何无私奉献的开发者也更加值得尊敬。另外分享的途径也有很多,如果曾经受惠于无私的开源,那么至少也应该在需要时无私的回馈开源,恰如IBM、Sun等在利用开源赚取利润的同时,也给予了开源极大的帮助,这是一种真正的良性循环,是对开源和应用都有极大好处的,只有这样开源才能不断发展和壮大。而且并不一定是要有源码才是真正的开源,分享思路和实践经验,让其他人少走弯路,或给予他人以参考借鉴,也算是一种“开源”。这也是最近编写几篇“编辑器杂谈”的初衷了。
编辑器杂谈(转载)+点评
点评:
Scintilla: 目前Scintilla有一统江湖的趋势。只要是新开发的软件工具能够用到高级编辑器的地方基本上就会用它了。的确Scintilla为一些开发提供了便利,但是,是不是也阻碍了编辑器发展的进程啊?没人愿意开发了,还会有进步嘛?所以说,有时候开源并不一定是好事,你开源开的不好就罢了,开的好了,就会挤掉很多优秀的共享软件,以至于没人来做这项了。
另外Scintilla的出现导致同质化非常严重,个个都长的差不多,操作也差不多,体现不出特点,这个HuaHope的杂谈中有描述。如果一个编辑器要定位于一个专业文本编辑软件,比如现在的Editplus, UlrtaEdit那样,我觉得还是不要采用Scintilla的较好,当然如果像Code:Blocks定位于IDE,采用Scintilla就是更快更好的选择了。坦白的说,开发高性能多用途编辑器难度是很高的。
Style: 这个是我纠结很长时间的一个东西,在几年前,我一直是用的动态渲染本屏文本。因为一个屏幕上显示的非常少,所以效率不错。但是也带来一些不便。比如括号匹配时,就需要重新进行分析,否则你不知道该括号是在注释中,还是在字符串中,还是真正我们需要的括号。再比如,现在有些编辑器带的功能,当鼠标移动到Email,URL之类的时候,会出现动作,如果采用动态渲染,那么就会看到CPU明显的上升。当然,也可以再采用一些措施,只存储当前屏幕的Style。但是这会使得编辑器的架构非常的复杂、繁琐,以至于我最后都不想去做了。所以为每一个字符存储一个Style(CHAR),是最好的选择。至此你会发现,世界清静了,代码漂亮了,但是内存也浪费了最多一倍(Unicode:0.5倍文本, 其它:最多一倍).有了Style之后,很多事情都好办了,比如前文提到的括号匹配,鼠标动作等。不过Style应该是个可选功能,在不需要的时候我们可以对它关掉,关掉的时候,去掉其它高级功能支持,MegxEdit已实现。因为每个CHAR有8位,我拿出了6位存储Style,剩下2为用来标记特殊用途,所以可以组合出很好的效果,和Scintilla差不多。
Lexer: 这也是一个难点,难点不在于写,而是在于如何和编辑器组合。我最初采用的算法是渲染本屏的文本,存储该行最后的状态。当用户滚动的时候,判断滚动时的可见行,从该行开始分析。猛一看,这么做太完美了,当我费了九年二虎之力做完之后,我发现我做了无用功。这么做只适合查看文本,但不适合编辑器文本,如果你编辑了文本,在滚动的话,同时屏幕下方都未被分析过的话,就会有明显的延迟了。另外你也判断不出屏幕下方是否被分析过,所以最后抛弃。
所以最后的策略:从用户输入点,开始分析,直到下一行是状态和本行一致(仅限多行注释,多行字符串,子语言)。有人会说,每编辑一次都要这么做,岂不是很浪费CPU啊?不是这样的,我告诉你,Editplus, EMEditor, Scintilla都是这么做的。所以也就出现了HuaHope提到的那种情况:如果一个C++文本很大,并且只是变量定义之类的,不含有任何多行注释,那么你在开头输入/*的话,现在市面上的编辑器(EditPlus, EMEditor, UltraEdit)都会有延迟。在这一点上Editplus做的较好,MegaxEdit的性能在EditPlus,he EmEditor之间, EmEditor <= MegaxEdit <= EditPlus,其它不再点评,基本会假死。
在现代的CPU+内存下,经过我测试,打开173万行c++文件进行括号匹配,插入字符,Lex分析的话,用户基本不会察觉有明显延迟。
Unicode: Editplus、EMEditor和其它的编辑器的内核均是UTF16的,MegaxEdit也是。所以如果你打开一个1M的ANSII文本的话,那么实际最少使用2M文本+1MStyle=最少3M内存。是不是很浪费内存啊。且听我分析。UTF16内核的显著优点是极大极大极大极大的简化了开发,而且完美支持各种字体,即使你现在的文件是CP932,你也可以输入日文韩文中文,而不会出现乱码。至于浪费内存,在windows操作系统上,申请大块内存谈不上浪费不浪费。真正浪费内存的地方是UndoRedo数据结构和一些文本操作。另外还有一个内存消耗大户,那就是行信息。为了解决这些真正的,看似不起眼的内存消耗,MegaxEdit采用了一个非常精巧的MemPool,参考自Loki,在一定程度上缓解了这些问题。不过即使如此,在1G的CPU上不建议编辑器超过200M的文本。
如果不采用UTF16内核,还有一种不错的方案,也就是MBCS方案,这个我实现过,但是被我抛弃了。原因是代码丑陋。方案如下:文件的存储仍然采用该文件的物理形式,也就是直接读取到内存上。在显示的时候动态转化成Unicode.相关的函数有CharNext, CharPrev和MB2CS,CS2MB之类的。这么做的话几乎可以达到和UTF16一模一样的效果,只是插入文本的时候,同样要转换,如果插入的文本非该文本的codepage,很显然会乱码。据我猜测, 日本的秀丸似乎是这么做的。秀丸虽然不支持Unicode,但是可以强制Codepage,KeepContent来实现。
关于UTF8,其实UTF8也可以看成MBCS。因为UTF8是不定长的,所以某些操作非常蹩脚,而且读取文件的时候需要一定程度的转换,非常的麻烦。
从平均性能和操作简便性上来说,没有比UTF16更棒的了。但是UTF16有个很大的缺点,并不是内存占用。而是它无法原原本本反向操作。比如你用Editplus读取一个EXE,指定codepage为932,不作修改,直接保存,那么保存后的文件和原来的EXE是肯定不一样的。因为涉及到字符映射的问题,这是硬伤,无解决方案。但是,我想不会有人用文本编辑器编辑器非文本文件吧,所以也无伤大雅。另外,还有一个硬伤,现在有了UTF32了,到时候UTF16就不够用了,呵呵,也许只有UTF8变长字节能支持了。
大文件支持: 呵呵,这是个很有意思的问题,关键是什么叫做大文件。在MegaxEdit上的定义是,文本的大小超过100M, 文件行数超过100万,叫可以叫做大文件了。注意这儿有个文件行数限制。如果一个文本除了换行什么都不含有的话,行数超过100万,就会让很多编辑器反映迟钝了。在此吹一下,MegaxEdit还是不错的,性能刚刚的。
高性能多用途的文本编辑器要考虑的事情非常多,对于大文件是不可能支持很完美的,甚至直接不支持。所以纠结于大文件是否支持的好,有点舍本逐末了。曾经我就在这点上浪费了很多青春。
不过我仍然对大文件处理颇有心得。最投机取巧的方法就是EmEditor现在采用的那样,分段映射。不管你多大,我每次只读取一点。修改的时候直接在原偏移处,插入修改的代码即可。如果这么做的话,任何一个编辑器通过插件都可以实现。比较好的做法是采用Piece Table,在此不详述。
正则表达式: 说实话,本人自动机学的很烂。我能写出一个正则库,但是效率估计连我都不想用。我最初的目的是做成Lex的那样,一个正则式映射一个状态。直接配置,实现语法加亮。可惜,最后因本人功力有限,放弃。最后采用了日本的鬼车c++ wrapper,最近更新成了5.9.2. 我以前看过它的日文Help,记得是不支持嵌套的,多谢HuaHope提醒,回头好好研究研究。如果支持嵌套,那么HotText就支持嵌套变量了。但是MegaxEdit仍然坚持变量要定义后使用,因为解析省事。
在此提一下鬼车,这是一个很牛X的正则库,性能颇高,而且支持各种Encoding,将来我的多文件正则查找就靠它了。鬼车和Ruby结合比较紧密,支持好几种mode,本人研究也不深,希望有志者仔细研究研究。这儿有个很不错的c++ wrapper: http://homepage3.nifty.com/k-takata/mysoft/bregonig.html
其它:
>>不过文中有几处小错还是需要指出,估计Megax是不是没有苹果机器实际试用和深入研究过Textmate,所以不太清楚?
本人确实没有MAC,找了几个GIF图片还有E和intype试用了一下,看见它们都叫bundle,于是误以为这个在Textmate上也叫bundle.
>>Megax在东京呆了这么多年,即便 英文的帮助没注意,日文的帮助也应该至少读一遍的。
你咋知道我在鬼子地方混过?这都能调查清楚。O(∩_∩)O哈哈~
>>另外需要提一个疑惑的是:既然使用了Oniguruma正则库,Oniguruma使用文本方式匹配时,其算法就是BM算法,已然很快,实在没有必要再编 写BM算法了。那又为何在2008年8月之“MegaxEdit开发最新状况”中要自行开发BM或KMP算法呢?
本人比较懒,能不写就尽量不写,至于想要自行写BM算法,主要是编辑器数据结构问题。不过现在这个问题已经不存在了,因为舍掉了多行匹配能力(即一段文本(含有换行符)可以跨行匹配)。
非常感谢含金量如此高的评论。抛砖引玉,结果钓了块钻石。
最后
以上就是任性白羊为你收集整理的编辑器杂谈的全部内容,希望文章能够帮你解决编辑器杂谈所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复