小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

SharpDevelop淺析_4_TextEditor_自動(dòng)完成、代碼折疊…… Parser及其應(yīng)用: Code Completion, Method Insight, Class Scout ...

 快樂(lè)學(xué)習(xí) 2008-05-02
Parser及其應(yīng)用: Code Completion, Method Insight, Class Scout ...


1、Demo界面及功能解釋
2、Parser實(shí)現(xiàn)概述
3、Parser應(yīng)用: MouseHover Tooltip
4、Parser應(yīng)用: CodeCompletion & MethodInsight
5、Parser應(yīng)用: QuickClassBrowserPanel
6、Parser應(yīng)用: Folding
7、總結(jié)
Demo下載

1、Demo界面及功能解釋
啟動(dòng)并打開(kāi)任一 .cs 文件后,界面如下:

自動(dòng)完成界面如下:

可見(jiàn)新增功能如下(僅支持.cs文件):
a, 鼠標(biāo)停留在方法、屬性等位置時(shí),會(huì)顯示出相關(guān)的文檔描述tooltip
b, 輸入時(shí)支持自動(dòng)完成
c, 編輯窗口頂部有類(lèi)列表和成員(方法、變量等)列表下拉框用以快速瀏覽、定位
d, 編輯窗口左側(cè)有折疊線(xiàn)用以方法、類(lèi)等的代碼折疊
相應(yīng)的Demo工程中新增項(xiàng)目如下:
a, SharpEditor:   包含擴(kuò)展TextEditor的控件, Dom結(jié)構(gòu), ParserService, 自動(dòng)完成功能代碼等
b, NRefactor :    代碼解析功能
c, CSharpBinding: 對(duì)應(yīng) .cs 文件的具體實(shí)現(xiàn)支持

[題外話(huà)]:
關(guān)于代碼解析(Parser)相關(guān)的代碼,我沒(méi)看懂,所以在這里只說(shuō)個(gè)大概,更多地談?wù)凱arser的使用;拋磚引玉,希望有相關(guān)經(jīng)驗(yàn)的網(wǎng)友提供詳盡的分析。
前兩周工作上的項(xiàng)目實(shí)施,每天都搞得比較累,所以這篇文章到現(xiàn)在才寫(xiě)了出來(lái),明天是大年三十了,這個(gè)系列的文章也只剩下一篇Windows Form Designer,只能等過(guò)了年再放上來(lái)嘍。
另外,這個(gè)系列寫(xiě)完后,暫不打算深究一些沒(méi)明白的細(xì)節(jié),接下來(lái)想看下os workflow 或 CommunityServer...


2、Parser實(shí)現(xiàn)概述

(1)首先,SharpEditor項(xiàng)目中的Dom下定義了以下重要類(lèi):
a, IDecoration及其子類(lèi):   代碼表現(xiàn)的輔助對(duì)象,如IClass, IMethod, IProperty等
b, ResolveResult及其子類(lèi): 分析結(jié)果對(duì)象,如MethodResolveResult, TypeResolveResult等
c, 其它重要類(lèi):           IExpressionFinder, IParser, IResolve, ICompilationUnit 等

(2)重要服務(wù)類(lèi):
ParserService:   提供 GetExpressionFinder(), Resolve(), ParseFile()等重要方法,相關(guān)重要類(lèi): ProjectContentRegistry, DefaultProjectContent, ReflectionProjectContent等
AmbienceService: 提供 IAmbience的實(shí)現(xiàn)類(lèi)用以將分析結(jié)果轉(zhuǎn)換為相應(yīng)的字符描述

(3)Parser分析步驟:
以鼠標(biāo)懸浮的Tooltip顯示為例:DebuggerService根據(jù)文件類(lèi)型返回對(duì)應(yīng)的IExpressionFinder實(shí)現(xiàn)類(lèi),再根據(jù)鼠標(biāo)位置找到并返回ExpressionResult對(duì)象,然后找到適當(dāng)?shù)腎Resolver實(shí)現(xiàn)類(lèi)調(diào)用Resolve()方法返回結(jié)果ResolveResult對(duì)象,最后由相應(yīng)的IAmbience實(shí)現(xiàn)類(lèi)轉(zhuǎn)換成結(jié)果字符,并調(diào)用e.ShowToolTip(toolTipText);顯示。

