{"id":250989,"date":"2024-11-04T07:41:35","date_gmt":"2024-11-04T15:41:35","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/visualstudio\/?p=250989"},"modified":"2024-11-04T07:41:35","modified_gmt":"2024-11-04T15:41:35","slug":"the-making-of-bring-back-plus-minus","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/visualstudio\/the-making-of-bring-back-plus-minus\/","title":{"rendered":"The making of Bring Back Plus\/Minus"},"content":{"rendered":"<p>A lesson about the software forensics process involved in developing the\u00a0<a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=MarcoGoertz.BringBackPlusMinus&amp;ssr=false#overview\">Bring Back Plus\/Minus<\/a>\u00a0extension, which brings back the plus\/minus symbols to the editor outlining feature in Visual Studio 2022.<\/p>\n<p>While I did have the advantage of being able to look at the Visual Studio source code, I could have figured this out just as well without it, and that&#8217;s the focus of this article.<\/p>\n<p>The investigation of how to bring back the plus\/minus symbols started with this important clue from a\u00a0<a href=\"https:\/\/developercommunity.visualstudio.com\/t\/Outlining-in-179-uses-ugly-v-for-coll\/10584634#T-N10625097\">comment<\/a>\u00a0on the Developer Community feedback ticket for this issue:<\/p>\n<blockquote><p>However, Visual Studio has a very rich extensibility model, and if users have strong feelings about the visuals in their IDE, I encourage people to try writing an extension to change the icon used here. The class that controls the expansion is this one:\u00a0<strong>OutliningMarginHeaderControl<\/strong><\/p><\/blockquote>\n<p>A quick internet search for the class name led me to this reference article for <a href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/api\/microsoft.visualstudio.text.editor.outliningmarginheadercontrol?view=visualstudiosdk-2022&amp;devlangs=csharp\">OutliningMarginHeaderControl Class<\/a>\u00a0where the definition contains the following valuable information:<\/p>\n<ul>\n<li>Namespace:\u00a0<code>Microsoft.VisualStudio.Text.Editor<\/code><\/li>\n<li>Assembly:\u00a0<code>Microsoft.VisualStudio.Text.UI.Wpf.dll<\/code><\/li>\n<li>Package:\u00a0<code>Microsoft.VisualStudio.Text.UI.Wpf v17.9.187<\/code><\/li>\n<\/ul>\n<p>Now that we know where to find this class, it&#8217;s time to examine the assembly. For that we will use the excellent ILSpy tool, which you can install from the Microsoft Store:\u00a0<a href=\"https:\/\/apps.microsoft.com\/detail\/xp8c26vdwlp4t4?hl=en-US&amp;gl=US\">ILSpy Fresh<\/a><\/p>\n<p>Once you&#8217;ve installed ILSpy, launch it and load the assembly <code>Microsoft.VisualStudio.Text.UI.Wpf.dll<\/code>. You can find this assembly in the Visual Studio installation folder, usually in the following path:<\/p>\n<p><code>&lt;VSInstallDir&gt;\\Common7\\IDE\\CommonExtensions\\Microsoft\\Editor\\Microsoft.VisualStudio.Text.UI.Wpf.dll<\/code><\/p>\n<p>After the assembly is loaded, search for the class\u00a0<code>OutliningMarginHeaderControl<\/code> in the\u00a0<code>Microsoft.VisualStudio.Text.Editor<\/code>\u00a0namespace and you will find the following code for the static constructor:<\/p>\n<p><img decoding=\"async\" width=\"1237\" height=\"624\" class=\"wp-image-251156\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2024\/10\/outliningmarginheadercontrol-in-ilspy.png\" alt=\"OutliningMarginHeaderControl in ILSpy\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2024\/10\/outliningmarginheadercontrol-in-ilspy.png 1237w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2024\/10\/outliningmarginheadercontrol-in-ilspy-300x151.png 300w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2024\/10\/outliningmarginheadercontrol-in-ilspy-1024x517.png 1024w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2024\/10\/outliningmarginheadercontrol-in-ilspy-768x387.png 768w\" sizes=\"(max-width: 1237px) 100vw, 1237px\" \/><\/p>\n<p>This is where the default style key for the control is being set. The next step is to find the XAML <code>Style<\/code>\u00a0for the control. For that we open the\u00a0<code>Resources<\/code> node where we find\u00a0<code>themes\/generic.baml<\/code>, which includes the entire style for the\u00a0<code>OutliningMarginHeaderControl<\/code>:<\/p>\n<p><img decoding=\"async\" width=\"412\" height=\"246\" class=\"wp-image-251157\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2024\/10\/generic-baml-node-in-ilspy.png\" alt=\"generic.baml node in ILSpy\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2024\/10\/generic-baml-node-in-ilspy.png 412w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2024\/10\/generic-baml-node-in-ilspy-300x179.png 300w\" sizes=\"(max-width: 412px) 100vw, 412px\" \/><\/p>\n<pre class=\"prettyprint language-xml\"><code class=\"language-xml\">\r\n&lt;Style x:Key=\"{x:Type textUiWpf:OutliningMarginHeaderControl}\" TargetType=\"{x:Type textUiWpf:OutliningMarginHeaderControl}\"&gt;\r\n    &lt;Style.Resources&gt; \r\n      &lt;ResourceDictionary&gt; \r\n        &lt;Geometry x:Key=\"ExpandRight\"&gt;F1M2.146.146a.5.5,0,0,1,.708,0l4,4a.5.5,0,0,1,0,.708l-4,4a.5.5,0,0,1-.708-.708L5.793,4.5,2.146.854A.5.5,0,0,1,2.146.146Z&lt;\/Geometry&gt; \r\n        &lt;Geometry x:Key=\"ExpandDown\"&gt;F1M8.854,2.146a.5.5,0,0,1,0,.708l-4,4a.5.5,0,0,1-.708,0l-4-4a.5.5,0,0,1,.708-.708L4.5,5.793,8.146,2.146A.5.5,0,0,1,8.854,2.146Z&lt;\/Geometry&gt; \r\n      &lt;\/ResourceDictionary&gt; \r\n    &lt;\/Style.Resources&gt; \r\n    &lt;Setter Property=\"Focusable\" Value=\"False\" \/&gt; \r\n    &lt;Setter Property=\"FrameworkElement.Cursor\" Value=\"Hand\" \/&gt; \r\n    &lt;Setter Property=\"Template\"&gt; \r\n      &lt;Setter.Value&gt; \r\n        &lt;ControlTemplate TargetType=\"{x:Type textUiWpf:OutliningMarginHeaderControl}\"&gt; \r\n          &lt;Grid&gt; \r\n            &lt;Viewbox Name=\"ExpandCollapseIcon\" Width=\"9\" Height=\"13\" VerticalAlignment=\"Center\"&gt; \r\n              &lt;Border Width=\"9\" Height=\"13\" Background=\"{DynamicResource outlining.chevron.background}\"&gt; \r\n                &lt;Rectangle Name=\"ExpandCollapseRectangle\" Width=\"9\" Height=\"9\"&gt; \r\n                  &lt;FrameworkElement.Resources&gt; \r\n                    &lt;ResourceDictionary&gt; \r\n                      &lt;SolidColorBrush x:Key=\"canvas\" Opacity=\"0\" \/&gt; \r\n                    &lt;\/ResourceDictionary&gt; \r\n                  &lt;\/FrameworkElement.Resources&gt; \r\n                  &lt;Shape.Fill&gt; \r\n                    &lt;DrawingBrush Stretch=\"None\"&gt; \r\n                      &lt;DrawingBrush.Drawing&gt; \r\n                        &lt;DrawingGroup&gt; \r\n                          &lt;DrawingGroup&gt; \r\n                            &lt;GeometryDrawing Brush=\"{DynamicResource canvas}\" Geometry=\"F1 M9,0 L9,9 L0,9 L0,0\" \/&gt; \r\n                          &lt;\/DrawingGroup&gt; \r\n                          &lt;DrawingGroup&gt; \r\n                            &lt;GeometryDrawing Brush=\"{DynamicResource outlining.chevron.foreground}\" Geometry=\"{StaticResource ExpandRight}\" \/&gt; \r\n                          &lt;\/DrawingGroup&gt; \r\n                        &lt;\/DrawingGroup&gt; \r\n                      &lt;\/DrawingBrush.Drawing&gt; \r\n                    &lt;\/DrawingBrush&gt; \r\n                  &lt;\/Shape.Fill&gt; \r\n                &lt;\/Rectangle&gt; \r\n              &lt;\/Border&gt; \r\n            &lt;\/Viewbox&gt; \r\n          &lt;\/Grid&gt; \r\n          &lt;ControlTemplate.Triggers&gt; \r\n            &lt;Trigger Property=\"textUiWpf:OutliningMarginHeaderControl.IsExpanded\" Value=\"True\"&gt; \r\n              &lt;Setter TargetName=\"ExpandCollapseRectangle\" Property=\"Shape.Fill\"&gt; \r\n                &lt;Setter.Value&gt; \r\n                  &lt;DrawingBrush Stretch=\"None\"&gt; \r\n                    &lt;DrawingBrush.Drawing&gt; \r\n                      &lt;DrawingGroup&gt; \r\n                        &lt;DrawingGroup&gt; \r\n                          &lt;GeometryDrawing Brush=\"{DynamicResource canvas}\" Geometry=\"F1 M9,0 L9,9 L0,9 L0,0\" \/&gt; \r\n                        &lt;\/DrawingGroup&gt; \r\n                        &lt;DrawingGroup&gt; \r\n                          &lt;GeometryDrawing Brush=\"{DynamicResource outlining.chevron.foreground}\" Geometry=\"{StaticResource ExpandDown}\" \/&gt; \r\n                        &lt;\/DrawingGroup&gt; \r\n                      &lt;\/DrawingGroup&gt; \r\n                    &lt;\/DrawingBrush.Drawing&gt; \r\n                  &lt;\/DrawingBrush&gt; \r\n                &lt;\/Setter.Value&gt; \r\n              &lt;\/Setter&gt; \r\n            &lt;\/Trigger&gt; \r\n          &lt;\/ControlTemplate.Triggers&gt; \r\n        &lt;\/ControlTemplate&gt; \r\n      &lt;\/Setter.Value&gt; \r\n    &lt;\/Setter&gt; \r\n&lt;\/Style&gt; \r\n<\/code><\/pre>\n<p>This is the style for the new chevron symbols. Here we find interesting things like the geometry for the expand\/collapse symbols, the colors, and the trigger that changes the symbol when the control is expanded. The next step is to find the original\u00a0<code>Style<\/code> for the plus\/minus symbols. For that we can either use an older VS installation or we can take advantage of the reference information above, which states that this control is included in the\u00a0<code>Microsoft.VisualStudio.Text.UI.Wpf v17.9.187<\/code>\u00a0NuGet package. Now we know that the symbols changed in 17.9, so we will look for a version before that. For example, the last one before that is\u00a0<a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.VisualStudio.Text.UI.Wpf\/17.8.222\">17.8.222<\/a>.<\/p>\n<p>We can download the package, change its extension from .nupkg to .zip, and extract the assembly from the\u00a0<code>lib\\net472<\/code>\u00a0folder. Once we have the assembly, we can load it in ILSpy and look for the original style for the control just like we did before:<\/p>\n<pre class=\"prettyprint language-xml\"><code class=\"language-xml\">\r\n&lt;Style x:Key=\"{x:Type textUiWpf:OutliningMarginHeaderControl}\" TargetType=\"{x:Type textUiWpf:OutliningMarginHeaderControl}\"&gt;\r\n\t&lt;Setter Property=\"Focusable\" Value=\"False\" \/&gt;\r\n\t&lt;Setter Property=\"Template\"&gt;\r\n\t\t&lt;Setter.Value&gt;\r\n\t\t\t&lt;ControlTemplate TargetType=\"{x:Type textUiWpf:OutliningMarginHeaderControl}\"&gt;\r\n\t\t\t\t&lt;Grid&gt;\r\n\t\t\t\t\t&lt;Border Name=\"WhitePadding\" Height=\"11\" Width=\"9\" BorderBrush=\"{DynamicResource ViewBackgroundBrush}\" Background=\"{DynamicResource ViewBackgroundBrush}\" BorderThickness=\"0,1,0,1\" VerticalAlignment=\"Center\"&gt;\r\n\t\t\t\t\t\t&lt;Border Name=\"TheSquare\" Height=\"9\" Width=\"9\" BorderBrush=\"{DynamicResource outlining.verticalrule.foreground}\" Background=\"{DynamicResource outlining.square.background}\" BorderThickness=\"1\"&gt;\r\n\t\t\t\t\t\t\t&lt;Canvas&gt;\r\n\t\t\t\t\t\t\t\t&lt;Line X1=\"1\" Y1=\"3.5\" X2=\"6\" Y2=\"3.5\" Stroke=\"{DynamicResource outlining.square.foreground}\" \/&gt;\r\n\t\t\t\t\t\t\t\t&lt;Line Name=\"Vertical\" X1=\"3.5\" Y1=\"1\" X2=\"3.5\" Y2=\"6\" Stroke=\"{DynamicResource outlining.square.foreground}\" \/&gt;\r\n\t\t\t\t\t\t\t&lt;\/Canvas&gt;\r\n\t\t\t\t\t\t&lt;\/Border&gt;\r\n\t\t\t\t\t&lt;\/Border&gt;\r\n\t\t\t\t&lt;\/Grid&gt;\r\n\t\t\t\t&lt;ControlTemplate.Triggers&gt;\r\n\t\t\t\t\t&lt;Trigger Property=\"textUiWpf:OutliningMarginHeaderControl.IsExpanded\" Value=\"True\"&gt;\r\n\t\t\t\t\t\t&lt;Setter TargetName=\"Vertical\" Property=\"Visibility\" Value=\"Hidden\" \/&gt;\r\n\t\t\t\t\t\t&lt;Setter TargetName=\"TheSquare\" Value=\"{DynamicResource ViewBackgroundBrush}\" Property=\"Border.Background\" \/&gt;\r\n\t\t\t\t\t&lt;\/Trigger&gt;\r\n\t\t\t\t&lt;\/ControlTemplate.Triggers&gt;\r\n\t\t\t&lt;\/ControlTemplate&gt;\r\n\t\t&lt;\/Setter.Value&gt;\r\n\t&lt;\/Setter&gt;\r\n&lt;\/Style&gt;\r\n<\/code><\/pre>\n<p>Since the new style no longer uses dynamic resources for\u00a0<code>outlining.square<\/code>, we must assume that these resources are no longer available in the new version of VS. This means that we needed to replace these resources with other colors. For the foreground\u00a0<code>outlining.chevron.foreground<\/code>\u00a0made sense. The background was a little bit harder because\u00a0<code>outlining.chevron.background<\/code>\u00a0didn&#8217;t do anything. With a little experimenting I had settled on\u00a0<code>outlining.collapsehintadornment.background<\/code>\u00a0for the first version of the extension. Both were not ideal or what they used to be &#8211; the chevron foreground is quite a bit darker and the background for the plus symbol is a lot lighter than before, but this combination worked in both light and dark themes, and any other existing color resources would look wrong in one theme or another.<\/p>\n<h2>How to build a VSIX extension to override the style<\/h2>\n<p>To override the style, I started by creating a new VSIX project with an async package:<\/p>\n<p><img decoding=\"async\" width=\"550\" height=\"206\" class=\"wp-image-251158\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2024\/10\/new-vsix-project-template.png\" alt=\"New VSIX Project Template\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2024\/10\/new-vsix-project-template.png 550w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2024\/10\/new-vsix-project-template-300x112.png 300w\" sizes=\"(max-width: 550px) 100vw, 550px\" \/><\/p>\n<p>Then I added a new ResourceDictionary file\u00a0<code>Style.xaml<\/code>\u00a0to the project and copied the style from the old assembly, pasted it into the ResourceDictionary, and updated it with the new color resource value. Make sure that the\u00a0<code>Build Action<\/code>\u00a0for this\u00a0<code>Style.xaml<\/code>\u00a0is set to\u00a0<code>Page<\/code>. I also gave this style a key\u00a0<code>x:Key=\"OriginalOutliningMarginHeaderControlStyle\"<\/code>, so that I can easily look it up later:<\/p>\n<pre class=\"prettyprint language-xml\"><code class=\"language-xml\">\r\n&lt;ResourceDictionary\r\n\txmlns=\"http:\/\/schemas.microsoft.com\/winfx\/2006\/xaml\/presentation\"\r\n\txmlns:x=\"http:\/\/schemas.microsoft.com\/winfx\/2006\/xaml\"\r\n\txmlns:textUiWpf=\"clr-namespace:Microsoft.VisualStudio.Text.Editor;assembly=Microsoft.VisualStudio.Text.UI.Wpf\"&gt;\r\n\t&lt;Style x:Key=\"OriginalOutliningMarginHeaderControlStyle\" TargetType=\"textUiWpf:OutliningMarginHeaderControl\"&gt;\r\n\t\t...\r\n<\/code><\/pre>\n<p>The last thing that needed to be done was to override the style in the <code>InitializeAsync<\/code> method of the package. The following code loads the resource dictionary, looks up the style by its key, and places it in the current application&#8217;s resources using the implicit style key\u00a0<code>typeof(OutliningMarginHeaderControl)<\/code>, so that Visual Studio will find this Style first:<\/p>\n<pre class=\"prettyprint language-csharp\"><code class=\"language-csharp\">\r\nprotected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) \r\n{ \r\n\t\/\/ When initialized asynchronously, the current thread may be a background thread at this point. \r\n\t\/\/ Do any initialization that requires the UI thread after switching to the UI thread. \r\n\tawait this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); \r\n\tvar resourceDictionary = new ResourceDictionary(); \r\n\tresourceDictionary.Source = new Uri(\"pack:\/\/application:,,,\/BringBackPlusMinus;component\/Style.xaml\"); \r\n\tvar style = resourceDictionary[\"OriginalOutliningMarginHeaderControlStyle\"]; \r\n\tApplication.Current.Resources[typeof(OutliningMarginHeaderControl)] = style; \r\n}\r\n<\/code><\/pre>\n<p>Building and running the project launched the experimental instance of Visual Studio and voila &#8211; the plus\/minus symbols were back!<\/p>\n<p>Now all that was left to do was to update the vsixmanifest, build the extension in\u00a0Release\u00a0mode, and upload it to the\u00a0<a href=\"https:\/\/marketplace.visualstudio.com\/\">Visual Studio Marketplace<\/a>\u00a0following this\u00a0<a href=\"https:\/\/learn.microsoft.com\/en-us\/visualstudio\/extensibility\/walkthrough-publishing-a-visual-studio-extension?view=vs-2022\">Walkthrough: Publish a Visual Studio extension<\/a>.<\/p>\n<h2>Adding support for color customization<\/h2>\n<p>When I started using the preview builds of Visual Studio 2022 17.12, I noticed that the rendering of the plus\/minus symbols was broken because the chevron symbol color definition had changed. I decided to introduce a dedicated color definition for the plus\/minus symbols to avoid such problems going forward:<\/p>\n<pre class=\"prettyprint language-csharp\"><code class=\"language-csharp\">\r\n[Export(typeof(EditorFormatDefinition))] \r\n[Name(OutliningExpanderIdentifier)] \r\n[UserVisible(true)] \r\ninternal sealed class OutliningExpanderFormatDefinition : EditorFormatDefinition \r\n{ \r\n\tpublic const string OutliningExpanderIdentifier = \"outlining.plusminus\"; \r\n\tpublic OutliningExpanderFormatDefinition() \r\n\t{ \r\n\t\tthis.ForegroundColor = Color.FromRgb(0x55, 0x55, 0x55); \r\n\t\tthis.BackgroundColor = Color.FromRgb(0xE2, 0xE2, 0xE2); \r\n\t\tthis.DisplayName = Strings.OutliningMarginPlusMinus; \r\n\t} \r\n}\r\n<\/code><\/pre>\n<p>As an added benefit the colors are now consistent with the original plus\/minus symbols, and they can be customized in\u00a0<strong>Tools -&gt; Options -&gt; Environment -&gt; Fonts and Colors<\/strong>:<\/p>\n<p><img decoding=\"async\" width=\"740\" height=\"431\" class=\"wp-image-251159\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2024\/10\/plus-minus-symbol-colors-in-tools-options-dialog.png\" alt=\"Plus\/minus symbol colors in Tools\/Options dialog\" srcset=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2024\/10\/plus-minus-symbol-colors-in-tools-options-dialog.png 740w, https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2024\/10\/plus-minus-symbol-colors-in-tools-options-dialog-300x175.png 300w\" sizes=\"(max-width: 740px) 100vw, 740px\" \/><\/p>\n<p>To make sure that the colors look correct in the dark theme as well, I added a <code>ThemeColors.xml<\/code> file to the project with the following content:<\/p>\n<pre class=\"prettyprint language-xml\"><code class=\"language-xml\">\r\n&lt;Themes&gt; \r\n\t&lt;Theme Name=\"Dark\" GUID=\"{1ded0138-47ce-435e-84ef-9ec1f439b749}\"&gt; \r\n\t\t&lt;Category Name=\"BringBackPlusMinus\" GUID=\"{063E9575-C1A8-4729-BB15-AAA2EFB44FC0}\"&gt; \r\n\t\t\t&lt;Color Name=\"outlining.plusminus\"&gt; \r\n\t\t\t\t&lt;Background Type=\"CT_RAW\" Source=\"FF000000\" \/&gt; \r\n\t\t\t\t&lt;Foreground Type=\"CT_RAW\" Source=\"FFE2E2E2\" \/&gt; \r\n\t\t\t&lt;\/Color&gt; \r\n\t\t&lt;\/Category&gt; \r\n\t&lt;\/Theme&gt; \r\n&lt;\/Themes&gt;\r\n<\/code><\/pre>\n<p>It needs to be converted to a .pkgdef file using the\u00a0<a href=\"https:\/\/learn.microsoft.com\/en-us\/visualstudio\/extensibility\/internals\/vsix-color-compiler\">VsixColorCompiler<\/a>\u00a0first, which is then included in the extension&#8217;s .vsixmanifest.<\/p>\n<h2>Conclusion<\/h2>\n<p>In summary, with a little bit of detective work we were able to locate the style for the outlining symbols, build a VSIX extension, and override the style with the original style that brings back the original plus\/minus outlining buttons.<\/p>\n<p>The source code for the extension is available on\u00a0<a href=\"https:\/\/github.com\/mgoertz-msft\/BringBackPlusMinus\">GitHub<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A lesson about the software forensics process involved in developing the\u00a0Bring Back Plus\/Minus\u00a0extension, which brings back the plus\/minus symbols to the editor outlining feature in Visual Studio 2022. While I did have the advantage of being able to look at the Visual Studio source code, I could have figured this out just as well without [&hellip;]<\/p>\n","protected":false},"author":118046,"featured_media":251030,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1388,155],"tags":[294,1539,6927],"class_list":["post-250989","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-extensibility","category-visual-studio","tag-extensions","tag-feedback","tag-story"],"acf":[],"blog_post_summary":"<p>A lesson about the software forensics process involved in developing the\u00a0Bring Back Plus\/Minus\u00a0extension, which brings back the plus\/minus symbols to the editor outlining feature in Visual Studio 2022. While I did have the advantage of being able to look at the Visual Studio source code, I could have figured this out just as well without [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/250989","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\/118046"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/comments?post=250989"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/250989\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media\/251030"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media?parent=250989"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/categories?post=250989"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/tags?post=250989"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}