實現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

相關文章
相關標籤/搜索