(4)對(duì)于.NET默認(rèn)類(lèi)庫(kù)的分析轉(zhuǎn)換:
默認(rèn)引進(jìn)的命名空間的類(lèi)結(jié)構(gòu)和文檔說(shuō)明一般可以在"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\"目錄下找到(如System.dll和System.xml),但是如果每次都要重新分析dll代碼結(jié)構(gòu)和xml注釋顯然是比較花費(fèi)時(shí)間的,于是SharpDevelop采用的方式是將分析過(guò)的數(shù)據(jù)(Dom下的類(lèi)結(jié)構(gòu)表示數(shù)據(jù)?,二進(jìn)制的.dat文件)存儲(chǔ)到"C:\Documents and Settings\michael\Local Settings\Temp\SharpDevelop"下,代碼結(jié)構(gòu)存儲(chǔ)到DomCacheDebug目錄下,文檔注釋存儲(chǔ)到DocumentationCacheDebug目錄下。
首先在ParserService的CreateDefaultProjectContent()中加載默認(rèn)命名空間的引用:


 1static void CreateDefaultProjectContent()
 2{
 3    LoggingService.Info("Creating default project content");
 4    LoggingService.Debug("Stacktrace is:\n" + Environment.StackTrace);
 5    defaultProjectContent = new DefaultProjectContent();
 6    defaultProjectContent.ReferencedContents.Add(ProjectContentRegistry.Mscorlib);
 7    string[] defaultReferences = new string[] {
 8        "System",
 9        "System.Data",
10        "System.Drawing",
11        "System.Windows.Forms",
12        "System.XML",
13        "Microsoft.VisualBasic",
14    };
15    foreach (string defaultReference in defaultReferences)
16    {
17        //ReferenceProjectItem item = new ReferenceProjectItem(null, defaultReference);
18        IProjectContent pc = ProjectContentRegistry.GetProjectContentForReference(defaultReference);
19        if (pc != null)
20        {
21            defaultProjectContent.ReferencedContents.Add(pc);
22        }
23    }
24}

其中ProjectContentRegistry的GetProjectContentForReference()方法如下:


 1public static IProjectContent GetProjectContentForReference(string Include)
 2{
 3    // 省略部分代碼
 4    Assembly assembly = GetDefaultAssembly(shortName);
 5    ReflectionProjectContent pc;
 6    if (assembly != null)
 7    {
 8        pc = DomPersistence.LoadProjectContentByAssemblyName(assembly.FullName);
 9        if (pc == null)
10        {
11            pc = new ReflectionProjectContent(assembly);
12            DomPersistence.SaveProjectContent(pc);
13        }
14    }
15    else
16    {
17        pc = LoadProjectContent(itemFileName, itemInclude);
18    }
19    // 省略部分代碼
20    return pc;
21}
22static Assembly GetDefaultAssembly(string shortName)
23{
24    // These assemblies are already loaded by SharpDevelop, so we don‘t need to load
25    // them in a separate AppDomain.
26    switch (shortName) {
27        case "System"// System != mscorlib !!!
28            return SystemAssembly;
29        case "System.Data":
30            return typeof(System.Data.DataException).Assembly;
31        case "System.Design":
32            return typeof(System.ComponentModel.Design.DesignSurface).Assembly;
33        case "System.DirectoryServices":
34            return typeof(System.DirectoryServices.AuthenticationTypes).Assembly;
35        case "System.Drawing":
36            return typeof(System.Drawing.Color).Assembly;
37        case "System.Web.Services":
38            return typeof(System.Web.Services.WebService).Assembly;
39        case "System.Windows.Forms":
40            return typeof(System.Windows.Forms.Control).Assembly;
41        case "System.Xml":
42        case "System.XML":
43            return typeof(XmlReader).Assembly;
44        case "Microsoft.Build.Engine":
45            return typeof(Microsoft.Build.BuildEngine.BuildSettings).Assembly;
46        case "Microsoft.Build.Framework":
47            return typeof(Microsoft.Build.Framework.LoggerVerbosity).Assembly;
48        default:
49            return null;
50    }
51}

