|
Parser及其應(yīng)用: Code Completion, Method Insight, Class Scout ... 1、Demo界面及功能解釋 [題外話(huà)]:
(2)重要服務(wù)類(lèi): (3)Parser分析步驟: (4)對(duì)于.NET默認(rèn)類(lèi)庫(kù)的分析轉(zhuǎn)換: 1 static 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()方法如下: 1 public 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 else16 {17 pc = LoadProjectContent(itemFileName, itemInclude);18 }19 // 省略部分代碼20 return pc;21 }22 static Assembly GetDefaultAssembly(string shortName)23 {24 // These assemblies are already loaded by SharpDevelop, so we don‘t need to load25 // 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)換:
1 public 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)綁定編輯控件。 1 static void TextArea_ToolTipRequest(object sender, ToolTipRequestEventArgs e)2 {3 try4 {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 == null) return;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 variable32 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 }
1 protected ArrayList completionData = null;2 // ![]() 3 protected 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 }16 protected 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 }26 protected 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)代碼如下: 1 string[][] 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 };23 public 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):2 public 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 else13 {14 return false;15 }16 case ‘[‘:17 if (enableIndexerInsight && CodeCompletionOptions.InsightEnabled)18 {19 editor.ShowInsightWindow(new IndexerInsightDataProvider());20 return true;21 }22 else23 {24 return false;25 }26 case ‘<‘:27 if (enableXmlCommentCompletion)28 {29 editor.ShowCompletionWindow(new CommentCompletionDataProvider(), ch);30 return true;31 }32 else33 {34 return false;35 }36 case ‘.‘:37 if (enableDotCompletion)38 {39 editor.ShowCompletionWindow(new CodeCompletionDataProvider(), ch);40 return true;41 }42 else43 {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 else53 return false;54 default:55 return false;56 }57 }58 // .cs 文件的處理(詳見(jiàn)CSharpBinding項(xiàng)目的CSharpCompletionBinding.cs):59 public 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 line107 // -> Attribute completion108 editor.ShowCompletionWindow(new AttributesDataProvider(), ch);109 return true;110 }111 }112 else if (ch == ‘,‘ && CodeCompletionOptions.InsightRefreshOnComma && CodeCompletionOptions.InsightEnabled)113 {114 // Show MethodInsightWindow or IndexerInsightWindow115 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 }
1 private System.Windows.Forms.ComboBox classComboBox;2 private System.Windows.Forms.ComboBox membersComboBox;3 ICompilationUnit currentCompilationUnit;4 // ![]() 5 public 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 }14 void CaretPositionChanged(object sender, EventArgs e)15 {16 // ignore simple movements17 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)或成員位置: 1 void 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 }
1 /// <summary>2 /// This interface is used for the folding capabilities3 /// of the textarea.4 /// </summary>5 public interface IFoldingStrategy6 {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: 1 public 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 }9 protected override void OnFileNameChanged(EventArgs e)10 {11 base.OnFileNameChanged(e);12 ActivateQuickClassBrowserOnDemand();13 ForceFoldingUpdate();14 }15 void ForceFoldingUpdate()16 {17 ParseInformation parseInfo = ParserService.GetParseInformation(FileName);18 if (parseInfo == null)19 {20 parseInfo = ParserService.ParseFile(FileName, Document.TextContent, false, false);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
|
|
|
來(lái)自: 快樂(lè)學(xué)習(xí) > 《SharpDevelop》