本來我的編輯器沒有自動完成功能的拄养,而且本來應(yīng)該繼續(xù)講代碼的載入與分析的离斩。
但剛好做了上一節(jié)的功能后,我臨時做出來了瘪匿,趁熱寫出來跛梗。
代碼自動完成,按自己的理解做的棋弥,不知道別人是怎么實現(xiàn)的核偿,先講自己的思路吧。
首先顽染,代碼自動完成漾岳,得記錄能自動完成的字符串(比如關(guān)鍵字、變量粉寞、類名等等)
這又要分:靜態(tài)載入和動態(tài)載入
所謂靜態(tài)載入尼荆,就是在程序啟動的時候載入的一些確定的字符串
比如:編輯器當前的配置是C#編譯器,那C#的關(guān)鍵字是確定的唧垦。這些是可以寫到配置文件里的捅儒,在程序啟動的時候就載入。
所謂動態(tài)載入振亮,就是在程序運行的時候巧还,分析代碼,在后才載入的字符串
比如:當前代碼的函數(shù)名双炕、變量等狞悲,這些是不能再之前確定的,只有當代碼分析完成后妇斤,才能確定摇锋。這部分字符串,在分析器里獲得站超。
好了荸恕,有了提示的字符串數(shù)組后,就可以實現(xiàn)功能了死相。
為了簡單融求,我這里只是在程序里直接定義了一些字符串數(shù)組
首先實現(xiàn)智能提示的核心類
public class IntelligentManager
{
private CodeManager codeManager;
private string[] ss = new string[]
{
"int", "Integer",
"public", "private", "protected"
};
private List<string> result;
public List<string> Result
{
get
{
return result;
}
}
public IntelligentManager(CodeManager setCodeManager)
{
this.codeManager = setCodeManager;
this.result = new List<string>();
this.codeManager.TextChanged += TextChangedEvent;
}
public void MatchingString()
{
string inputString = codeManager.GetLastCut();
this.result.Clear();
if ( inputString.Length == 0 )
{
return;
}
inputString = inputString.ToLower(); // 代碼提示時,要不要區(qū)分大小寫就在這里搞定
foreach ( string s in ss )
{
if ( s.ToLower().StartsWith(inputString) && inputString.Length < s.Length )
{
result.Add(s);
}
}
}
public void SelectMatching(int index)
{
if ( index < 0 || index >= result.Count )
{
return;
}
string str = result[index];
string lastString = codeManager.GetLastCut();
ReplaceStringCommand cmd = new ReplaceStringCommand(
codeManager,
codeManager.Text.Length - lastString.Length,
lastString.Length,
str);
codeManager.Execute(cmd);
result.Clear();
}
private void TextChangedEvent()
{
MatchingString();
}
}
代碼不多算撮,也比較好理解生宛,稍微解釋下县昂。
MatchingString就是匹配CodeManager中,最后輸入的一個字符串塊
這里提一下陷舅,所謂字符串塊倒彰,就是被一些符號和空白符分開的東西,比如“abc,de+fg”這里就有三個塊莱睁,"abc","de","fg"待讳。他們被“," "+”這些符號分開了
因為我們不會為包含符號的字符串做匹配處理(比如str+abc,只用abc匹配仰剿,而不是str+abc)
selectMatching函數(shù)是表示選擇了匹配列表里的值
函數(shù)里面的ReplaceStringCommand是一個替換指定字符串的命令创淡,繼承IUndoCommand接口(不了解的,可以看上一節(jié))
TextChangedEvent是當CodeManager的文字發(fā)生改變的時候執(zhí)行了
特別說明南吮,我這里是用 codeManager.GetLastCut()來獲取最后輸入的一個塊琳彩。
在實際的項目中,應(yīng)該是取光標所在的塊部凑,至于怎么取汁针,就看自己的意思了,比較簡單砚尽。
CodeManager也要做一下對應(yīng)的改變
加入事件
public event CodeManagerEventHandler TextChanged;
另外在所有改變了文字內(nèi)容的地方,激活事件辉词。通知所有注冊了事件的其它類(這里只有IntelligentManager)
public void InsertCharacter(int index, char ch)
{
text.Insert(index, ch);
TextChangedEvent();
}
private void TextChangedEvent()
{
if ( TextChanged != null )
{
TextChanged.Invoke();
}
}
最后在Coder里定義即可
public IntelligentManager intelligentManager;
哦必孤,忘了說。為了顯示代碼提示的列表瑞躺,在上一節(jié)的基礎(chǔ)上敷搪,在窗體再拖一個label控件
在KeyDown事件的最后加入代碼
string[] ss = coder.intelligentManager.Result.ToArray();
label2.Text = string.Empty;
foreach ( string s in ss )
{
label2.Text += s;
label2.Text += '\n';
}
這樣就能顯示了。至于怎么選擇幢哨,看你了赡勘,可以按回車選中第一個,也可以按數(shù)字鍵捞镰,只需要調(diào)用函數(shù)SelectMatching闸与,傳入序號就可以了
當然,在真正的項目中岸售,還是得由IntelligentManager插件調(diào)用Renderer插件來自己繪制
好践樱,到這里代碼提示也完成了
當然,考慮效率問題凸丸,還有待優(yōu)化