ScintillaNET的应用
出于工作需要,需要制作一个嵌入在桌面应用中的C语言编辑器,经过一系列调研,目前ScintillaNET应该是最合适的了,开源、轻便、功能丰富,但是踩得坑也很多,接下面一一说道。
目前ScintillaNET托管在https://github.com/jacobslusser/ScintillaNET,拉下来重新编译。由于需要移植到.NET 2.0的平台上,需要修改源码中的对Linq的依赖,这里不多说,把目标框架改为.NET 2.0,编译,哪里报错改哪里。
1. 编辑器风格
参考:https://github.com/robinrodricks/ScintillaNET.Demo
2. 括号的匹配和高亮
为了方便多处调用该控件,继承Scintilla类,实现“自定义”控件,以下均以这种做法来实现功能。
重写OnUpdateUI事件,在UpdateUI中实现括号匹配功能。
1 private int m_lastCaretPos =0; 2 protected override void OnUpdateUI(UpdateUIEventArgs e) 3 { 4 base.OnUpdateUI(e); 5 MatchAndLightBracket(); 6 } 7 private void MatchAndLightBracket() 8 { 9 // Has the caret changed position? 10 int caretPos = this.CurrentPosition; 11 if (m_lastCaretPos != caretPos) 12 { 13 m_lastCaretPos = caretPos; 14 int bracePos1 = -1; 15 int bracePos2 = -1; 16 17 // Is there a brace to the left or right? 18 if (caretPos > 0 && IsBrace(this.GetCharAt(caretPos - 1))) 19 bracePos1 = (caretPos - 1); 20 else if (IsBrace(this.GetCharAt(caretPos))) 21 bracePos1 = caretPos; 22 23 if (bracePos1 >= 0) 24 { 25 // Find the matching brace 26 bracePos2 = this.BraceMatch(bracePos1); 27 if (bracePos2 == CodeEditor.InvalidPosition) 28 { 29 ReleaseHighlightB(); 30 } 31 else 32 { 33 ReleaseHighlightB(); 34 HighlightBracket(bracePos1); 35 HighlightBracket(bracePos2); 36 } 37 } 38 else 39 { 40 ReleaseHighlightB(); 41 } 42 } 43 } 44 private void HighlightBracket(int pos) 45 { 46 if (pos < 0) 47 return; 48 this.IndicatorFillRange(pos, 1); 49 } 50 private void ReleaseHighlightB() 51 { 52 this.IndicatorClearRange(0, this.TextLength); 53 } 54 private static bool IsBrace(int c) 55 { 56 switch (c) 57 { 58 case '(': 59 case ')': 60 case '[': 61 case ']': 62 case '{': 63 case '}': 64 case '<': 65 case '>': 66 return true; 67 } 68 69 return false; 70 }
3. Ctrl+Z会一次性清空所有的修改
1 protected override void OnBeforeInsert(BeforeModificationEventArgs e) 2 { 3 base.OnBeforeInsert(e); 4 Count = this.Text.Length; 5 this.BeginUndoAction(); 6 } 7 protected override void OnInsert(ModificationEventArgs e) 8 { 9 base.OnInsert(e); 10 if (Count < this.Text.Length) 11 this.EndUndoAction(); 12 }
4.缩进调整
1 protected override void OnCharAdded(CharAddedEventArgs e) 2 { 3 base.OnCharAdded(e); 4 AutoIndicator(); 5 } 6 private void AutoIndicator() 7 { 8 int pos = this.CurrentPosition; 9 if (pos > 3 && this.GetCharAt(pos - 1) == '\n' && this.GetCharAt(pos - 2) == '\r') 10 { 11 if (this.GetCharAt(pos - 3) == '{') 12 { 13 string[] Text = GetStringList(); 14 string line = Text[this.CurrentLine - 1]; 15 int start = line.IndexOf(line.TrimStart()); 16 string ss = line.Substring(0, start); 17 string str = new string(' ',4); 18 this.InsertText(pos, ss+str); 19 this.SelectionStart = this.SelectionEnd = pos + ss.Length + 4; 20 } 21 else 22 { 23 string[] Text = GetStringList(); 24 string line = Text[this.CurrentLine - 1]; 25 int start = line.IndexOf(line.TrimStart()); 26 string ss = line.Substring(0, start); 27 this.InsertText(pos, ss); 28 this.SelectionStart = this.SelectionEnd = pos + ss.Length; 29 } 30 31 } 32 } 33 private string[] GetStringList() 34 { 35 string[] s = new string[] { "\n" }; 36 return this.Text.Split(s, StringSplitOptions.None); 37 }
目前整理了这么多,有机会再继续深入理解和应用ScintillaNET。