• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 76,  comments - 621,  trackbacks - 0
            很多人可能沒有聽過tab trigger這個(gè)功能,那么諸位可以google一把即可知道其為何物。
            本來我是打算把這樣的功能放到插件里面做的,可是一想到最后能為我的編輯器開發(fā)插件的,
            在初期估計(jì)也沒啥人,于是乎還是在內(nèi)核上給予支持吧。

            本篇文章即是分析如何去實(shí)現(xiàn)該功能的,事實(shí)上,我已經(jīng)在MegaxEdit基本上實(shí)現(xiàn)了。不過相較于
            TextMate功能有所縮水。縮水的原因主要是因?yàn)槲也捎昧苏齽t表達(dá)式去實(shí)現(xiàn)的,而絕大多數(shù)
            正則表達(dá)式庫是不支持嵌套的(本人使用了日本的鬼車正則庫),所以在我的編輯器里變量里面
            不可以再定義變量。

            在我的編輯器里面,這個(gè)東西不叫TextMate上的Bundle,我給起了個(gè)名字叫HotText, hoho~~~

            首先我們看一下下面的語句:
            for (${1:unsigned int} ${2:i} = ${3:0}; ${4:< ${5:count}}; ${6:++}) {
                $0
            \}

            基于上面的形式我們作出如下定義:

            變量:    變量以${數(shù)字:內(nèi)容}的形式開頭, 內(nèi)容可以為空, 比如${1:name}, ${2:test}, ${3:}
            引用:    這里面的引用是指對(duì)變量的引用, 比如 $數(shù)字, $1, $2, $3之類的
            常量:    編輯器提供的常量,比如${FILE_NAME}, ${TIME}
            規(guī)則:    變量不可嵌套變量, 變量必須順序定義,順序引用

            經(jīng)過上面的規(guī)則,這個(gè)for語句就變成了下面這樣:
            for (${1:unsigned int} ${2:i} = ${3:0}; ${4:} < ${5:count}}; ${6:++}) {
                $0
            \}

            Ok, 我們看一下典型的效果,當(dāng)用戶輸入for語句的時(shí)候,編輯器應(yīng)該顯示出:
            for (<unsigned int> i = 0; i < count; i++) {
                   
            }
            <>部分為光標(biāo)選擇區(qū)域。

            聰明的讀者頭腦里面應(yīng)該馬上知道如何構(gòu)造了,其實(shí)也就是幾步正則替換,因?yàn)槲谋痉浅P。孕适欠浅?br>高效的。偽代碼如下:

            const int MAX_HT_CNT = 16;

            forint i=1; i<=MAX_HT_CNT; i++ ){   
                
            //首先替換變量
                string strFind;
                strFind.Format( 
            "\$\{%d:(.*?)\}", i );
                
            string strReplace;
                strReplace.Format( 
            "$1" );

                
            //在進(jìn)行替換的時(shí)候我們同時(shí)要保存該變量Pos和長度信息
                
            //正因?yàn)槿绱?我們在定義了上面的規(guī)則,變量要順序定義,否則就亂序了。
                GetSearchPos&Length();
                RegexReplace();

                GetBackRef();
            //在這兒獲取一下上面的()中內(nèi)引用內(nèi)容,在進(jìn)行一次替換
                
            //替換對(duì)變量的引用
                string strRef;
                strRef.Format( 
            "\$%d", i );
                RegexReplace();

                
            //到這兒對(duì)變量1替換完畢
            }


            上面是非常簡單的邏輯。

            因?yàn)檫@東西要和編輯器結(jié)合,所以有一些數(shù)據(jù)結(jié)構(gòu)是必要的。最重要的要屬上面循環(huán)中變量的位置和長度信息了。
            有了它我們才能夠?qū)崿F(xiàn)HotSpot(熱點(diǎn)即變量)的跳轉(zhuǎn)。

            在這里,我簡單描述一下我的編輯器的數(shù)據(jù)結(jié)構(gòu):

            // 這個(gè)存儲(chǔ)了每一個(gè)變量的信息
            struct CTextSpot{
                CText pCText;
                
            int nPos;

                CTextSpot(){
                    pCText 
            = 0;
                    nPos 
            = -1;
                }
            };

            // 保存了HotText的基本信息
            class HotText{
            public:
                
            int m_nDocOffset;//HotText應(yīng)該從Doc中哪個(gè)偏移開始插入
                CText m_Text;//原始文字
                CText m_RetText;//替換后的文字
                CTextSpot m_List[ MAX_HT ];//最多可以有幾個(gè)變量
                int m_nSpotPos;//指向當(dāng)前Spot,這樣在Tab跳轉(zhuǎn)的時(shí)候我們就知道該跳到那個(gè)Spot上了
            }

            這些HotText均保存于Map之中,根據(jù)當(dāng)前的輸入進(jìn)行查詢,思路還是很簡單的。

            和編輯器的結(jié)合,基本上就是一個(gè)Replace命令,用本次輸入產(chǎn)生的HotText替換掉上次的HotText.因?yàn)榇蟛糠值?br>HotText都很短,所以幾乎不會(huì)浪費(fèi)內(nèi)存。EmEditor則是只對(duì)用戶最后的輸入產(chǎn)生Insert命令,雖然節(jié)省了一點(diǎn)內(nèi)存
            但卻失去了UndoRedo的能力,到底哪個(gè)好,也不好說。MegaxEdit是采用的前者。

            關(guān)于HotText的取消:

            用戶在輸入的時(shí)候不能總處于HotText狀態(tài)中吧,比如用戶按下了方向鍵或者其他快捷鍵,這個(gè)時(shí)候我們要取消
            HotText的功能,恢復(fù)Tab鍵本來的作用。那么如何取消呢?其實(shí)這東西和編輯器結(jié)合過于緊密,在MegaxEdit中
            是這樣來實(shí)現(xiàn)的:
            1. 取得當(dāng)前光標(biāo)的偏移量 offsetA
            2. 取得當(dāng)前HotSpot的尾部偏移量 offsetB = m_nDocOffset + HotSpot.nPos + HotSpot.pCText.GetLength();
            3. offsetA != offsetB, 即取消當(dāng)前HotText;

            到此,邏輯即全部結(jié)束。

            雖然我們實(shí)現(xiàn)了一個(gè)縮水版的tab trigger,不過根據(jù)我的研究,這幾乎可以滿足絕絕絕絕絕絕大多數(shù)的應(yīng)用,至少比
            Notepad++上的QuickText要強(qiáng)多了。不占用 CPU,不占用內(nèi)存,完美UndoRedo, 夠用了。

            歡迎討論。
            posted on 2010-02-02 20:39 megax 閱讀(3064) 評(píng)論(12)  編輯 收藏 引用

            只有注冊用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            久久男人Av资源网站无码软件 | 久久精品国产亚洲AV无码娇色 | 久久久艹| 色天使久久综合网天天| A级毛片无码久久精品免费| 久久发布国产伦子伦精品| 久久97久久97精品免视看秋霞| 欧美久久久久久| 97超级碰碰碰碰久久久久| 性做久久久久久久久| 久久精品一区二区三区不卡| 一级做a爰片久久毛片毛片| 日韩精品无码久久久久久| 久久精品国产福利国产琪琪| 久久精品亚洲精品国产色婷| 久久久久无码精品国产app| 久久丫精品国产亚洲av| 91麻豆国产精品91久久久| 久久久久久久波多野结衣高潮 | 久久久久亚洲AV无码永不| 国产ww久久久久久久久久| 7777精品久久久大香线蕉| 九九热久久免费视频| 91精品国产综合久久精品| 亚洲AV乱码久久精品蜜桃| 欧美午夜A∨大片久久 | 久久免费观看视频| 久久这里只有精品久久| 国产成人精品久久一区二区三区| 久久这里都是精品| 四虎国产精品免费久久| 久久精品无码一区二区三区免费| 久久免费小视频| 国产成人综合久久精品尤物| 久久精品国产只有精品2020| 亚洲国产二区三区久久| 99国内精品久久久久久久| 国产精品99久久久久久董美香| 亚洲一区中文字幕久久| 久久99精品久久久久久不卡| 久久精品国产亚洲Aⅴ香蕉 |