可以看到DomPersistence類(lèi)的作用即在加載或保存dll的代碼結(jié)構(gòu)數(shù)據(jù), 如果尚未有分析過(guò)的數(shù)據(jù),則在ReflectionProjectContnet類(lèi)的構(gòu)造函數(shù)中加以分析,同時(shí)調(diào)用XmlDoc類(lèi)的相關(guān)方法加載、保存文檔注釋數(shù)據(jù)。

(5)對(duì)于文件的轉(zhuǎn)換:
[略]


3、Parser應(yīng)用: MouseHover Tooltip

注意在SharpEditor項(xiàng)目中有個(gè)DebuggerService類(lèi),它提供了一個(gè)重要方法如下:


1public static void BindTextAreaEvent(TextEditorControl control)
2{
3    TextArea textArea = control.ActiveTextAreaControl.TextArea;
4    //textArea.IconBarMargin.MouseDown += IconBarMouseDown;
5    textArea.ToolTipRequest -= TextArea_ToolTipRequest;
6    textArea.ToolTipRequest += TextArea_ToolTipRequest;
7}

此方法即用以綁定需要鼠標(biāo)懸浮提示的TextEditor控件,在SharpPad項(xiàng)目的Open菜單類(lèi)方法中調(diào)用此類(lèi)綁定編輯控件。
注意上面的方法中可以看到ICSharpCode.TextEditor控件是通過(guò)其TextArea的ToolTipRequest事件公開(kāi)給外部,用以分析并由外部提供ToolTip數(shù)據(jù),而TextArea_ToolTipRequest(object sender, ToolTipRequestEventArgs e)方法中根據(jù)鼠標(biāo)位置分析出要顯示的數(shù)據(jù)后,最終調(diào)用e.ShowToolTip(toolTipText);用以設(shè)置提供數(shù)據(jù)。


 1static void TextArea_ToolTipRequest(object sender, ToolTipRequestEventArgs e)
 2{
 3    try
 4    {
 5        TextArea textArea = (TextArea)sender;
 6        if (e.ToolTipShown) return;
 7        if (oldToolTipControl != null && !oldToolTipControl.AllowClose) return;
 8        if (!CodeCompletionOptions.TooltipsEnabled) return;
 9
10        if (CodeCompletionOptions.TooltipsOnlyWhenDebugging)
11        {
12            if (currentDebugger == nullreturn;
13            if (!currentDebugger.IsDebugging) return;
14        }
15
16        if (e.InDocument)
17        {
18            Point logicPos = e.LogicalPosition;
19            IDocument doc = textArea.Document;
20            IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(textArea.MotherTextEditorControl.FileName);
21            if (expressionFinder == null)
22                return;
23            LineSegment seg = doc.GetLineSegment(logicPos.Y);
24            if (logicPos.X > seg.Length - 1)
25                return;
26            string textContent = doc.TextContent;
27            ExpressionResult expressionResult = expressionFinder.FindFullExpression(textContent, seg.Offset + logicPos.X);
28            string expression = expressionResult.Expression;
29            if (expression != null && expression.Length > 0)
30            {
31                // Look if it is variable
32                ResolveResult result = ParserService.Resolve(expressionResult, logicPos.Y + 1, logicPos.X + 1, textArea.MotherTextEditorControl.FileName, textContent);
33                bool debuggerCanShowValue;
34                string toolTipText = GetText(result, expression, out debuggerCanShowValue);
35                DebuggerGridControl toolTipControl = null;
36                if (toolTipText != null)
37                {
38                    if (Control.ModifierKeys == Keys.Control)
39                    {
40                        toolTipText = "expr: " + expressionResult.ToString() + "\n" + toolTipText;
41                    }
42                    else if (debuggerCanShowValue && currentDebugger != null)
43                    {
44                        toolTipControl = currentDebugger.GetTooltipControl(expressionResult.Expression);
45                        toolTipText = null;
46                    }
47                }
48                if (toolTipText != null)
49                {
50                    e.ShowToolTip(toolTipText);
51                }
52                if (oldToolTipControl != null)
53                {
54                    Form frm = oldToolTipControl.FindForm();
55                    if (frm != null) frm.Close();
56                }
57                if (toolTipControl != null)
58                {
59                    toolTipControl.ShowForm(textArea, logicPos);
60                }
61                oldToolTipControl = toolTipControl;
62            }
63        }
64    }
65    catch (Exception ex)
66    {
67        MessageBox.Show(ex.ToString());
68    }
69}


4、Parser應(yīng)用: CodeCompletion & MethodInsight

ICSharpCode.TextEditor控件使用ICompletionData類(lèi)以及ICompletionDataProvider接口(GenerateCompletionData()方法)定義數(shù)據(jù)自動(dòng)完成列表的數(shù)據(jù)及其提供者: SharpEditor項(xiàng)目中的AbstractCodeCompletionDataProvider類(lèi)中由GetExpression()及AddResolveResults()兩個(gè)輔助方法生成數(shù)據(jù),代碼如下:


 1protected ArrayList completionData = null;
 2// 
 3protected ExpressionResult GetExpression(TextArea textArea)
 4{
 5    IDocument document = textArea.Document;
 6    IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(fileName);
 7    if (expressionFinder == null{
 8        return new ExpressionResult(TextUtilities.GetExpressionBeforeOffset(textArea, textArea.Caret.Offset));
 9    } else {
10        ExpressionResult res = expressionFinder.FindExpression(document.GetText(0, textArea.Caret.Offset), textArea.Caret.Offset - 1);
11        if (overrideContext != null)
12            res.Context = overrideContext;
13        return res;
14    }
15}
16protected void AddResolveResults(ResolveResult results, ExpressionContext context)
17{
18    insertedElements.Clear();
19    insertedPropertiesElements.Clear();
20    insertedEventElements.Clear();
21    
22    if (results != null{
23        AddResolveResults(results.GetCompletionData(ParserService.CurrentProjectContent), context);
24    }
25}
26protected void AddResolveResults(ICollection list, ExpressionContext context)
27{
28    if (list == null{
29        return;
30    }
31    completionData.Capacity += list.Count;
32    CodeCompletionData suggestedData = null;
33    foreach (object o in list) {
34        if (context != null && !context.ShowEntry(o))
35            continue;
36        CodeCompletionData ccd = CreateItem(o, context);
37        if (object.Equals(o, context.SuggestedItem))
38            suggestedData = ccd;
39        if (ccd != null && !ccd.Text.StartsWith("___"))
40            completionData.Add(ccd);
41    }
42    if (context.SuggestedItem != null{
43        if (suggestedData == null{
44            suggestedData = CreateItem(context.SuggestedItem, context);
45            if (suggestedData != null{
46                completionData.Add(suggestedData);
47            }
48        }
49        if (suggestedData != null{
50            completionData.Sort();
51            this.DefaultIndex = completionData.IndexOf(suggestedData);
52        }
53    }
54}

CommentCompletionDataProvider類(lèi)提供注釋的自動(dòng)完成,相關(guān)代碼如下:


 1string[][] commentTags = new string[][] {
 2    new string[] {"c""marks text as code"},
 3    new string[] {"code""marks text as code"},
 4    new string[] {"example""A description of the code example\n(must have a <code> tag inside)"},
 5    new string[] {"exception cref=\"\"""description to an exception thrown"},
 6    new string[] {"list type=\"\"""A list"},
 7    new string[] {"listheader""The header from the list"},
 8    new string[] {"item""A list item"},
 9    new string[] {"term""A term in a list"},
10    new string[] {"description""A description to a term in a list"},
11    new string[] {"para""A text paragraph"},
12    new string[] {"param name=\"\"""A description for a parameter"},
13    new string[] {"paramref name=\"\"""A reference to a parameter"},
14    new string[] {"permission cref=\"\""""},
15    new string[] {"remarks""Gives description for a member"},
16    new string[] {"include file=\"\" path=\"\"""Includes comments from other files"},
17    new string[] {"returns""Gives description for a return value"},
18    new string[] {"see cref=\"\"""A reference to a member"},
19    new string[] {"seealso cref=\"\"""A reference to a member in the seealso section"},
20    new string[] {"summary""A summary of the object"},
21    new string[] {"value""A description of a property"}
22};
23public override ICompletionData[] GenerateCompletionData(string fileName, TextArea textArea, char charTyped)
24{
25    caretLineNumber = textArea.Caret.Line;
26    caretColumn     = textArea.Caret.Column;
27    LineSegment caretLine = textArea.Document.GetLineSegment(caretLineNumber);
28    string lineText = textArea.Document.GetText(caretLine.Offset, caretLine.Length);
29    if (!lineText.Trim().StartsWith("///"&& !lineText.Trim().StartsWith("‘‘‘")) {
30        return null;
31    }
32    
33    ArrayList completionData = new ArrayList();
34    foreach (string[] tag in commentTags) {
35        completionData.Add(new CommentCompletionData(tag[0], tag[1]));
36    }
37    return (ICompletionData[])completionData.ToArray(typeof(ICompletionData));
38}

類(lèi)似地,ICSharpCode.TextEditor控件提供了IInsightDataProvider接口(GetInsightData()方法),SharpEditor項(xiàng)目中實(shí)現(xiàn)類(lèi)MethodInsightDataProvider和IndexerInsightDataProvider提供相關(guān)數(shù)據(jù)。

除了上面需要提供數(shù)據(jù)的類(lèi)外,還要綁定TextEditor的TextArea的KeyEventHandler事件(詳見(jiàn)SharpEditor項(xiàng)目的SharpDevelopTextAreaControl.cs),其中輔助類(lèi)的處理代碼如下:


  1// 默認(rèn)處理 DefaultCodeCompletionBinding(詳見(jiàn)SharpEditor項(xiàng)目的CodeCompletionBinding.cs):
  2public virtual bool HandleKeyPress(SharpDevelopTextAreaControl editor, char ch)
  3{
  4    switch (ch)
  5    {
  6        case (:
  7            if (enableMethodInsight && CodeCompletionOptions.InsightEnabled)
  8            {
  9                editor.ShowInsightWindow(new MethodInsightDataProvider());
 10                return true;
 11            }
 12            else
 13            {
 14                return false;
 15            }
 16        case [:
 17            if (enableIndexerInsight && CodeCompletionOptions.InsightEnabled)
 18            {
 19                editor.ShowInsightWindow(new IndexerInsightDataProvider());
 20                return true;
 21            }
 22            else
 23            {
 24                return false;
 25            }
 26        case <:
 27            if (enableXmlCommentCompletion)
 28            {
 29                editor.ShowCompletionWindow(new CommentCompletionDataProvider(), ch);
 30                return true;
 31            }
 32            else
 33            {
 34                return false;
 35            }
 36        case .:
 37            if (enableDotCompletion)
 38            {
 39                editor.ShowCompletionWindow(new CodeCompletionDataProvider(), ch);
 40                return true;
 41            }
 42            else
 43            {
 44                return false;
 45            }
 46        case  :
 47            if (!CodeCompletionOptions.KeywordCompletionEnabled)
 48                return false;
 49            string word = editor.GetWordBeforeCaret();
 50            if (word != null)
 51                return HandleKeyword(editor, word);
 52            else
 53                return false;
 54        default:
 55            return false;
 56    }
 57}
 58// .cs 文件的處理(詳見(jiàn)CSharpBinding項(xiàng)目的CSharpCompletionBinding.cs):
 59public override bool HandleKeyPress(SharpDevelopTextAreaControl editor, char ch)
 60{
 61    Parser.ExpressionFinder ef = new Parser.ExpressionFinder(editor.FileName);
 62    int cursor = editor.ActiveTextAreaControl.Caret.Offset;
 63    ExpressionContext context = null;
 64    if (ch == ()
 65    {
 66        if (CodeCompletionOptions.KeywordCompletionEnabled)
 67        {
 68            switch (editor.GetWordBeforeCaret().Trim())
 69            {
 70                case "for":
 71                case "lock":
 72                    context = ExpressionContext.Default;
 73                    break;
 74                case "using":
 75                    context = ExpressionContext.TypeDerivingFrom(ReflectionReturnType.Disposable.GetUnderlyingClass(), false);
 76                    break;
 77                case "catch":
 78                    context = ExpressionContext.TypeDerivingFrom(ReflectionReturnType.Exception.GetUnderlyingClass(), false);
 79                    break;
 80                case "foreach":
 81                case "typeof":
 82                case "sizeof":
 83                case "default":
 84                    context = ExpressionContext.Type;
 85                    break;
 86            }
 87        }
 88        if (context != null)
 89        {
 90            if (IsInComment(editor)) return false;
 91            editor.ShowCompletionWindow(new CtrlSpaceCompletionDataProvider(context), ch);
 92            return true;
 93        }
 94        else if (EnableMethodInsight && CodeCompletionOptions.InsightEnabled)
 95        {
 96            editor.ShowInsightWindow(new MethodInsightDataProvider());
 97            return true;
 98        }
 99        return false;
100    }
101    else if (ch == [)
102    {
103        LineSegment line = editor.Document.GetLineSegmentForOffset(cursor);
104        if (TextUtilities.FindPrevWordStart(editor.Document, cursor) <= line.Offset)
105        {
106            // [ is first character on the line
107            // -> Attribute completion
108            editor.ShowCompletionWindow(new AttributesDataProvider(), ch);
109            return true;
110        }
111    }
112    else if (ch == , && CodeCompletionOptions.InsightRefreshOnComma && CodeCompletionOptions.InsightEnabled)
113    {
114        // Show MethodInsightWindow or IndexerInsightWindow
115        string documentText = editor.Text;
116        int oldCursor = cursor;
117        string textWithoutComments = ef.FilterComments(documentText, ref cursor);
118        int commentLength = oldCursor - cursor;
119        if (textWithoutComments != null)
120        {
121            Stack<ResolveResult> parameters = new Stack<ResolveResult>();
122            char c = \0;
123            while (cursor > 0)
124            {
125                while (--cursor > 0 &&
126                       ((c = textWithoutComments[cursor]) == , ||
127                        char.IsWhiteSpace(c))) ;
128                if (c == ()
129                {
130                    ShowInsight(editor, new MethodInsightDataProvider(cursor + commentLength, true), parameters, ch);
131                    return true;
132                }
133                else if (c == [)
134                {
135                    ShowInsight(editor, new IndexerInsightDataProvider(cursor + commentLength, true), parameters, ch);
136                    return true;
137                }
138                string expr = ef.FindExpressionInternal(textWithoutComments, cursor);
139                if (expr == null || expr.Length == 0)
140                    break;
141                parameters.Push(ParserService.Resolve(new ExpressionResult(expr),
142                                                      editor.ActiveTextAreaControl.Caret.Line,
143                                                      editor.ActiveTextAreaControl.Caret.Column,
144                                                      editor.FileName,
145                                                      documentText));
146                cursor = ef.LastExpressionStartPosition;
147            }
148        }
149    }
150    else if (ch == =)
151    {
152        LineSegment curLine = editor.Document.GetLineSegmentForOffset(cursor);
153        string documentText = editor.Text;
154        int position = editor.ActiveTextAreaControl.Caret.Offset - 2;
155
156        if (position > 0 && (documentText[position + 1== +))
157        {
158            ExpressionResult result = ef.FindFullExpression(documentText, position);
159
160            if (result.Expression != null)
161            {
162                ResolveResult resolveResult = ParserService.Resolve(result, editor.ActiveTextAreaControl.Caret.Line, editor.ActiveTextAreaControl.Caret.Column, editor.FileName, documentText);
163                if (resolveResult != null && resolveResult.ResolvedType != null)
164                {
165                    IClass underlyingClass = resolveResult.ResolvedType.GetUnderlyingClass();
166                    if (underlyingClass != null && underlyingClass.IsTypeInInheritanceTree(ProjectContentRegistry.Mscorlib.GetClass("System.MulticastDelegate")))
167                    {
168                        EventHandlerCompletitionDataProvider eventHandlerProvider = new EventHandlerCompletitionDataProvider(result.Expression, resolveResult);
169                        eventHandlerProvider.InsertSpace = true;
170                        editor.ShowCompletionWindow(eventHandlerProvider, ch);
171                    }
172                }
173            }
174        }
175    }
176    else if (ch == ;)
177    {
178        LineSegment curLine = editor.Document.GetLineSegmentForOffset(cursor);
179        // don‘t return true when inference succeeds, otherwise the ‘;‘ won‘t be added to the document.
180        TryDeclarationTypeInference(editor, curLine);
181    }
182
183    return base.HandleKeyPress(editor, ch);
184}


5、Parser應(yīng)用: QuickClassBrowserPanel

QuickClassBrowserPanel即編輯窗口頂部的類(lèi)及成員快速瀏覽窗口,其實(shí)現(xiàn)如下:
首先在SharpDevelopTextAreaControl類(lèi)中重寫(xiě)override void OnFileNameChanged(EventArgs e)方法,即打開(kāi)新文件時(shí),調(diào)用ActivateQuickClassBrowserOnDemand()來(lái)根據(jù)是否有能夠分析此文件的Parser來(lái)決定是否顯示控件,如果可以顯示,則實(shí)例化出一個(gè)新對(duì)象,并添加進(jìn)來(lái)。實(shí)例化QuickClassBrowserPanel對(duì)象的相關(guān)代碼如下:


 1private System.Windows.Forms.ComboBox classComboBox;
 2private System.Windows.Forms.ComboBox membersComboBox;
 3ICompilationUnit            currentCompilationUnit;
 4// 
 5public QuickClassBrowserPanel(SharpDevelopTextAreaControl textAreaControl)
 6{
 7    InitializeComponent();
 8    this.membersComboBox.MaxDropDownItems = 20;
 9
10    base.Dock = DockStyle.Top;
11    this.textAreaControl = textAreaControl;
12    this.textAreaControl.ActiveTextAreaControl.Caret.PositionChanged += new EventHandler(CaretPositionChanged);
13}
14void CaretPositionChanged(object sender, EventArgs e)
15{
16    // ignore simple movements
17    if (e != EventArgs.Empty) {
18        return;
19    }
20    try {
21        
22        ParseInformation parseInfo = ParserService.GetParseInformation(textAreaControl.FileName);
23        if (parseInfo != null{
24            if (currentCompilationUnit != (ICompilationUnit)parseInfo.MostRecentCompilationUnit) {
25                currentCompilationUnit = (ICompilationUnit)parseInfo.MostRecentCompilationUnit;
26                if (currentCompilationUnit != null{
27                    
28                    FillClassComboBox(true);
29                    FillMembersComboBox();
30                }
31            }
32            UpdateClassComboBox();
33            UpdateMembersComboBox();
34        }
35    } catch (Exception ex) {
36        MessageService.ShowError(ex);
37    }
38}

可以看到類(lèi)、成員列表的ComboBox數(shù)據(jù)的填充是在textAreaControl.ActiveTextAreaControl.Caret.PositionChanged事件后執(zhí)行,因?yàn)楣鈽?biāo)位置的改變可能需要同步更新頂部列表框的顯示;注意兩個(gè)列表的列表項(xiàng)使用自定義類(lèi)ComboBoxItem, 包括成員的Line, Column等信息;該類(lèi)中綁定兩個(gè)列表的SelectedIndexChange事件用以在編輯器中定位相應(yīng)的類(lèi)或成員位置:


 1void ComboBoxSelectedIndexChanged(object sender, System.EventArgs e)
 2{
 3    ComboBox comboBox = (ComboBox)sender;
 4    if (autoselect) {
 5        ComboBoxItem item = (ComboBoxItem)comboBox.Items[comboBox.SelectedIndex];
 6        if (item.IsInCurrentPart)
 7        {
 8            textAreaControl.ActiveTextAreaControl.Caret.Position = new Point(item.Column, item.Line);
 9            textAreaControl.ActiveTextAreaControl.TextArea.Focus();
10        }
11    }
12}


6、Parser應(yīng)用: Folding

ICSharpCode.TextEditor控件提供了IFoldingStrategy接口用以定義代碼折疊需實(shí)現(xiàn)的方法:


 1/// <summary>
 2/// This interface is used for the folding capabilities
 3/// of the textarea.
 4/// </summary>
 5public interface IFoldingStrategy
 6{
 7    /// <remarks>
 8    /// Calculates the fold level of a specific line.
 9    /// </remarks>
10    List<FoldMarker> GenerateFoldMarkers(IDocument document, string fileName, object parseInformation);
11}

SharpEditor項(xiàng)目中,SharpDevelopTextAreaControl在構(gòu)造函數(shù)中指明了FoldingStrategy:


 1public SharpDevelopTextAreaControl()
 2{
 3    Document.FoldingManager.FoldingStrategy = new ParserFoldingStrategy();
 4
 5    // 由于UpdateClassMemberBookmarks()方法中以Bookmark形式顯示方法、屬性、變量等
 6    // 故此處需要定義Bookmark Factory 以使上面的Bookmark 與用戶(hù)加入的書(shū)簽區(qū)別開(kāi)
 7    Document.BookmarkManager.Factory = new Bookmarks.SDBookmarkFactory(Document.BookmarkManager);
 8}
 9protected override void OnFileNameChanged(EventArgs e)
10{
11    base.OnFileNameChanged(e);
12    ActivateQuickClassBrowserOnDemand();
13    ForceFoldingUpdate();
14}
15void ForceFoldingUpdate()
16{
17    ParseInformation parseInfo = ParserService.GetParseInformation(FileName);
18    if (parseInfo == null)
19    {
20        parseInfo = ParserService.ParseFile(FileName, Document.TextContent, falsefalse);
21    }
22    Document.FoldingManager.UpdateFoldings(FileName, parseInfo);
23    
24    // 在編輯器的類(lèi)、屬性、變量等行左側(cè)顯示相應(yīng)圖標(biāo)
25    UpdateClassMemberBookmarks(parseInfo);
26}

同樣需要在打開(kāi)新文件時(shí)調(diào)用更新代碼折疊標(biāo)簽,代碼折疊FoldMarker生成的具體實(shí)現(xiàn)詳見(jiàn)SharpEditor項(xiàng)目的ParserFoldingStrategy.cs


7、總結(jié)

上面簡(jiǎn)要介紹了Parser的部分實(shí)現(xiàn), 期待有相關(guān)經(jīng)驗(yàn)的網(wǎng)友指定我的理解錯(cuò)誤或給予補(bǔ)充解釋。
以及Parser的部分應(yīng)用:MouseHover Tooltip, CodeCompletion & MethodInsight, QuickClassBrowserPanel, Folding;SharpDevelop中的其它應(yīng)用如類(lèi)視圖ClassBrowser, 對(duì)象瀏覽AssemblyPad(SharpDevelop2.0源碼中未見(jiàn)到?).

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多