实现Visual Studio 2010一个源代码的统计信息扩展介绍

推荐 百搜技术网:http://www.baisoujs.com html

基本介绍篇 android

本人推荐学习资料技术网:http://www.baisoujs.com/list_android_andarticle.html 浏览器

在实现这个扩展以前,让咱们先弄清楚这个扩展实现什么功能。这个扩展其实是在你的VS窗口的右上角建立了一个信息框代码。该信息框显示您的源代码的统计信息。这些信息包括: 编辑器

一、文件的代码行数 函数

二、文件的字符数 布局

三、命名空间的个数 学习

四、字段个数 ui

五、接口个数 this

六、类的个数 spa

七、函数个数

八、属性个数

九、注释的数量

十、统计文件的大小(Bytes, KB, MB等)。

Visual Studio 2010 扩展插件

当您键入您的代码,你会看到信息窗口中的数据会即时更新。

这个信息窗口,是利用可扩展面板。你能够把它当作两个部分,每个部分均可以根据您的须要展开和折叠。这样,当你不须要它时,你将它能够折叠起来,须要的时候,将它展开。下面演示如何展开/折叠这个控件。

Visual Studio 2010 扩展插件

这个控件有三个特殊的状态。第一个状态是一个很小的扩展按钮。如上图的第一部分。只需点击它,就会打开控件右侧的面板,这个面板显示文件的基本数据,如上图的第二部分。这个控件还有一个可扩展面板,若是点击扩展,就会看到下面的面板,其中显示其余的统计数据,如上图的第三部分。

实现篇:

须要软件:

一、 Microsoft Visual Studio 2010

二、 Visual Studio 2010 SDK

你安装 Visual Studio SDK以后,你的Visual Studio 2010中会多出下面这些模板:

Visual Studio 2010 扩展插件

这篇文章中,咱们使用模板Editor ViewPort Adornment实现这个扩展,此模板将为你的代码编辑器的带来一个装饰品。 

其实这个扩展包一个WPF用户控件,我把它放进VS的视窗中就成了信息框。它还含有两个类,一个类用来解析代码,获取代码的相关信息;另外一个类用来处理自定义编辑器的事件和当页以及加载的时候将WPF控件添加到页面中。

第一步:建立一个Viewport Adornment项目

咱们从Extensibility中选择Viewport Adornment模板建立一个项目。这将生成一个SourceManifest文件和两个类文件。一个是Adornment类自己,另一个是AdornmentFactory类。

第二步:添加一个WPF用户控件

右键单击项目,选择添加一个新的WPF用户控件。为了简单起见,我使用了一个用户控件。这个用户控件实际上包含一个Expander控件,设置它的ExpandDirection = Left,它里面又包含了一些TextBlock控件和另一个Expander ,设置里面的这个Expander的ExpandDirection = Down。看下面的代码(我删除没必要要的元素,使其更简单):


 


你能够看到,代码很简单,两个Expanders,一个用来显示基本的统计信息和另一个显示扩展的统计信息。我还使用StackPanel来固定TextBlocks布局。

如今,若是你看一下后台代码,发现它也同样简单。其实我已经建立了一个CodeInfoTracker类,用它来为咱们分析源代码文件。我只是为咱们的用户控件添加了一个构造函数,使用户控件更具扩展性而已。


//百搜技术:http://www.baisoujs.com
private CodeInfoTracker _cinfo;
 private CodeInfoTracker.Calculators _calculator;
 public ucInfoBox(CodeInfoTracker cinfo)
             : this()
 {
         this._cinfo = cinfo;
 }
  public void UpdateInfo(CodeInfoTracker info)
  {
             _calculator = info.PerFormCalculate();
             this.txtNoLines.Text = string.Format("No of Lines : {0}", 
                                     _calculator.no_of_lines);
             this.txtNoCharacters.Text = string.Format("No of Characters : {0}", 
                                                        _calculator.no_of_characters);
             this.txtFileSize.Text = string.Format("Total File Size : {0}", 
                                                        _calculator.totalfilesize);
 
             StringBuilder builder = new StringBuilder();
             if (this._calculator.interfaces != 0)
                 builder.AppendFormat("Interfaces : {0}\n\r", 
                                           this._calculator.interfaces);
             if (this._calculator.namespaces != 0)
                 builder.AppendFormat("NameSpaces : {0}\n\r", 
                                             this._calculator.namespaces);
             if (this._calculator.classes != 0)
                 builder.AppendFormat("Classes : {0}\n\r", 
                                             this._calculator.classes);
             if (this._calculator.methods != 0)
                 builder.AppendFormat("Methods : {0}\n\r", this._calculator.methods);
             if (this._calculator.properties != 0)
                 builder.AppendFormat("Properties : {0}\n\r", 
                                                this._calculator.properties);
             if (this._calculator.fields != 0)
                 builder.AppendFormat("Fields : {0}\n\r", this._calculator.fields);
             if (this._calculator.comments != 0)
                 builder.AppendFormat("Comments : {0}\n\r", this._calculator.comments);
 
             if (builder.Length > 0)
             {
                 this.txtClassInfo.Visibility = System.Windows.Visibility.Visible;
                 this.txtClassInfo.Text = builder.ToString();
             }
             else
             {
                 this.txtClassInfo.Text = "";
                 this.txtClassInfo.Visibility = System.Windows.Visibility.Hidden;
        }
   }


使用了一个结构体Calculators ,这个结构体放置在咱们的自定义类中,它有几个int属性用来保存分析源文件获取的全部信息。 info.PerFormCalculate(); 给出分析的结果。这里使用的全部获取的信息来更新了UIElements。

