編輯器雜談(轉載)+點評
點評:
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算法,主要是編輯器數據結構問題。不過現在這個問題已經不存在了,因為舍掉了多行匹配能力(即一段文本(含有換行符)可以跨行匹配)。
非常感謝含金量如此高的評論。拋磚引玉,結果釣了塊鉆石。
================以下是轉載========================
作者: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的編輯器不談,就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來控制,估計需要做的事情依然很多,不夠輕量化,也 不符合現在網絡化的發展趨勢。
至于比編輯器更復雜的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想做得更好,實在 將是很艱難的前行。
很高興沒看到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的編程 范圍了。
一時感慨,寫得多了,希望對于關注或采用Scintilla的項目,以及致力于自行編寫編輯器的能有所用。
posted on 2010-02-05 12:57
megax 閱讀(5313)
評論(10) 編輯 收藏 引用