{"id":123500,"date":"2009-11-23T15:50:00","date_gmt":"2009-11-23T15:50:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/visualstudio\/2009\/11\/23\/whats-new-for-editor-extenders-in-beta-2\/"},"modified":"2019-02-14T15:42:06","modified_gmt":"2019-02-14T23:42:06","slug":"whats-new-for-editor-extenders-in-beta-2-2","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/visualstudio\/whats-new-for-editor-extenders-in-beta-2-2\/","title":{"rendered":"What&#8217;s new for editor extenders in Beta 2?"},"content":{"rendered":"<p><DIV id=\"author\">\n<P><A href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/NoahRic_2.png\"><IMG title=\"Noah Richards\" border=\"0\" alt=\"Noah Richards\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/02\/NoahRic_thumb.png\" width=\"81\" height=\"105\"><\/A> <STRONG>Noah Richards<\/STRONG> \u2013 Developer, Visual Studio Editor Team <BR><STRONG>Short Bio:<\/STRONG>&nbsp; Noah has been working on the Visual Studio Editor team since he graduated college two and a half years ago.&nbsp; He maintains a <A title=\"Noah's Blog : Letters from the editor\" href=\"http:\/\/blogs.msdn.com\/noahric\">blog<\/A>, posts <A title=\"GitHub : NoahRic's Profile\" href=\"http:\/\/github.com\/noahric\">sample code<\/A> for editor extensions, and frequently answers editor-related questions <A title=\"Noah Richards (noahsmark) on Twitter\" href=\"https:\/\/twitter.com\/noahsmark\">on Twitter<\/A>.<\/P>\n<P><EM>Editor\u2019s Note:&nbsp; This post was <A title=\"Letters from the editor : What's new for extenders in Beta 2?\" href=\"http:\/\/blogs.msdn.com\/noahric\/archive\/2009\/11\/04\/what-s-new-for-extenders-in-beta-2.aspx\">originally published<\/A> on <A title=\"Noah's Blog : Letters from the editor\" href=\"http:\/\/blogs.msdn.com\/noahric\">Noah\u2019s personal blog<\/A>, which we\u2019d encourage you to follow for additional content about the new VS 2010 editor and its extensibility.<\/EM><\/P><\/DIV>\n<P>Now that Visual Studio 2010 Beta 2 has been out for about a month, most of you have probably seen it and tried many of its new features.&nbsp; For those interested in writing extensions for VS, we wanted to share a couple of updates around editor extensibility, particularly for people who wrote extensions in Beta 1 and want to upgrade to Beta 2.<\/P>\n<H4>1 \u2013 No More <FONT face=\"Consolas\">IEnvironment<\/FONT><\/H4>\n<P>If you wrote any code that had classifiers or taggers or various other extensions that take an <FONT face=\"Consolas\">IEnvironment<\/FONT> parameter, you&#8217;ll be deleting those parameters in Beta 2. <FONT face=\"Consolas\">IEnvironment<\/FONT> had a few historical reasons for being there (back when the editor was a part of a different project and not in Visual Studio yet), but it wasn&#8217;t really serving a purpose anymore. In Beta 1, all it really did was confuse people and make you type an extra few characters and\/or add an FxCop suppression since you weren&#8217;t using it. This is a small change but a simplifying one. (If you are curious about the one place that did use it for taggers, see #5 below).<\/P>\n<H4>2 \u2013 Mouse and key processors get more metadata<\/H4>\n<P>In Beta 2, mouse and key processor providers take the following metadata; note that some of these were required for mouse <EM>or<\/EM> key processors, but now the list applies to both:<\/P>\n<OL>\n<LI><CODE><FONT face=\"Consolas\">Export<\/FONT><\/CODE>, like all components <\/LI>\n<LI><CODE><FONT face=\"Consolas\">ContentType<\/FONT><\/CODE> <\/LI>\n<LI><CODE><FONT face=\"Consolas\">Name<\/FONT><\/CODE> and <CODE><FONT face=\"Consolas\">Order<\/FONT><\/CODE>, so that you can position yourself before or after other known handlers. This is important in cases where you want to preempt whatever normally happens in a certain event. <\/LI>\n<LI><CODE><FONT face=\"Consolas\">TextViewRole<\/FONT><\/CODE><\/LI><\/OL>\n<P>Also, somewhat tangentially, the <CODE><FONT face=\"Consolas\">ContentType<\/FONT><\/CODE> attribute now applies to any buffer in a view&#8217;s graph &#8211; that&#8217;s just a fancy way of saying that if you have something like an ASP.NET page that has embedded C#, your key or mouse processors will get loaded if they have <CODE><FONT face=\"Consolas\">[ContentType(&#8220;CSharp&#8221;)]<\/FONT><\/CODE>.<\/P>\n<P>These fixes were necessary to write the <A title=\"Letters from the editor : Beta 2!\" href=\"http:\/\/blogs.msdn.com\/noahric\/archive\/2009\/10\/19\/beta-2.aspx\">triple click extension<\/A>, which selects a line on triple click (you can find <A title=\"GitHub : NoahRic's TripleClick\" href=\"http:\/\/github.com\/NoahRic\/TripleClick\">its code on github<\/A> and <A title=\"VS Gallery : Triple Click Extension\" href=\"http:\/\/visualstudiogallery.msdn.microsoft.com\/en-us\/2bbdc70c-32f7-4b69-8cff-d8190cae0cc7\">its binaries on the VS Gallery<\/A>). Without the ordering, I couldn&#8217;t put the mouse handler early enough to work correctly. Also, there were a few bugs in some of the default mouse handlers that have since been fixed.<\/P>\n<P>Note that, unfortunately, the general guidance is to <EM>not<\/EM> use keyboard providers. The VS command system and the way components like the editor plug in don&#8217;t play very well with normal WPF keyboard input, so the short story is that you&#8217;ll only get keyboard events for key combinations that aren&#8217;t already bound to a command. Which leads me to the next new thing&#8230;<\/P>\n<H4>3 \u2013 Listening for the creation of <FONT face=\"Consolas\">IVsTextView<\/FONT> adapters (<FONT face=\"Consolas\">IVsTextViewCreationListener<\/FONT>)<\/H4>\n<P>We added this as an extension to the VS integration piece of the editor to allow people to listen for the creation of <FONT face=\"Consolas\">IVsTextView<\/FONT> (which is what the underlying <FONT face=\"Consolas\">IWpfTextView<\/FONT> \/<FONT face=\"Consolas\">ITextView<\/FONT> are wrapped in for the sake of people who still use the existing VS API). It&#8217;s effectively identical to <FONT face=\"Consolas\">IWpfTextViewCreationListener<\/FONT>, except that you get an <FONT face=\"Consolas\">IVsTextView<\/FONT> instead of an <FONT face=\"Consolas\">IWpfTextView<\/FONT> when called.<\/P>\n<P><EM>A quick note \u2013 if you want to use this extension, you&#8217;ll need to add a reference to <CODE><FONT face=\"Consolas\">Microsoft.VisualStudio.Editor.dll<\/FONT><\/CODE>. It&#8217;s in the SDK, so that&#8217;s not a problem, but it isn&#8217;t a part of any of the standard editor project templates.<\/EM><\/P>\n<P>The biggest reason we introduced this was for extensions that want to add command handlers to the editor. You could do this in the past, somewhat painfully, by doing the following:<\/P>\n<OL>\n<LI>Write an <FONT face=\"Consolas\">IWpfTextViewCreationListener<\/FONT> <\/LI>\n<LI>The ugly step &#8211; listen for the <FONT face=\"Consolas\">GotAggregateFocus <\/FONT>event on the text view and do the remaining steps in that handler. If you skipped this step, the eventually attempt at getting the <FONT face=\"Consolas\">IVsTextView<\/FONT> would fail, since the two objects weren&#8217;t fully hooked up yet. <\/LI>\n<LI>With an <CODE><FONT face=\"Consolas\">[Import]<\/FONT><\/CODE>ed <CODE><FONT face=\"Consolas\">IVsEditorAdaptersFactoryService<\/FONT><\/CODE>, call <CODE><FONT face=\"Consolas\">GetViewAdapter<\/FONT><\/CODE> to get the <FONT face=\"Consolas\">IVsTextView<\/FONT>. <\/LI>\n<LI>Call <CODE><FONT face=\"Consolas\">IVsTextView.AddCommandFilter<\/FONT><\/CODE> <\/LI>\n<LI>&#8230;and don&#8217;t forget to unsubscribe from <CODE><FONT face=\"Consolas\">GotAggregateFocus<\/FONT><\/CODE> or use a flag so that you only listen to the first time the event is raised. <\/LI><\/OL>\n<P>With the new event, you just need to:<\/P>\n<OL>\n<LI>Write an <CODE><FONT face=\"Consolas\">IVsTextViewCreationListener<\/FONT><\/CODE> <\/LI>\n<LI>Call <CODE><FONT face=\"Consolas\">IVsTextView.AddCommandFilter<\/FONT><\/CODE><\/LI><\/OL>\n<P>If you do want to get the associated <FONT face=\"Consolas\">IWpfTextView<\/FONT> for the <FONT face=\"Consolas\">IVsTextView<\/FONT> adapter, you can do the opposite of #3 above (using <CODE><FONT face=\"Consolas\">GetWpfTextView<\/FONT><\/CODE>); the upside, relative to the above list, is that you don&#8217;t need to worry about initialization being finished. When you get the call in your creation listener, initialization has completed to the point that <CODE><FONT face=\"Consolas\">GetWpfTextView<\/FONT><\/CODE> will always succeed.<\/P>\n<P>Because command filters are still not entirely obvious to get correct, I&#8217;m working on a template to do this for you. More in general, I&#8217;m working on a set of &#8220;New Item&#8221; templates for the editor, so that you can add new components (or at least a skeleton of a new component) with a couple clicks in an existing project. I haven\u2019t finished these yet, but you can see the work in progress on <A title=\"GitHub : CommandFilter.cs from NoahRic's EditorItemTemplates\" href=\"http:\/\/github.com\/NoahRic\/EditorItemTemplates\/blob\/master\/CommandFilter.cs\">CommandFilter.cs<\/A>.<\/P>\n<H4>4 \u2013 Custom text marker visual definitions<\/H4>\n<P>One of the other things missing in Beta 1 was the ability to set the visualizations for text markers (the markers you can create with an <CODE><FONT face=\"Consolas\">ITagger&lt;TextMarkerTag&gt;<\/FONT><\/CODE>). There were some built-in marker types, but they were somewhat limited.<\/P>\n<P>In Beta 2, that&#8217;s now changed, and you can export a <CODE><FONT face=\"Consolas\">MarkerFormatDefinition<\/FONT><\/CODE> that looks something like this:<\/P>\n<P class=\"MsoNormal\"><SPAN><FONT size=\"2\" face=\"Consolas\">Export(<SPAN>typeof<\/SPAN>(EditorFormatDefinition))] <BR><\/FONT><\/SPAN><SPAN><FONT size=\"2\" face=\"Consolas\">[Name(<SPAN>&#8220;mymarker&#8221;<\/SPAN>)]<\/FONT><\/SPAN><\/P>\n<P><SPAN><FONT size=\"2\" face=\"Consolas\">internal<\/FONT><\/SPAN><SPAN><FONT size=\"2\" face=\"Consolas\"> <\/FONT><FONT color=\"#333333\"><FONT face=\"Consolas\"><FONT size=\"2\"><SPAN>sealed<\/SPAN> <SPAN>class<\/SPAN> <SPAN>MyMarkerDefinition<\/SPAN> : MarkerFormatDefinition <BR><\/FONT><\/FONT><\/FONT><\/SPAN><SPAN><FONT size=\"2\" face=\"Consolas\">{ <BR><\/FONT><\/SPAN><SPAN><SPAN><FONT size=\"2\" face=\"Consolas\">&nbsp;&nbsp;&nbsp; <\/FONT><\/SPAN><FONT color=\"#333333\"><FONT face=\"Consolas\"><FONT size=\"2\"><SPAN>public<\/SPAN> MyMarkerDefinition() <BR><\/FONT><\/FONT><\/FONT><\/SPAN><SPAN><FONT face=\"Consolas\"><FONT size=\"2\"><SPAN>&nbsp;&nbsp;&nbsp; <\/SPAN>{ <BR><\/FONT><\/FONT><\/SPAN><SPAN><SPAN><FONT size=\"2\" face=\"Consolas\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/FONT><\/SPAN><FONT color=\"#333333\"><FONT face=\"Consolas\"><FONT size=\"2\"><SPAN>this<\/SPAN>.ZOrder = <SPAN>1<\/SPAN>; <BR><\/FONT><\/FONT><\/FONT><\/SPAN><SPAN><SPAN><FONT size=\"2\" face=\"Consolas\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/FONT><\/SPAN><FONT color=\"#333333\"><FONT face=\"Consolas\"><FONT size=\"2\"><SPAN>this<\/SPAN>.Fill = <SPAN>Brushes<\/SPAN>.Blue; <BR><\/FONT><\/FONT><\/FONT><\/SPAN><SPAN><SPAN><FONT size=\"2\" face=\"Consolas\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/FONT><\/SPAN><FONT color=\"#333333\"><FONT face=\"Consolas\"><FONT size=\"2\"><SPAN>this<\/SPAN>.Border = <SPAN>new<\/SPAN> <SPAN>Pen<\/SPAN>(<SPAN>Brushes<\/SPAN>.DarkGray, <SPAN>0.5<\/SPAN>); <BR><\/FONT><\/FONT><\/FONT><\/SPAN><SPAN><SPAN><FONT size=\"2\" face=\"Consolas\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/FONT><\/SPAN><FONT color=\"#333333\"><FONT face=\"Consolas\"><FONT size=\"2\"><SPAN>this<\/SPAN>.Fill.Freeze(); <BR><\/FONT><\/FONT><\/FONT><\/SPAN><SPAN><SPAN><FONT size=\"2\" face=\"Consolas\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/FONT><\/SPAN><FONT color=\"#333333\"><FONT face=\"Consolas\"><FONT size=\"2\"><SPAN>this<\/SPAN>.Border.Freeze(); <BR><\/FONT><\/FONT><\/FONT><\/SPAN><FONT face=\"Consolas\"><FONT size=\"2\"><SPAN><SPAN>&nbsp;&nbsp;&nbsp; <\/SPAN>} <BR><\/SPAN><SPAN>}<\/SPAN><\/FONT><\/FONT> <\/P>\n<P class=\"MsoNormal\">And then create a <CODE><FONT face=\"Consolas\">TextMarkerTag<\/FONT><\/CODE> with the name &#8220;mymarker&#8221;, and you are all set. Note that you&#8217;ll probably want some transparency on your fill brush, since the selection is drawn <EM>underneath<\/EM> markers.<\/P>\n<P><A><\/A><\/P>\n<H4>5 \u2013 View tagger provider (<FONT face=\"Consolas\">IViewTaggerProvider<\/FONT>)<\/H4>\n<P>In Beta 1, you exported your taggers with an <CODE><FONT face=\"Consolas\">ITaggerProvider<\/FONT><\/CODE>. In Beta 2, there is an additional interface you can use called <CODE><FONT face=\"Consolas\">IViewTaggerProvider<\/FONT><\/CODE>, which is passed both a buffer and a view in its <FONT face=\"Consolas\"><CODE>CreateTagger<\/CODE> <\/FONT>method. There are a few cases where you may want to use this:<\/P>\n<OL>\n<LI><EM>Your tagger needs information specific to a certain view<\/EM> \u2013 this may be the case if you are writing an extension that wants to, say, highlight all references in a view that match the reference under the caret. In this case, you need to know the caret position in the view to produce your results. <\/LI>\n<LI><EM>Your tagger wants to produce different results depending on the view<\/EM> \u2013 this is basically the same as #1, but it may help to also think of it in this way. With the highlight references example again, it&#8217;s possible to have two different views over the same buffer (split window, for example, or the code definition window), where you want each view to show different results for the highlighted references, even though they are displaying the content of the same text buffer. <\/LI>\n<LI><EM>Your tagger wants to consume other tag information<\/EM> \u2013 this is a more complex case that probably deserves its own blog article. Basically, if you have a tagger for type <CODE><FONT face=\"Consolas\">T<\/FONT><\/CODE> that consumes, say, classification tags, you want to avoid accidentally including a classifier that is trying to consume tags of type <CODE><FONT face=\"Consolas\">T<\/FONT><\/CODE>, or else you&#8217;ll end up with an ugly recursive loop when trying to get tags. You can sidestep this by providing your tagger with an <CODE><FONT face=\"Consolas\">IViewTaggerProvider<\/FONT><\/CODE> and consuming taggers (or classifiers) you get from an <CODE><FONT face=\"Consolas\">IBufferTagAggregatorFactoryService<\/FONT><\/CODE> (or <CODE><FONT face=\"Consolas\">IClassifierAggregatorService.GetClassifier <\/FONT><\/CODE>that takes a buffer). That way, you are guaranteed that any taggers\/classifiers you may consume can&#8217;t accidentally consume your extension as well. <\/LI><\/OL>\n<P>The downside to #3 is that it is still hairy for other components to safely consume your tagger (that they are using via <CODE><FONT face=\"Consolas\">IViewTagAggregatorFactoryService<\/FONT><\/CODE>) to produce tags; if two view-level taggers are each consuming other view-level taggers, you get the same problem as before. As such, any component you make that does this should be created with the understanding that it can&#8217;t be safely consumed. For any extensions you write, you should probably steer clear of creating view-level taggers that consume a view-level <CODE><FONT face=\"Consolas\">ITagAggregator&lt;ClassificationTag&gt;<\/FONT><\/CODE>, for example. In general, it&#8217;s probably safest to follow this rule:<\/P>\n<P><STRONG>Never create a tag aggregator using an <FONT face=\"Consolas\">IViewTagAggregatorFactoryService<\/FONT> inside a tagger provided with an <CODE><FONT face=\"Consolas\">IViewTaggerProvider<\/FONT><\/CODE>.<\/STRONG><\/P>\n<H4>&#8230;and more<\/H4>\n<P>This is not an exhaustive list; these are just the biggest ones I can think of off the top of my head. We\u2019ll continue to post more editor and extensibility content on the <A title=\"The Visual Studio Blog\" href=\"http:\/\/blogs.msdn.com\/visualstudio\">Visual Studio Blog<\/A> and <A title=\"Noah's Blog: Letters from the editor\" href=\"http:\/\/blogs.msdn.com\/noahric\">my blog<\/A>, so stay tuned.&nbsp; And as always, comments are welcome.<\/P>\n<P>&#8211; Noah<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Noah Richards \u2013 Developer, Visual Studio Editor Team Short Bio:&nbsp; Noah has been working on the Visual Studio Editor team since he graduated college two and a half years ago.&nbsp; He maintains a blog, posts sample code for editor extensions, and frequently answers editor-related questions on Twitter. Editor\u2019s Note:&nbsp; This post was originally published on [&hellip;]<\/p>\n","protected":false},"author":13,"featured_media":255385,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[155,1029],"tags":[85,1383,13,20],"class_list":["post-123500","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-visual-studio","category-web","tag-asp-net","tag-c","tag-visual-studio-2010","tag-wpf"],"acf":[],"blog_post_summary":"<p>Noah Richards \u2013 Developer, Visual Studio Editor Team Short Bio:&nbsp; Noah has been working on the Visual Studio Editor team since he graduated college two and a half years ago.&nbsp; He maintains a blog, posts sample code for editor extensions, and frequently answers editor-related questions on Twitter. Editor\u2019s Note:&nbsp; This post was originally published on [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/123500","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/comments?post=123500"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/123500\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media\/255385"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media?parent=123500"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/categories?post=123500"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/tags?post=123500"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}