├── images
├── ContextMenu.png
├── CommandWindow.png
├── FontsAndColors.png
├── EditorGuidelines_90px.png
└── EditorGuidelines_128px.png
├── src
├── ColumnGuidePackage
│ ├── Resources
│ │ ├── Package.ico
│ │ └── Images_32bit.png
│ ├── packages.config
│ ├── PkgCmdID.cs
│ ├── app.config
│ ├── Guids.cs
│ ├── GlobalSuppressions.cs
│ ├── Telemetry.cs
│ ├── TextEditorGuidesSettingsRendezvous.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── VSPackage.resx
│ ├── ColumnGuidePackage.vsct
│ ├── ColumnGuidePackage.csproj
│ └── ColumnGuidePackage.cs
├── References
│ └── 11.0.0.0
│ │ ├── Microsoft.VisualStudio.Editor.dll
│ │ ├── Microsoft.VisualStudio.Text.UI.dll
│ │ ├── Microsoft.VisualStudio.CoreUtility.dll
│ │ ├── Microsoft.VisualStudio.Shell.11.0.dll
│ │ ├── Microsoft.VisualStudio.Text.Data.dll
│ │ ├── Microsoft.VisualStudio.Text.UI.Wpf.dll
│ │ └── Microsoft.VisualStudio.ComponentModelHost.dll
├── ColumnGuide
│ ├── packages.config
│ ├── ITextEditorGuidesSettings.cs
│ ├── ITelemetry.cs
│ ├── ITextEditorGuidesSettingsChanger.cs
│ ├── GuidelineColorDefinition.cs
│ ├── HostServices.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Telemetry.cs
│ ├── ColumnGuide.ruleset
│ ├── ColumnGuideFactory.cs
│ ├── ColumnGuide.cs
│ ├── ColumnGuide.csproj
│ └── TextEditorGuidesSettings.cs
├── VSIX
│ ├── app.config
│ ├── ReleaseNotes.txt
│ ├── source.extension.vsixmanifest
│ └── Editor Guidelines.csproj
└── Editor Guidelines.sln
├── LICENSE
├── README.md
└── .gitignore
/images/ContextMenu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/EditorGuidelines/master/images/ContextMenu.png
--------------------------------------------------------------------------------
/images/CommandWindow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/EditorGuidelines/master/images/CommandWindow.png
--------------------------------------------------------------------------------
/images/FontsAndColors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/EditorGuidelines/master/images/FontsAndColors.png
--------------------------------------------------------------------------------
/images/EditorGuidelines_90px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/EditorGuidelines/master/images/EditorGuidelines_90px.png
--------------------------------------------------------------------------------
/images/EditorGuidelines_128px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/EditorGuidelines/master/images/EditorGuidelines_128px.png
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/Resources/Package.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/EditorGuidelines/master/src/ColumnGuidePackage/Resources/Package.ico
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/Resources/Images_32bit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/EditorGuidelines/master/src/ColumnGuidePackage/Resources/Images_32bit.png
--------------------------------------------------------------------------------
/src/References/11.0.0.0/Microsoft.VisualStudio.Editor.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/EditorGuidelines/master/src/References/11.0.0.0/Microsoft.VisualStudio.Editor.dll
--------------------------------------------------------------------------------
/src/References/11.0.0.0/Microsoft.VisualStudio.Text.UI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/EditorGuidelines/master/src/References/11.0.0.0/Microsoft.VisualStudio.Text.UI.dll
--------------------------------------------------------------------------------
/src/ColumnGuide/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/References/11.0.0.0/Microsoft.VisualStudio.CoreUtility.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/EditorGuidelines/master/src/References/11.0.0.0/Microsoft.VisualStudio.CoreUtility.dll
--------------------------------------------------------------------------------
/src/References/11.0.0.0/Microsoft.VisualStudio.Shell.11.0.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/EditorGuidelines/master/src/References/11.0.0.0/Microsoft.VisualStudio.Shell.11.0.dll
--------------------------------------------------------------------------------
/src/References/11.0.0.0/Microsoft.VisualStudio.Text.Data.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/EditorGuidelines/master/src/References/11.0.0.0/Microsoft.VisualStudio.Text.Data.dll
--------------------------------------------------------------------------------
/src/References/11.0.0.0/Microsoft.VisualStudio.Text.UI.Wpf.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/EditorGuidelines/master/src/References/11.0.0.0/Microsoft.VisualStudio.Text.UI.Wpf.dll
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/References/11.0.0.0/Microsoft.VisualStudio.ComponentModelHost.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/madskristensen/EditorGuidelines/master/src/References/11.0.0.0/Microsoft.VisualStudio.ComponentModelHost.dll
--------------------------------------------------------------------------------
/src/ColumnGuide/ITextEditorGuidesSettings.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace ColumnGuide
4 | {
5 | interface ITextEditorGuidesSettings
6 | {
7 | IEnumerable GuideLinePositionsInChars { get; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/PkgCmdID.cs:
--------------------------------------------------------------------------------
1 | // PkgCmdID.cs
2 | // MUST match PkgCmdID.h
3 | using System;
4 |
5 | namespace Microsoft.ColumnGuidePackage
6 | {
7 | enum PkgCmdIDList
8 | {
9 | cmdidAddColumnGuideline = 0x100,
10 | cmdidRemoveColumnGuideline = 0x101,
11 | cmdidRemoveAllColumnGuidelines = 0x103
12 | };
13 | }
--------------------------------------------------------------------------------
/src/ColumnGuide/ITelemetry.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.ApplicationInsights;
2 |
3 | namespace ColumnGuide
4 | {
5 | public interface ITelemetry
6 | {
7 | ///
8 | /// Access the Application Insights telemetry client shared between both components.
9 | ///
10 | TelemetryClient Client { get; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/ColumnGuide/ITextEditorGuidesSettingsChanger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ColumnGuide
4 | {
5 | public interface ITextEditorGuidesSettingsChanger
6 | {
7 | bool AddGuideline(int column);
8 | bool RemoveGuideline(int column);
9 | bool CanAddGuideline(int column);
10 | bool CanRemoveGuideline(int column);
11 | void RemoveAllGuidelines();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/VSIX/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/Guids.cs:
--------------------------------------------------------------------------------
1 | // Guids.cs
2 | // MUST match guids.h
3 | using System;
4 |
5 | namespace Microsoft.ColumnGuidePackage
6 | {
7 | static class GuidList
8 | {
9 | public const string guidColumnGuidePkgString = "a0b80b01-be16-4c42-ab44-7f8d057faa2f";
10 | public const string guidColumnGuideCmdSetString = "5aa4cf31-6030-4655-99e7-239b331103f3";
11 |
12 | public static readonly Guid guidColumnGuideCmdSet = new Guid(guidColumnGuideCmdSetString);
13 | };
14 | }
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/GlobalSuppressions.cs:
--------------------------------------------------------------------------------
1 | // This file is used by Code Analysis to maintain SuppressMessage
2 | // attributes that are applied to this project. Project-level
3 | // suppressions either have no target or are given a specific target
4 | // and scoped to a namespace, type, member, etc.
5 | //
6 | // To add a suppression to this file, right-click the message in the
7 | // Error List, point to "Suppress Message(s)", and click "In Project
8 | // Suppression File". You do not need to add suppressions to this
9 | // file manually.
10 |
11 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")]
12 |
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/Telemetry.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.ApplicationInsights;
2 | using Microsoft.VisualStudio.ComponentModelHost;
3 | using Microsoft.VisualStudio.Shell;
4 | using ColumnGuide;
5 |
6 | namespace Microsoft.ColumnGuidePackage
7 | {
8 | internal static class Telemetry
9 | {
10 | public static readonly TelemetryClient Client = ImportClient();
11 |
12 | private static TelemetryClient ImportClient()
13 | {
14 | IComponentModel componentModel = (IComponentModel)Package.GetGlobalService(typeof(SComponentModel));
15 | var telemetry = componentModel.GetService();
16 | return telemetry.Client;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/ColumnGuide/GuidelineColorDefinition.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.Text.Classification;
2 | using Microsoft.VisualStudio.Utilities;
3 | using System.ComponentModel.Composition;
4 | using System.Windows.Media;
5 |
6 | namespace ColumnGuide
7 | {
8 | [Export(typeof(EditorFormatDefinition)), UserVisible(true), Name(GuidelineColorDefinition.Name)]
9 | public class GuidelineColorDefinition : EditorFormatDefinition
10 | {
11 | internal const string Name = "Guideline";
12 |
13 | public GuidelineColorDefinition()
14 | {
15 | this.DisplayName = "Guideline";
16 | this.ForegroundCustomizable = false;
17 | this.BackgroundColor = Colors.DarkRed;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/TextEditorGuidesSettingsRendezvous.cs:
--------------------------------------------------------------------------------
1 | using ColumnGuide;
2 | using Microsoft.VisualStudio.ComponentModelHost;
3 | using Microsoft.VisualStudio.Shell;
4 |
5 | namespace Microsoft.ColumnGuidePackage
6 | {
7 | static class TextEditorGuidesSettingsRendezvous
8 | {
9 | private static ITextEditorGuidesSettingsChanger _instance;
10 | public static ITextEditorGuidesSettingsChanger Instance
11 | {
12 | get
13 | {
14 | if (_instance == null)
15 | {
16 | IComponentModel componentModel = (IComponentModel)Package.GetGlobalService(typeof(SComponentModel));
17 | _instance = componentModel.GetService();
18 | }
19 |
20 | return _instance;
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/ColumnGuide/HostServices.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel.Composition;
3 | using Microsoft.VisualStudio.Shell;
4 | using Microsoft.VisualStudio.Shell.Interop;
5 |
6 | namespace ColumnGuide
7 | {
8 | [Export]
9 | sealed class HostServices
10 | {
11 | [Import(typeof(SVsServiceProvider))]
12 | IServiceProvider ServiceProvider
13 | {
14 | get;
15 | set;
16 | }
17 |
18 | public T GetService(Type serviceType) where T : class
19 | {
20 | return ServiceProvider.GetService(serviceType) as T;
21 | }
22 |
23 | // Add services here
24 |
25 | public IVsSettingsManager SettingsManagerService
26 | {
27 | get
28 | {
29 | return GetService(typeof(SVsSettingsManager));
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/VSIX/ReleaseNotes.txt:
--------------------------------------------------------------------------------
1 | Editor Guidelines
Version 2.0.3 (December 26th 2017)
1. Updated icon with one from the PPT artwork team.
Version 2.0.2 (December 24th 2017)
1. Update icon again.
Version 2.0.1 (December 24th 2017)
1. Update icon (with permission from PPT team).
Version 2.0.0 (December 23rd 2017)
1. Changed to MIT license.
2. Open sourced on https://github.com/pharring/EditorGuidelines
Version 1.15.61202.0 (December 2nd 2016)
1. Thinned out telemetry events.
Version 1.15.61129.0 (November 29th 2016)
1. Moved color selection into 'Fonts and Colors' section in Tools/Options.
Version 1.15.61103.1 (November 3rd 2016)
1. Added usage telemetry
Version 1.15.61102.0 (November 2nd 2016)
1. Updated to support VS "15" RC
2. Updated copyright year to 2016
Version 1.11.70722.0 (July 22nd 2015)
1. Fixed a bug where the guideline menu was missing from context menu in HTML files in VS 2013.
2. Added "Remove All Guidelines" command.
3. "Edit.AddGuideline" and "Edit.RemoveGuideline" can now take a parameter when invoked from the command window indicating which column to add or remove.
4. Updated description to indicate that VS 2015 is supported.
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Paul Harrington
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using System.Resources;
4 | using System.Runtime.CompilerServices;
5 | using System.Runtime.InteropServices;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("Editor Guidelines UI Package")]
11 | [assembly: AssemblyDescription("Adds commands for the Editor Guidelines extension")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("Paul Harrington")]
14 | [assembly: AssemblyProduct("ColumnGuidePackage")]
15 | [assembly: AssemblyCopyright("Copyright © 2017 Paul Harrington")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 | [assembly: ComVisible(false)]
19 | [assembly: CLSCompliant(false)]
20 | [assembly: NeutralResourcesLanguage("en-US")]
21 |
22 | // Version information for an assembly consists of the following four values:
23 | //
24 | // Major Version
25 | // Minor Version
26 | // Build Number
27 | // Revision
28 | //
29 | // You can specify all the values or you can default the Revision and Build Numbers
30 | // by using the '*' as shown below:
31 |
32 | [assembly: AssemblyVersion("2.0.3")]
33 | [assembly: AssemblyFileVersion("2.0.3")]
34 |
--------------------------------------------------------------------------------
/src/ColumnGuide/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("ColumnGuide")]
9 | [assembly: AssemblyDescription("Editor Guidelines Extension")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Paul Harrington")]
12 | [assembly: AssemblyProduct("ColumnGuide")]
13 | [assembly: AssemblyCopyright("Copyright © 2017 Paul Harrington")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // Version information for an assembly consists of the following four values:
23 | //
24 | // Major Version
25 | // Minor Version
26 | // Build Number
27 | // Revision
28 | //
29 | // You can specify all the values or you can default the Build and Revision Numbers
30 | // by using the '*' as shown below:
31 | // [assembly: AssemblyVersion("1.0.*")]
32 | [assembly: AssemblyVersion("2.0.3")]
33 | [assembly: AssemblyFileVersion("2.0.3")]
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Editor Guidelines
2 | A Visual Studio extension that adds vertical column guides to the text editor.
3 |
4 | The extension adds vertical column guides behind your code. This is useful if you are trying to tabulate columns of data or if you want to ensure that your lines don't extend beyond a certain length. You specify where the guides go and what color they should be.
5 |
6 | ## Getting Started
7 | [Download](https://marketplace.visualstudio.com/items?itemName=PaulHarrington.EditorGuidelines) and run the extension (VSIX) for Visual Studio 2012 or later from the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=PaulHarrington.EditorGuidelines) or, from within Visual Studio, search for "Editor Guidelines" in the "Extensions and Updates" UI.
8 |
9 | Control guidelines via the context (right-click) menu on the editor surface. You will see a *Guidelines* flyout with three commands:
10 |
11 | 
12 |
13 | * When *Add Guideline* is selected, a vertical dashed line will be drawn at the same position as the caret (insertion point).
14 | * *Remove Guideline* will remove any guideline at the current insertion point.
15 | * *Remove All Guidelines* does exactly that.
16 |
17 | You can change the guideline color from the Fonts and Colors page in `Tools|Options`. Look for *Guideline* in the Text Editor category:
18 |
19 | 
20 |
21 | These commands may also be accessed from Visual Studio's Command Window.
22 |
23 | 
24 |
25 | Note that the column numbers used for the `Edit.AddGuideline` and `Edit.RemoveGuideline` commands refer to the right side of the given column of text.
26 | i.e. To place a guide to the right of column 80, use `Edit.AddGuideline 80`. To place a guide to the left of the first column use `Edit.AddGuideline 0`.
27 |
28 | _Note: This extension collects and transmits anonymized usage statistics to the extension author for product improvement purposes._
29 |
--------------------------------------------------------------------------------
/src/ColumnGuide/Telemetry.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.ApplicationInsights;
2 | using Microsoft.ApplicationInsights.Channel;
3 | using Microsoft.ApplicationInsights.Extensibility;
4 | using System;
5 | using System.ComponentModel.Composition;
6 |
7 | namespace ColumnGuide
8 | {
9 | [Export(typeof(ITelemetry))]
10 | internal class Telemetry : ITelemetry
11 | {
12 | private const string c_InstrumentationKey = "f8324fcc-eb39-4931-bebc-968aab7d3d7d";
13 |
14 | private readonly TelemetryClient _telemetryClient = CreateClient();
15 |
16 | public TelemetryClient Client => _telemetryClient;
17 |
18 | private Telemetry()
19 | {
20 | }
21 |
22 | private static TelemetryClient CreateClient()
23 | {
24 | var configuration = new TelemetryConfiguration
25 | {
26 | InstrumentationKey = c_InstrumentationKey,
27 | TelemetryChannel = new InMemoryChannel
28 | {
29 | #if DEBUG
30 | DeveloperMode = true
31 | #else
32 | DeveloperMode = false
33 | #endif
34 | }
35 | };
36 |
37 | var client = new TelemetryClient(configuration);
38 | client.Context.User.Id = Anonymize(Environment.UserDomainName + "\\" + Environment.UserName);
39 | client.Context.Session.Id = Guid.NewGuid().ToString();
40 | client.Context.Device.OperatingSystem = Environment.OSVersion.ToString();
41 | client.Context.Component.Version = typeof(Telemetry).Assembly.GetName().Version.ToString();
42 |
43 | return client;
44 | }
45 |
46 | private static string Anonymize(string str)
47 | {
48 | using (var sha1 = System.Security.Cryptography.SHA1.Create())
49 | {
50 | byte[] inputBytes = System.Text.Encoding.Unicode.GetBytes(str);
51 | byte[] hash = sha1.ComputeHash(inputBytes);
52 | string base64 = System.Convert.ToBase64String(hash);
53 | return base64;
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/VSIX/source.extension.vsixmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Editor Guidelines
6 | Adds vertical column guides to the Visual Studio text editor.
7 | https://marketplace.visualstudio.com/items?itemName=PaulHarrington.EditorGuidelines
8 | LICENSE
9 | https://github.com/pharring/EditorGuidelines#getting-started
10 | ReleaseNotes.txt
11 | EditorGuidelines_128px.png
12 | Editor;Editing;Guidelines;Column
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/Editor Guidelines.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.25901.2
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColumnGuide", "ColumnGuide\ColumnGuide.csproj", "{0C5B092D-506C-4F92-9902-205874908ACC}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColumnGuidePackage", "ColumnGuidePackage\ColumnGuidePackage.csproj", "{B2BA96C9-1020-4D3E-9E4F-9D2525FD4DC3}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Editor Guidelines", "VSIX\Editor Guidelines.csproj", "{BD32086D-4DD4-43E4-B1DF-69DA079DA88C}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {0C5B092D-506C-4F92-9902-205874908ACC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {0C5B092D-506C-4F92-9902-205874908ACC}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {0C5B092D-506C-4F92-9902-205874908ACC}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {0C5B092D-506C-4F92-9902-205874908ACC}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {B2BA96C9-1020-4D3E-9E4F-9D2525FD4DC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {B2BA96C9-1020-4D3E-9E4F-9D2525FD4DC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {B2BA96C9-1020-4D3E-9E4F-9D2525FD4DC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {B2BA96C9-1020-4D3E-9E4F-9D2525FD4DC3}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {BD32086D-4DD4-43E4-B1DF-69DA079DA88C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {BD32086D-4DD4-43E4-B1DF-69DA079DA88C}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {BD32086D-4DD4-43E4-B1DF-69DA079DA88C}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {BD32086D-4DD4-43E4-B1DF-69DA079DA88C}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {64E283A2-5918-46A4-9D2B-83B601BBEBBD}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Microsoft.ColumnGuidePackage {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.ColumnGuidePackage.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/ColumnGuide/ColumnGuide.ruleset:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/src/ColumnGuide/ColumnGuideFactory.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.Composition;
2 | using Microsoft.VisualStudio.Text.Editor;
3 | using Microsoft.VisualStudio.Utilities;
4 | using Microsoft.VisualStudio.Text.Classification;
5 | using System.Collections.Generic;
6 | using System.Windows.Media;
7 | using System.ComponentModel;
8 | using System.Globalization;
9 |
10 | namespace ColumnGuide
11 | {
12 | #region Adornment Factory
13 | ///
14 | /// Establishes an to place the adornment on and exports the
15 | /// that instantiates the adornment on the event of a 's creation
16 | ///
17 | [Export(typeof(IWpfTextViewCreationListener))]
18 | [ContentType("text")]
19 | [TextViewRole(PredefinedTextViewRoles.Document)]
20 | internal sealed class ColumnGuideAdornmentFactory : IWpfTextViewCreationListener, IPartImportsSatisfiedNotification
21 | {
22 | ///
23 | /// Defines the adornment layer for the adornment. This layer is ordered
24 | /// below the text in the Z-order
25 | ///
26 | [Export(typeof(AdornmentLayerDefinition))]
27 | [Name("ColumnGuide")]
28 | [Order(Before = PredefinedAdornmentLayers.Text)]
29 | [TextViewRole(PredefinedTextViewRoles.Document)]
30 | public AdornmentLayerDefinition editorAdornmentLayer = null;
31 |
32 | ///
33 | /// Instantiates a ColumnGuide manager when a textView is created.
34 | ///
35 | /// The upon which the adornment should be placed
36 | public void TextViewCreated(IWpfTextView textView)
37 | {
38 | // Always create the adornment, even if there are no guidelines, since we
39 | // respond to dynamic changes.
40 | var formatMap = EditorFormatMapService.GetEditorFormatMap(textView);
41 | new ColumnGuide(textView, TextEditorGuidesSettings, formatMap, Telemetry);
42 |
43 | // To reduce the amount of telemetry, only report the color for the first instance.
44 | if (!_colorReported)
45 | {
46 | _colorReported = true;
47 | var brush = GetGuidelineBrushFromFontsAndColors(formatMap);
48 | if (brush != null)
49 | {
50 | Telemetry.Client.TrackEvent("CreateGuidelines", new Dictionary { ["Color"] = brush.ToString() });
51 | }
52 | }
53 | }
54 |
55 | public void OnImportsSatisfied()
56 | {
57 | Telemetry.Client.TrackEvent(nameof(ColumnGuideAdornmentFactory) + " initialized");
58 |
59 | TrackSettings("CreateGuidelines");
60 | if (TextEditorGuidesSettings is INotifyPropertyChanged settingsChanged)
61 | {
62 | settingsChanged.PropertyChanged += OnSettingsChanged;
63 | }
64 | }
65 |
66 | private void OnSettingsChanged(object sender, PropertyChangedEventArgs e)
67 | {
68 | if (e.PropertyName == nameof(ITextEditorGuidesSettings.GuideLinePositionsInChars))
69 | {
70 | TrackSettings("SettingsChanged");
71 | }
72 | }
73 |
74 | private void TrackSettings(string eventName)
75 | {
76 | var telemetryProperties = new Dictionary();
77 | foreach (var column in TextEditorGuidesSettings.GuideLinePositionsInChars)
78 | {
79 | telemetryProperties.Add("guide" + telemetryProperties.Count.ToString(CultureInfo.InvariantCulture), column.ToString(CultureInfo.InvariantCulture));
80 | }
81 |
82 | Telemetry.Client.TrackEvent(eventName, telemetryProperties, new Dictionary { ["Count"] = telemetryProperties.Count });
83 | }
84 |
85 | internal static Brush GetGuidelineBrushFromFontsAndColors(IEditorFormatMap formatMap)
86 | {
87 | var resourceDictionary = formatMap.GetProperties(GuidelineColorDefinition.Name);
88 | if (resourceDictionary.Contains(EditorFormatDefinition.BackgroundBrushId))
89 | {
90 | return resourceDictionary[EditorFormatDefinition.BackgroundBrushId] as Brush;
91 | }
92 |
93 | return null;
94 | }
95 |
96 | [Import]
97 | private ITextEditorGuidesSettings TextEditorGuidesSettings { get; set; }
98 |
99 | [Import]
100 | private ITelemetry Telemetry { get; set; }
101 |
102 | [Import]
103 | private IEditorFormatMapService EditorFormatMapService { get; set; }
104 |
105 | private bool _colorReported;
106 | }
107 | #endregion //Adornment Factory
108 | }
109 |
--------------------------------------------------------------------------------
/src/VSIX/Editor Guidelines.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 15.0
5 | 11.0
6 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
7 | 4.0
8 |
9 |
10 |
11 | Debug
12 | AnyCPU
13 | 2.0
14 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
15 | {BD32086D-4DD4-43E4-B1DF-69DA079DA88C}
16 | Library
17 | Properties
18 | Editor_Guidelines
19 | EditorGuidelines
20 | v4.5
21 | false
22 | false
23 | false
24 | false
25 | false
26 | false
27 |
28 |
29 | true
30 | full
31 | false
32 | bin\Debug\
33 | DEBUG;TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 | pdbonly
40 | true
41 | bin\Release\
42 | TRACE
43 | prompt
44 | 4
45 |
46 |
47 |
48 |
49 |
50 | EditorGuidelines_128px.png
51 | Always
52 | true
53 |
54 |
55 | LICENSE
56 | Always
57 | true
58 |
59 |
60 | Designer
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | Always
69 | true
70 |
71 |
72 |
73 |
74 | {B2BA96C9-1020-4D3E-9E4F-9D2525FD4DC3}
75 | ColumnGuidePackage
76 | BuiltProjectOutputGroup%3bBuiltProjectOutputGroupDependencies%3bGetCopyToOutputDirectoryItems%3bSatelliteDllsProjectOutputGroup%3bPkgdefProjectOutputGroup%3b
77 | DebugSymbolsProjectOutputGroup%3b
78 |
79 |
80 | {0C5B092D-506C-4F92-9902-205874908ACC}
81 | ColumnGuide
82 | BuiltProjectOutputGroup%3bBuiltProjectOutputGroupDependencies%3bGetCopyToOutputDirectoryItems%3bSatelliteDllsProjectOutputGroup%3b
83 | DebugSymbolsProjectOutputGroup%3b
84 |
85 |
86 |
87 |
88 |
95 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 |
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 | text/microsoft-resx
119 |
120 |
121 | 2.0
122 |
123 |
124 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
125 |
126 |
127 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
128 |
129 |
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/VSPackage.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Editor Guidelines Package
122 |
123 |
124 | Adds and handles context menu commands for the Editor Guidelines editor extension.
125 |
126 |
127 |
128 | Resources\Package.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
129 |
130 |
--------------------------------------------------------------------------------
/src/ColumnGuide/ColumnGuide.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Windows;
4 | using System.Windows.Media;
5 | using System.Windows.Shapes;
6 | using Microsoft.VisualStudio.Text.Editor;
7 | using Microsoft.VisualStudio.Text.Formatting;
8 | using System.ComponentModel;
9 | using Microsoft.VisualStudio.Text.Classification;
10 |
11 | namespace ColumnGuide
12 | {
13 | ///
14 | /// Adornment class that draws vertical guide lines beneath the text
15 | ///
16 | class ColumnGuide
17 | {
18 | private const double _lineThickness = 1.0;
19 |
20 | private IList _guidelines;
21 | private IWpfTextView _view;
22 | private bool _firstLayoutDone;
23 | private double _baseIndentation;
24 | private double _columnWidth;
25 | private INotifyPropertyChanged _settingsChanged;
26 | private IEditorFormatMap _formatMap;
27 | private ITelemetry _telemetry;
28 | private Brush _guidelineBrush;
29 |
30 | ///
31 | /// Creates editor column guidelines
32 | ///
33 | /// The upon which the adornment will be drawn
34 | /// The guideline settings.
35 | /// The editor format map used to discover formatting options (guideline color).
36 | public ColumnGuide(IWpfTextView view, ITextEditorGuidesSettings settings, IEditorFormatMap editorFormatMap, ITelemetry telemetry)
37 | {
38 | _view = view;
39 | _formatMap = editorFormatMap;
40 | _telemetry = telemetry;
41 |
42 | InitializeGuidelines(settings);
43 |
44 | _view.LayoutChanged += OnViewLayoutChanged;
45 | _settingsChanged = settings as INotifyPropertyChanged;
46 | if (_settingsChanged != null)
47 | {
48 | _settingsChanged.PropertyChanged += SettingsChanged;
49 | }
50 |
51 | _formatMap.FormatMappingChanged += FormatMappingChanged;
52 | _view.Closed += ViewClosed;
53 | }
54 |
55 | private void FormatMappingChanged(object sender, FormatItemsEventArgs e)
56 | {
57 | GuidelineBrush = GetGuidelineBrushFromFontsAndColors();
58 | }
59 |
60 | void ViewClosed(object sender, EventArgs e)
61 | {
62 | _view.LayoutChanged -= OnViewLayoutChanged;
63 | _view.Closed -= ViewClosed;
64 | if (_settingsChanged != null)
65 | {
66 | _settingsChanged.PropertyChanged -= SettingsChanged;
67 | _settingsChanged = null;
68 | }
69 |
70 | if (_formatMap != null)
71 | {
72 | _formatMap.FormatMappingChanged -= FormatMappingChanged;
73 | _formatMap = null;
74 | }
75 | }
76 |
77 | private void InitializeGuidelines(ITextEditorGuidesSettings settings)
78 | {
79 | _guidelines = CreateGuidelines(settings);
80 | }
81 |
82 | void SettingsChanged(object sender, PropertyChangedEventArgs e)
83 | {
84 | ITextEditorGuidesSettings settings = sender as ITextEditorGuidesSettings;
85 | if (settings != null && e.PropertyName == nameof(ITextEditorGuidesSettings.GuideLinePositionsInChars))
86 | {
87 | InitializeGuidelines(settings);
88 | UpdatePositions();
89 | AddGuidelinesToAdornmentLayer();
90 | }
91 | }
92 |
93 | private Brush GetGuidelineBrushFromFontsAndColors()
94 | {
95 | return ColumnGuideAdornmentFactory.GetGuidelineBrushFromFontsAndColors(_formatMap);
96 | }
97 |
98 | private Brush GuidelineBrush
99 | {
100 | get => _guidelineBrush ?? (_guidelineBrush = GetGuidelineBrushFromFontsAndColors());
101 |
102 | set
103 | {
104 | if (value != _guidelineBrush)
105 | {
106 | _guidelineBrush = value;
107 | _telemetry.Client.TrackEvent("GuidelineColorChanged", new Dictionary { ["Color"] = value.ToString() });
108 | if (_guidelines != null)
109 | {
110 | foreach (var guideline in _guidelines)
111 | {
112 | guideline.Stroke = value;
113 | }
114 | }
115 | }
116 | }
117 | }
118 |
119 | void OnViewLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
120 | {
121 | bool fUpdatePositions = false;
122 |
123 | IFormattedLineSource lineSource = _view.FormattedLineSource;
124 | if (lineSource == null)
125 | {
126 | return;
127 | }
128 |
129 | if(_columnWidth != lineSource.ColumnWidth )
130 | {
131 | _columnWidth = lineSource.ColumnWidth;
132 | fUpdatePositions = true;
133 | }
134 |
135 | if (_baseIndentation != lineSource.BaseIndentation)
136 | {
137 | _baseIndentation = lineSource.BaseIndentation;
138 | fUpdatePositions = true;
139 | }
140 |
141 | if (fUpdatePositions ||
142 | e.VerticalTranslation ||
143 | e.NewViewState.ViewportTop != e.OldViewState.ViewportTop ||
144 | e.NewViewState.ViewportBottom != e.OldViewState.ViewportBottom)
145 | {
146 | UpdatePositions();
147 | }
148 |
149 | if (!_firstLayoutDone)
150 | {
151 | AddGuidelinesToAdornmentLayer();
152 | _firstLayoutDone = true;
153 | }
154 | }
155 |
156 | private IList CreateGuidelines(ITextEditorGuidesSettings settings)
157 | {
158 | var lineBrush = GuidelineBrush;
159 | var dashArray = new DoubleCollection(new double[] { 1.0, 3.0 });
160 | var result = new List();
161 |
162 | foreach (int column in settings.GuideLinePositionsInChars)
163 | {
164 | var line = new Line()
165 | {
166 | DataContext = column,
167 | Stroke = lineBrush,
168 | StrokeThickness = _lineThickness,
169 | StrokeDashArray = dashArray
170 | };
171 |
172 | result.Add(line);
173 | }
174 |
175 | return result;
176 | }
177 |
178 | void UpdatePosition(Line line)
179 | {
180 | int column = (int)line.DataContext;
181 |
182 | line.X1 = line.X2 = _baseIndentation + 0.5 + column * _columnWidth;
183 | line.Y1 = _view.ViewportTop;
184 | line.Y2 = _view.ViewportBottom;
185 | }
186 |
187 | void UpdatePositions()
188 | {
189 | foreach (Line line in _guidelines)
190 | {
191 | UpdatePosition(line);
192 | }
193 | }
194 |
195 | void AddGuidelinesToAdornmentLayer()
196 | {
197 | //Grab a reference to the adornment layer that this adornment should be added to
198 | IAdornmentLayer adornmentLayer = _view.GetAdornmentLayer("ColumnGuide");
199 | if (adornmentLayer == null)
200 | {
201 | return;
202 | }
203 |
204 | adornmentLayer.RemoveAllAdornments();
205 |
206 | // Add the guidelines to the adornment layer and make them relative to the viewport
207 | foreach (UIElement element in _guidelines)
208 | {
209 | adornmentLayer.AddAdornment(AdornmentPositioningBehavior.OwnerControlled, null, null, element, null);
210 | }
211 | }
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/src/ColumnGuide/ColumnGuide.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | 10.0.20305
8 | 2.0
9 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
10 | {0C5B092D-506C-4F92-9902-205874908ACC}
11 | Library
12 | Properties
13 | ColumnGuide
14 | ColumnGuide
15 | v4.5
16 | 512
17 | false
18 | 15.0
19 |
20 |
21 |
22 |
23 | 4.0
24 | false
25 |
26 | SAK
27 | SAK
28 | SAK
29 | SAK
30 | publish\
31 | true
32 | Disk
33 | false
34 | Foreground
35 | 7
36 | Days
37 | false
38 | false
39 | true
40 | 0
41 | 1.0.0.%2a
42 | false
43 | true
44 |
45 |
46 | true
47 | full
48 | false
49 | bin\Debug\
50 | DEBUG;TRACE
51 | prompt
52 | 4
53 | False
54 | False
55 | false
56 | ColumnGuide.ruleset
57 |
58 |
59 | pdbonly
60 | true
61 | bin\Release\
62 | TRACE
63 | prompt
64 | 4
65 | False
66 | False
67 | false
68 | true
69 | ColumnGuide.ruleset
70 |
71 |
72 | false
73 |
74 |
75 |
76 |
77 |
78 |
79 | bin\SDV analysis\
80 | false
81 | ColumnGuide.ruleset
82 |
83 |
84 |
85 | ..\packages\Microsoft.ApplicationInsights.2.1.0\lib\net45\Microsoft.ApplicationInsights.dll
86 | True
87 |
88 |
89 | True
90 | ..\References\11.0.0.0\Microsoft.VisualStudio.CoreUtility.dll
91 |
92 |
93 |
94 |
95 | True
96 |
97 |
98 | True
99 | ..\References\11.0.0.0\Microsoft.VisualStudio.Text.Data.dll
100 |
101 |
102 | True
103 | ..\References\11.0.0.0\Microsoft.VisualStudio.Text.UI.dll
104 |
105 |
106 | True
107 | ..\References\11.0.0.0\Microsoft.VisualStudio.Text.UI.Wpf.dll
108 |
109 |
110 | True
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 | False
138 | Microsoft .NET Framework 4 %28x86 and x64%29
139 | true
140 |
141 |
142 | False
143 | .NET Framework 3.5 SP1 Client Profile
144 | false
145 |
146 |
147 | False
148 | .NET Framework 3.5 SP1
149 | false
150 |
151 |
152 |
153 | 10.0
154 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
155 |
156 |
157 |
158 |
159 |
166 |
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/ColumnGuidePackage.vsct:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
31 |
32 |
39 |
40 |
41 |
45 |
46 |
47 |
51 |
52 |
55 |
56 |
59 |
62 |
63 |
64 |
65 |
66 |
72 |
73 |
74 |
75 |
77 |
78 |
85 |
86 |
95 |
96 |
105 |
106 |
113 |
114 |
115 |
116 |
117 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
136 |
137 |
139 |
142 |
143 |
144 |
147 |
148 |
149 |
152 |
153 |
154 |
157 |
158 |
159 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
--------------------------------------------------------------------------------
/src/ColumnGuide/TextEditorGuidesSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.Composition;
4 | using System.Runtime.InteropServices;
5 | using System.Windows.Media;
6 | using Microsoft.VisualStudio.Shell.Interop;
7 | using System.ComponentModel;
8 | using System.Text;
9 |
10 | namespace ColumnGuide
11 | {
12 | [Export(typeof(ITextEditorGuidesSettings))]
13 | [Export(typeof(ITextEditorGuidesSettingsChanger))]
14 | sealed class TextEditorGuidesSettings : ITextEditorGuidesSettings, INotifyPropertyChanged, ITextEditorGuidesSettingsChanger
15 | {
16 | private const int _maxGuides = 12;
17 |
18 | [Import]
19 | Lazy HostServices { get; set; }
20 |
21 | IVsSettingsStore ReadOnlyUserSettings
22 | {
23 | get
24 | {
25 | IVsSettingsManager manager = HostServices.Value.SettingsManagerService;
26 | Marshal.ThrowExceptionForHR(manager.GetReadOnlySettingsStore((uint)__VsSettingsScope.SettingsScope_UserSettings, out var store));
27 | return store;
28 | }
29 | }
30 |
31 | IVsWritableSettingsStore ReadWriteUserSettings
32 | {
33 | get
34 | {
35 | IVsSettingsManager manager = HostServices.Value.SettingsManagerService;
36 | Marshal.ThrowExceptionForHR(manager.GetWritableSettingsStore((uint)__VsSettingsScope.SettingsScope_UserSettings, out var store));
37 | return store;
38 | }
39 | }
40 |
41 |
42 | private string GetUserSettingsString(string key, string value)
43 | {
44 | IVsSettingsStore store = ReadOnlyUserSettings;
45 | Marshal.ThrowExceptionForHR(store.GetStringOrDefault(key, value, String.Empty, out string result));
46 | return result;
47 | }
48 |
49 | private void WriteUserSettingsString(string key, string propertyName, string value)
50 | {
51 | IVsWritableSettingsStore store = ReadWriteUserSettings;
52 | Marshal.ThrowExceptionForHR(store.SetString(key, propertyName, value));
53 | }
54 |
55 | private void WriteSettings(Color color, IEnumerable columns)
56 | {
57 | string value = ComposeSettingsString(color, columns);
58 | GuidelinesConfiguration = value;
59 | }
60 |
61 | private static string ComposeSettingsString(Color color, IEnumerable columns)
62 | {
63 | StringBuilder sb = new StringBuilder();
64 | sb.AppendFormat("RGB({0},{1},{2})", color.R, color.G, color.B);
65 | IEnumerator columnsEnumerator = columns.GetEnumerator();
66 | if( columnsEnumerator.MoveNext() )
67 | {
68 | sb.AppendFormat(" {0}", columnsEnumerator.Current);
69 | while( columnsEnumerator.MoveNext() )
70 | {
71 | sb.AppendFormat(", {0}", columnsEnumerator.Current);
72 | }
73 | }
74 |
75 | return sb.ToString();
76 | }
77 |
78 | #region ITextEditorGuidesSettingsChanger Members
79 |
80 | public bool AddGuideline(int column)
81 | {
82 | if (!IsValidColumn(column))
83 | {
84 | throw new ArgumentOutOfRangeException("column", "The paramenter must be between 1 and 10,000");
85 | }
86 |
87 | if (GetCountOfGuidelines() >= _maxGuides)
88 | {
89 | return false; // Cannot add more than _maxGuides guidelines
90 | }
91 |
92 | // Check for duplicates
93 | List columns = new List(GuideLinePositionsInChars);
94 | if (columns.Contains(column))
95 | {
96 | return false;
97 | }
98 |
99 | columns.Add(column);
100 |
101 | WriteSettings(this.GuidelinesColor, columns);
102 | return true;
103 | }
104 |
105 | public bool RemoveGuideline(int column)
106 | {
107 | if (!IsValidColumn(column))
108 | {
109 | throw new ArgumentOutOfRangeException("column", "The paramenter must be between 1 and 10,000");
110 | }
111 |
112 | List columns = new List(GuideLinePositionsInChars);
113 | if (!columns.Remove(column))
114 | {
115 | // Not present
116 | // Allow user to remove the last column even if they're not on the right column
117 | if (columns.Count != 1)
118 | {
119 | return false;
120 | }
121 |
122 | columns.Clear();
123 | }
124 |
125 | WriteSettings(this.GuidelinesColor, columns);
126 | return true;
127 | }
128 |
129 | public bool CanAddGuideline(int column)
130 | {
131 | if (!IsValidColumn(column))
132 | {
133 | return false;
134 | }
135 |
136 | if (GetCountOfGuidelines() >= _maxGuides)
137 | {
138 | return false;
139 | }
140 |
141 | return !IsGuidelinePresent(column);
142 | }
143 |
144 | public bool CanRemoveGuideline(int column)
145 | {
146 | if (!IsValidColumn(column))
147 | {
148 | return false;
149 | }
150 |
151 | return IsGuidelinePresent(column)
152 | || HasExactlyOneGuideline(); // Allow user to remove the last guideline regardless of the column
153 | }
154 |
155 | public void RemoveAllGuidelines()
156 | {
157 | WriteSettings(this.GuidelinesColor, new int[0]);
158 | }
159 |
160 | #endregion
161 |
162 | private bool HasExactlyOneGuideline()
163 | {
164 | using (var enumerator = GuideLinePositionsInChars.GetEnumerator())
165 | {
166 | return enumerator.MoveNext() && !enumerator.MoveNext();
167 | }
168 | }
169 |
170 | private int GetCountOfGuidelines()
171 | {
172 | int i = 0;
173 | foreach (int value in GuideLinePositionsInChars)
174 | {
175 | i++;
176 | }
177 | return i;
178 | }
179 |
180 | private static bool IsValidColumn(int column)
181 | {
182 | // -ve is not allowed
183 | // zero is allowed (per user request)
184 | // 10000 seems like a sensible upper limit
185 | return 0 <= column && column <= 10000;
186 | }
187 |
188 | private bool IsGuidelinePresent(int column)
189 | {
190 | foreach (int value in GuideLinePositionsInChars)
191 | {
192 | if (value == column)
193 | {
194 | return true;
195 | }
196 | }
197 |
198 | return false;
199 | }
200 |
201 | private string _guidelinesConfiguration;
202 | private string GuidelinesConfiguration
203 | {
204 | get
205 | {
206 | if (_guidelinesConfiguration == null)
207 | {
208 | _guidelinesConfiguration = GetUserSettingsString("Text Editor", "Guides").Trim();
209 | }
210 | return _guidelinesConfiguration;
211 | }
212 |
213 | set
214 | {
215 | if (value != _guidelinesConfiguration)
216 | {
217 | _guidelinesConfiguration = value;
218 | WriteUserSettingsString("Text Editor", "Guides", value);
219 | FirePropertyChanged(nameof(ITextEditorGuidesSettings.GuideLinePositionsInChars));
220 | }
221 | }
222 | }
223 |
224 | private void FirePropertyChanged(string propertyName)
225 | {
226 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
227 | }
228 |
229 | // Parse a color out of a string that begins like "RGB(255,0,0)"
230 | public Color GuidelinesColor
231 | {
232 | get
233 | {
234 | string config = GuidelinesConfiguration;
235 | if (!String.IsNullOrEmpty(config) && config.StartsWith("RGB(", StringComparison.Ordinal))
236 | {
237 | int lastParen = config.IndexOf(')');
238 | if (lastParen > 4)
239 | {
240 | string[] rgbs = config.Substring(4, lastParen - 4).Split(',');
241 |
242 | if (rgbs.Length >= 3)
243 | {
244 | if (byte.TryParse(rgbs[0], out byte r) &&
245 | byte.TryParse(rgbs[1], out byte g) &&
246 | byte.TryParse(rgbs[2], out byte b))
247 | {
248 | return Color.FromRgb(r, g, b);
249 | }
250 | }
251 | }
252 | }
253 | return Colors.DarkRed;
254 | }
255 |
256 | set
257 | {
258 | WriteSettings(value, GuideLinePositionsInChars);
259 | }
260 | }
261 |
262 | // Parse a list of integer values out of a string that looks like "RGB(255,0,0) 1,5,10,80"
263 | public IEnumerable GuideLinePositionsInChars
264 | {
265 | get
266 | {
267 | string config = GuidelinesConfiguration;
268 | if (String.IsNullOrEmpty(config))
269 | {
270 | yield break;
271 | }
272 | if (!config.StartsWith("RGB(", StringComparison.Ordinal))
273 | {
274 | yield break;
275 | }
276 |
277 | int lastParen = config.IndexOf(')');
278 | if (lastParen <= 4)
279 | {
280 | yield break;
281 | }
282 |
283 | string[] columns = config.Substring(lastParen + 1).Split(',');
284 |
285 | int columnCount = 0;
286 | foreach (string columnText in columns)
287 | {
288 | int column = -1;
289 | if (int.TryParse(columnText, out column) && column >= 0 /*Note: VS 2008 didn't allow zero, but we do, per user request*/ )
290 | {
291 | columnCount++;
292 | yield return column;
293 | if (columnCount >= _maxGuides)
294 | {
295 | break;
296 | }
297 | }
298 | }
299 | }
300 | }
301 |
302 | #region INotifyPropertyChanged Members
303 |
304 | public event PropertyChangedEventHandler PropertyChanged;
305 |
306 | #endregion
307 | }
308 | }
309 |
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/ColumnGuidePackage.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | 2.0
8 | {B2BA96C9-1020-4D3E-9E4F-9D2525FD4DC3}
9 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
10 | Library
11 | Properties
12 | Microsoft.ColumnGuidePackage
13 | ColumnGuidePackage
14 | false
15 |
16 |
17 | v4.5
18 | 15.0
19 |
20 |
21 |
22 |
23 | 4.0
24 | false
25 |
26 | SAK
27 | SAK
28 | SAK
29 | SAK
30 | publish\
31 | true
32 | Disk
33 | false
34 | Foreground
35 | 7
36 | Days
37 | false
38 | false
39 | true
40 | 0
41 | 1.0.0.%2a
42 | false
43 | true
44 |
45 |
46 | true
47 | full
48 | false
49 | bin\Debug\
50 | DEBUG;TRACE
51 | prompt
52 | 4
53 | False
54 | False
55 | false
56 |
57 |
58 |
59 | pdbonly
60 | true
61 | bin\Release\
62 | TRACE
63 | prompt
64 | 4
65 | true
66 | False
67 | False
68 | false
69 |
70 |
71 |
72 |
73 | False
74 |
75 |
76 | ..\packages\Microsoft.ApplicationInsights.2.1.0\lib\net45\Microsoft.ApplicationInsights.dll
77 | True
78 |
79 |
80 |
81 | True
82 | ..\References\11.0.0.0\Microsoft.VisualStudio.ComponentModelHost.dll
83 |
84 |
85 | True
86 | ..\References\11.0.0.0\Microsoft.VisualStudio.CoreUtility.dll
87 |
88 |
89 | True
90 | ..\References\11.0.0.0\Microsoft.VisualStudio.Editor.dll
91 |
92 |
93 |
94 |
95 |
96 | True
97 |
98 |
99 |
100 |
101 |
102 | True
103 | ..\References\11.0.0.0\Microsoft.VisualStudio.Text.UI.dll
104 |
105 |
106 | True
107 | ..\References\11.0.0.0\Microsoft.VisualStudio.Text.UI.Wpf.dll
108 |
109 |
110 |
111 | True
112 | ..\References\11.0.0.0\Microsoft.VisualStudio.Shell.11.0.dll
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 | {00020430-0000-0000-C000-000000000046}
123 | 2
124 | 0
125 | 0
126 | primary
127 | False
128 | False
129 |
130 |
131 |
132 |
133 |
134 | True
135 | True
136 | Resources.resx
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 | ResXFileCodeGenerator
148 | Resources.Designer.cs
149 | Designer
150 |
151 |
152 | true
153 | VSPackage
154 |
155 |
156 |
157 |
158 |
159 | Designer
160 |
161 |
162 |
163 |
164 | Menus.ctmenu
165 | Designer
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 | {0C5B092D-506C-4F92-9902-205874908ACC}
175 | ColumnGuide
176 |
177 |
178 |
179 |
180 | False
181 | Microsoft .NET Framework 4 %28x86 and x64%29
182 | true
183 |
184 |
185 | False
186 | .NET Framework 3.5 SP1 Client Profile
187 | false
188 |
189 |
190 | False
191 | .NET Framework 3.5 SP1
192 | false
193 |
194 |
195 |
196 | true
197 |
198 |
199 | bin\SDV analysis\
200 | false
201 |
202 |
203 |
204 | 10.0
205 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
206 |
207 |
208 |
209 |
210 |
217 |
--------------------------------------------------------------------------------
/src/ColumnGuidePackage/ColumnGuidePackage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel.Design;
3 | using System.Diagnostics;
4 | using System.Globalization;
5 | using System.Runtime.InteropServices;
6 | using Microsoft.VisualStudio.Shell;
7 | using Microsoft.VisualStudio.Shell.Interop;
8 | using Microsoft.VisualStudio;
9 | using Microsoft.VisualStudio.TextManager.Interop;
10 | using Microsoft.VisualStudio.Text.Editor;
11 | using System.Collections.Generic;
12 |
13 | namespace Microsoft.ColumnGuidePackage
14 | {
15 | ///
16 | /// This is the class that implements the package exposed by this assembly.
17 | ///
18 | /// The minimum requirement for a class to be considered a valid package for Visual Studio
19 | /// is to implement the IVsPackage interface and register itself with the shell.
20 | /// This package uses the helper classes defined inside the Managed Package Framework (MPF)
21 | /// to do it: it derives from the Package class that provides the implementation of the
22 | /// IVsPackage interface and uses the registration attributes defined in the framework to
23 | /// register itself and its components with the shell.
24 | ///
25 | // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is
26 | // a package.
27 | [PackageRegistration(UseManagedResourcesOnly = true)]
28 | // This attribute is needed to let the shell know that this package exposes some menus.
29 | [ProvideMenuResource("Menus.ctmenu", 2)]
30 | [Guid(GuidList.guidColumnGuidePkgString)]
31 | public sealed class ColumnGuidePackage : Package
32 | {
33 | ///
34 | /// Default constructor of the package.
35 | /// Inside this method you can place any initialization code that does not require
36 | /// any Visual Studio service because at this point the package object is created but
37 | /// not sited yet inside Visual Studio environment. The place to do all the other
38 | /// initialization is the Initialize method.
39 | ///
40 | public ColumnGuidePackage()
41 | {
42 | }
43 |
44 | /////////////////////////////////////////////////////////////////////////////
45 | // Overriden Package Implementation
46 | #region Package Members
47 |
48 | ///
49 | /// Initialization of the package; this method is called right after the package is sited, so this is the place
50 | /// where you can put all the initilaization code that rely on services provided by VisualStudio.
51 | ///
52 | protected override void Initialize()
53 | {
54 | base.Initialize();
55 |
56 | Telemetry.Client.TrackEvent(nameof(ColumnGuidePackage) + "." + nameof(Initialize), new Dictionary() { ["VSVersion"] = GetShellVersion() });
57 |
58 | // Add our command handlers for menu (commands must exist in the .vsct file)
59 |
60 | OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
61 | if (null != mcs)
62 | {
63 | _addGuidelineCommand = new OleMenuCommand(AddColumnGuideExecuted, null, AddColumnGuideBeforeQueryStatus, new CommandID(GuidList.guidColumnGuideCmdSet, (int)PkgCmdIDList.cmdidAddColumnGuideline))
64 | {
65 | ParametersDescription = ""
66 | };
67 | mcs.AddCommand(_addGuidelineCommand);
68 |
69 | _removeGuidelineCommand = new OleMenuCommand(RemoveColumnGuideExecuted, null, RemoveColumnGuideBeforeChangeQueryStatus, new CommandID(GuidList.guidColumnGuideCmdSet, (int)PkgCmdIDList.cmdidRemoveColumnGuideline))
70 | {
71 | ParametersDescription = ""
72 | };
73 | mcs.AddCommand(_removeGuidelineCommand);
74 |
75 | mcs.AddCommand(new MenuCommand(RemoveAllGuidelinesExecuted, new CommandID(GuidList.guidColumnGuideCmdSet, (int)PkgCmdIDList.cmdidRemoveAllColumnGuidelines)));
76 | }
77 | }
78 |
79 | #endregion
80 |
81 | private string GetShellVersion()
82 | {
83 | var shell = GetService(typeof(SVsShell)) as IVsShell;
84 | if (shell != null)
85 | {
86 | object obj;
87 | if (ErrorHandler.Succeeded(shell.GetProperty((int)__VSSPROPID5.VSSPROPID_ReleaseVersion, out obj)) && obj != null)
88 | {
89 | return obj.ToString();
90 | }
91 | }
92 |
93 | return "Unknown";
94 | }
95 |
96 | OleMenuCommand _addGuidelineCommand;
97 | OleMenuCommand _removeGuidelineCommand;
98 |
99 | private void AddColumnGuideBeforeQueryStatus(object sender, EventArgs e)
100 | {
101 | int currentColumn = GetCurrentEditorColumn();
102 | _addGuidelineCommand.Enabled = TextEditorGuidesSettingsRendezvous.Instance.CanAddGuideline(currentColumn);
103 | }
104 |
105 | private void RemoveColumnGuideBeforeChangeQueryStatus(object sender, EventArgs e)
106 | {
107 | int currentColumn = GetCurrentEditorColumn();
108 | _removeGuidelineCommand.Enabled = TextEditorGuidesSettingsRendezvous.Instance.CanRemoveGuideline(currentColumn);
109 | }
110 |
111 | ///
112 | /// Determine the applicable column number for an add or remove command.
113 | /// The column is parsed from command arguments, if present. Otherwise
114 | /// the current position of the caret is used to determine the column.
115 | ///
116 | /// Event args passed to the command handler.
117 | /// The column number. May be negative to indicate the column number is unavailable.
118 | /// The column number parsed from event args was not a valid integer.
119 | private int GetApplicableColumn(EventArgs e)
120 | {
121 | var inValue = ((OleMenuCmdEventArgs)e).InValue as string;
122 | if (!string.IsNullOrEmpty(inValue))
123 | {
124 | int column;
125 | if (!int.TryParse(inValue, out column) || column < 0)
126 | throw new ArgumentException("Invalid column");
127 |
128 | Telemetry.Client.TrackEvent("Command parameter used");
129 | return column;
130 | }
131 |
132 | return GetCurrentEditorColumn();
133 | }
134 |
135 | ///
136 | /// This function is the callback used to execute a command when the a menu item is clicked.
137 | /// See the Initialize method to see how the menu item is associated to this function using
138 | /// the OleMenuCommandService service and the MenuCommand class.
139 | ///
140 | private void AddColumnGuideExecuted(object sender, EventArgs e)
141 | {
142 | int column = GetApplicableColumn(e);
143 | if (column >= 0)
144 | {
145 | Telemetry.Client.TrackEvent(nameof(AddColumnGuideExecuted), new Dictionary() { ["Column"] = column.ToString() });
146 | TextEditorGuidesSettingsRendezvous.Instance.AddGuideline(column);
147 | }
148 | }
149 |
150 | private void RemoveColumnGuideExecuted(object sender, EventArgs e)
151 | {
152 | int column = GetApplicableColumn(e);
153 | if (column >= 0)
154 | {
155 | Telemetry.Client.TrackEvent(nameof(RemoveColumnGuideExecuted), new Dictionary() { ["Column"] = column.ToString() });
156 | TextEditorGuidesSettingsRendezvous.Instance.RemoveGuideline(column);
157 | }
158 | }
159 |
160 | private void RemoveAllGuidelinesExecuted(object sender, EventArgs e)
161 | {
162 | Telemetry.Client.TrackEvent(nameof(RemoveAllGuidelinesExecuted));
163 | TextEditorGuidesSettingsRendezvous.Instance.RemoveAllGuidelines();
164 | }
165 |
166 | ///
167 | /// Find the active text view (if any) in the active document.
168 | ///
169 | /// The IVsTextView of the active view, or null if there is no active document or the
170 | /// active view in the active document is not a text view.
171 | private IVsTextView GetActiveTextView()
172 | {
173 | IVsMonitorSelection selection = GetService(typeof(IVsMonitorSelection)) as IVsMonitorSelection;
174 | object frameObj = null;
175 | ErrorHandler.ThrowOnFailure(selection.GetCurrentElementValue((uint)VSConstants.VSSELELEMID.SEID_DocumentFrame, out frameObj));
176 |
177 | IVsWindowFrame frame = frameObj as IVsWindowFrame;
178 | if (frame == null)
179 | {
180 | return null;
181 | }
182 |
183 | return GetActiveView(frame);
184 | }
185 |
186 | private static IVsTextView GetActiveView(IVsWindowFrame windowFrame)
187 | {
188 | if (windowFrame == null)
189 | {
190 | throw new ArgumentException("windowFrame");
191 | }
192 |
193 | object pvar;
194 | ErrorHandler.ThrowOnFailure(windowFrame.GetProperty((int)__VSFPROPID.VSFPROPID_DocView, out pvar));
195 |
196 | IVsTextView textView = pvar as IVsTextView;
197 | if (textView == null)
198 | {
199 | IVsCodeWindow codeWin = pvar as IVsCodeWindow;
200 | if (codeWin != null)
201 | {
202 | ErrorHandler.ThrowOnFailure(codeWin.GetLastActiveView(out textView));
203 | }
204 | }
205 | return textView;
206 | }
207 |
208 | private static IWpfTextView GetTextViewFromVsTextView(IVsTextView view)
209 | {
210 | if (view == null)
211 | {
212 | throw new ArgumentNullException("view");
213 | }
214 |
215 | IVsUserData userData = view as IVsUserData;
216 | if (userData == null)
217 | {
218 | throw new InvalidOperationException();
219 | }
220 |
221 | object objTextViewHost;
222 | if (VSConstants.S_OK != userData.GetData(Microsoft.VisualStudio.Editor.DefGuidList.guidIWpfTextViewHost, out objTextViewHost))
223 | {
224 | throw new InvalidOperationException();
225 | }
226 |
227 | IWpfTextViewHost textViewHost = objTextViewHost as IWpfTextViewHost;
228 | if (textViewHost == null)
229 | {
230 | throw new InvalidOperationException();
231 | }
232 |
233 | return textViewHost.TextView;
234 | }
235 |
236 | ///
237 | /// Given an IWpfTextView, find the position of the caret and report its column number
238 | /// The column number is 0-based
239 | ///
240 | /// The text view containing the caret
241 | /// The column number of the caret's position. When the caret is at the leftmost column, the return value is zero.
242 | private static int GetCaretColumn(IWpfTextView textView)
243 | {
244 | // This is the code the editor uses to populate the status bar. Thanks, Jack!
245 | Microsoft.VisualStudio.Text.Formatting.ITextViewLine caretViewLine = textView.Caret.ContainingTextViewLine;
246 | double columnWidth = textView.FormattedLineSource.ColumnWidth;
247 | return (int)(Math.Round((textView.Caret.Left - caretViewLine.Left) / columnWidth));
248 | }
249 |
250 | private int GetCurrentEditorColumn()
251 | {
252 | IVsTextView view = GetActiveTextView();
253 | if (view == null)
254 | {
255 | return -1;
256 | }
257 |
258 | try
259 | {
260 | IWpfTextView textView = GetTextViewFromVsTextView(view);
261 | int column = GetCaretColumn(textView);
262 |
263 | // Note: GetCaretColumn returns 0-based positions. Guidelines are 1-based positions.
264 | // However, do not subtract one here since the caret is positioned to the left of
265 | // the given column and the guidelines are positioned to the right. We want the
266 | // guideline to line up with the current caret position. e.g. When the caret is
267 | // at position 1 (zero-based), the status bar says column 2. We want to add a
268 | // guideline for column 1 since that will place the guideline where the caret is.
269 | return column;
270 | }
271 | catch (InvalidOperationException)
272 | {
273 | return -1;
274 | }
275 | }
276 | }
277 | }
278 |
--------------------------------------------------------------------------------