第三步:建立获取源文件信息的类

虽然代码存在一些复杂性,可是这个类其实很简单。我很感谢CS Parser ,它帮助我自动地解析源代码。 
这个类须要一个IWpfTextView对象,它表明着Visual Studio文本编辑器。实际上WpfTextView实现了IWpfTextView。在执行期间这个类接受这个对象。我能够从WPFTextView.TextSnapshot.GetText()得到到了源代码。

在我调用的这个分析的时候,我只须要检测的代码是什么语言写的。开始我想本身来实现,可是感谢上帝,我在WPFTextView中发现已经存在这个对象了。


//百搜技术:http://www.baisoujs.com

public enum Language
 {
         CSharp, VisualBasic, Indeterminate
 }
 internal Language DetectLanguage
 {
             get
             {
                 string langtype = 
         this._view.FormattedLineSource.TextAndAdornmentSequencer.
         SourceBuffer.ContentType.DisplayName;
                 if(langtype.Equals("CSHARP", 
             StringComparison.InvariantCultureIgnoreCase))
                     return Language.CSharp;
                 else if(langtype.Equals("BASIC", 
                               StringComparison.InvariantCultureIgnoreCase))
                     return Language.VisualBasic;
                 else
                     return Language.Indeterminate;
             }
 }


DetectLanguage妥善地利用WPFTextView对象的FormattedLineSource.TextAndAdornmentSequencer.
SourceBuffer.ContentType.DisplayName,这个属性告诉我是使用了哪一种语言。以后我建立了一个新的方法PerFormCalculate,用它来解析源代码,它返回一个Calculation结构对象。

第四步:建立 Adornment Factory 类

回到这个扩展,我建立一个Adornment(InfoBoxAdornmentFactory)的Factory类。这个类继承IWpfTextViewCreationListener,用来监听WPF的编辑和建立事件。


[Export(typeof(IWpfTextViewCreationListener))]
 [ContentType("text")]
 [TextViewRole(PredefinedTextViewRoles.Document)] 
 internal sealed class InfoBoxAdornmentFactory : IWpfTextViewCreationListener
 {
         [Export(typeof(AdornmentLayerDefinition))]
         [Name("AlwaysVisibleInfoBox")]
         [Order(After = PredefinedAdornmentLayers.Selection)]
         [TextViewRole(PredefinedTextViewRoles.Interactive)]
         public AdornmentLayerDefinition editorAdornmentLayer = null;
         public void TextViewCreated(IWpfTextView textView)
         {
             new AlwaysVisibleInfoBox(textView);
         }
  }


这里,你能够看到我在这个类上使用了不少Attributes,像ContentType,它定义了咱们只处理文本格式的编辑器;还有TextViewRole,它定义了将被这个类处理的textview的类型。

在这个类中,我建立了一个AdornmentLayerDefination对象。可能你想知道咱们没有使用它,无什么还须要定义它呢,它只是用来配置属性的。Order属性指定,当,InfoBox在层被选以后监听,Name是编辑扩展的名字。

第五步:建立Adornment 类

Adornment类实际建立了一个WPF用户控件对象,并设置它的视图画布。在内部构造函数中,我处理IWpfTextView.LayoutChanged事件,当代码修改或者布局改变的时候,就触发这个事件。所以,经过这一事件,当咱们编辑的文档时,咱们能够很容易地获得回调。当浏览器编辑器的大小改变时,我还经过处理WPFTextView.ViewportHeightChanged,WPFTextView.ViewportWidthChanged获得回调,使咱们能够从新定位相应的UserControl。


//百搜技术:http://www.baisoujs.com

public AlwaysVisibleInfoBox(IWpfTextView view)
 {
           _view.LayoutChanged += this.OnLayoutChanged;
           this.GetLayer();
 }
//http://www.baisoujs.com private void GetLayer()
  {
             _adornmentLayer = this._view.GetAdornmentLayer("AlwaysVisibleInfoBox");
             _view.ViewportHeightChanged += delegate { this.onSizeChange(); };
             _view.ViewportWidthChanged += delegate { this.onSizeChange(); };
 }
  private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
 {
             this._info = new CodeInfoTracker(_view);
             this.infobox.UpdateInfo(this._info);
  }
  public void onSizeChange()
  {
      
             _adornmentLayer.RemoveAllAdornments();
             Canvas.SetLeft(infobox, _view.ViewportRight - 255);
             Canvas.SetTop(infobox, _view.ViewportTop + 10);
             
           _adornmentLayer.AddAdornment(AdornmentPositioningBehavior.ViewportRelative, 
           null, null, 
           infobox, null);
 }


所以,构造函数只是调用GetLayer来获取的Layer对象,发生在ViewportHeightChanged和ViewportWidthChanged ViewPortSizeChage事件。当一个布局改变时,我就能更新这个用户的控件。

至此,咱们成功地创建咱们的扩展。你可使用F5运行它,它会打开一个Visual Studio的Experimental实例。

安装和卸载这个扩展:

安装和卸载这个扩展是很是容易的。当您编译项目后,它会产生一个VSIX文件。您能够只需双击这个文件,它会自动安装到Visual Studio。

Visual Studio 2010 扩展插件

要卸载的文件,您打开Visual Studio,转到 Tools - > Extension Manager,而后选择卸载该扩展。

发布您的扩展:

发布你的扩展到Visual Studio库的方式也很是的酷。只要你须要上传VSIX文件到http://www.baisoujs.com/detail_137433956352461.html。我已经上载个人这个扩展。

//百搜技术:http://www.baisoujs.com

相关文章
相关标签/搜索