├── .editorconfig ├── .gitattributes ├── .github ├── CONTRIBUTING.md ├── FUNDING.yml └── ISSUE_TEMPLATE.md ├── .gitignore ├── CHANGELOG.md ├── Directory.Build.props ├── EditorConfig.sln ├── LICENSE ├── README.md ├── THIRD-PARTY-NOTICES.txt ├── Test └── EditorConfigTest │ ├── CompletionTest.cs │ ├── DocumentTest.cs │ ├── EditorConfigTest.csproj │ ├── Helpers │ ├── Extensions.cs │ ├── Mef.cs │ └── Samples.cs │ ├── ParseItemTest.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── ValidationTest.cs │ └── app.config ├── appveyor.yml ├── art ├── classification.png ├── context-menu.png ├── csharp-analyzers.png ├── editor-context-menu.png ├── formatting.png ├── inheritance-visualizer.png ├── keyword-intellisense.png ├── light-bulb.png ├── navigation-dropdown.png ├── quick-info.png ├── settings.png ├── snippets-context-menu.png ├── snippets-expansion.png ├── suppress-comment.png ├── suppress-errorlist.png ├── suppress_error.png ├── validation-duplicates-parent.png ├── validation-duplicates.png ├── validation.png └── value-intellisense.png ├── lib ├── Microsoft.VisualStudio.Platform.VSEditor.Interop.dll ├── Microsoft.VisualStudio.Platform.VSEditor.dll ├── Microsoft.VisualStudio.Telemetry.dll └── Microsoft.VisualStudio.Text.Internal.dll └── src ├── Adornments ├── InheritanceAdornment.cs └── InheritanceAdornmentProvider.cs ├── BraceCompletion ├── BraceCompletionContext.cs ├── BraceCompletionContextProvider.cs ├── BraceMatchingTagger.cs └── BraceMatchingTaggerProvider.cs ├── Classifier ├── EditorConfigClassifier.cs └── EditorConfigProvider.cs ├── CodeExpansions ├── EnableSnippetsCommand.cs └── Snippets │ ├── basicdocument.snippet │ ├── csharpstyle.snippet │ └── dotnetstyle.snippet ├── CommandTable.cs ├── CommandTable.vsct ├── Commands ├── BaseCommand.cs ├── CreateEditorConfigFile.cs ├── CreateEditorConfigFileAnyCode.cs ├── F1Help.cs ├── HideDefaultCommands.cs ├── NavigateToParent.cs └── OpenSettings.cs ├── Completion ├── CompletionController.cs ├── CompletionElementProvider.cs ├── CompletionOptions.cs ├── CompletionSource.cs ├── CompletionSourceProvider.cs └── FilteredCompletionSet.cs ├── Constants.cs ├── DragDrop ├── EditorConfigDropHandler.cs └── EditorConfigDropHandlerProvider.cs ├── EditorConfig.csproj ├── EditorConfigPackage.cs ├── Formatting ├── EditorConfigFormatter.cs ├── FormatterCommand.cs ├── FormatterOptions.cs └── FormattingType.cs ├── LanguageService ├── Colorizer.cs ├── ContentTypes.cs ├── DropDownBars.cs ├── EditorFactory.cs ├── LanguageService.cs └── Source.cs ├── Monikers.imagemanifest ├── Outlining ├── OutliningTagger.cs └── OutliningTaggerProvider.cs ├── Parser ├── EditorConfigDocument.cs ├── EditorConfigDocumentInheritance.cs ├── EditorConfigDocumentParser.cs ├── ParseItem.cs ├── Property.cs └── Section.cs ├── Properties └── AssemblyInfo.cs ├── ProvideBraceCompletionAttribute.cs ├── QuickInfo ├── EditorConfigQuickInfo.cs ├── EditorConfigQuickInfoController.cs ├── EditorConfigQuickInfoControllerProvider.cs └── EditorConfigQuickInfoSourceProvider.cs ├── Resources ├── ButtonIcon.png ├── Icon.png ├── Text.Designer.cs └── Text.resx ├── Schema ├── Category.cs ├── EditorConfig-schema.json ├── EditorConfig.json ├── Keyword.cs ├── SchemaCatalog.cs ├── Severity.cs └── Value.cs ├── Shared ├── AnalyzerConfig_SectionNameMatching.cs ├── EditorTooltip.xaml ├── EditorTooltip.xaml.cs ├── Extensions.cs ├── ITooltip.cs ├── JoinableTaskFactoryExtensions.cs ├── Telemetry.cs ├── TextViewCreationListener.cs ├── TextViewUtil.cs └── VsHelpers.cs ├── SignatureHelp ├── SectionParameter.cs ├── SectionSignature.cs ├── SectionSignatureHelpSource.cs ├── SignatureHelpController.cs └── SignatureHelpSourceProvider.cs ├── SuggestedActions ├── AddMissingRulesAction.cs ├── AddMissingRulesActionAll.cs ├── AddMissingRulesActionCSharp.cs ├── AddMissingRulesActionDotNet.cs ├── AddMissingRulesActionVB.cs ├── BaseSuggestedAction.cs ├── DeleteSectionAction.cs ├── RemoveDuplicatePropertiesAction.cs ├── SortAllPropertiesAction.cs ├── SortPropertiesAction.cs ├── SuggestedActionsSource.cs ├── SuggestedActionsSourceProvider.cs └── SuppressErrorAction.cs ├── Validation ├── Commands │ └── SuppressError.cs ├── EditorConfigValidator.cs ├── EditorConfigValidatorRules.cs ├── Error.cs ├── ErrorCatalog.cs ├── ErrorCategory.cs ├── ErrorList │ ├── DisplayError.cs │ ├── ErrorList.cs │ ├── SinkManager.cs │ ├── TableDataSource.cs │ └── TableEntriesSnapshot.cs ├── NamingStyles │ ├── Accessibility.cs │ ├── EditorConfigNamingStyleParser.cs │ ├── ModifierKind.cs │ ├── NamingRule.cs │ ├── NamingStyle.cs │ ├── NamingStylePreferences.cs │ ├── NamingStyleRules.cs │ ├── ReportDiagnostic.cs │ ├── SerializableNamingRule.cs │ ├── SymbolKindOrTypeKind.cs │ └── SymbolSpecification.cs ├── Tagger │ ├── ErrorFormatDefinition.cs │ ├── ErrorTagger.cs │ └── ErrorTaggerProvider.cs └── ValidationOptions.cs ├── icons.pkgdef ├── source.extension.cs ├── source.extension.ico ├── source.extension.resx └── source.extension.vsixmanifest /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome:http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Don't use tabs for indentation. 7 | [*] 8 | indent_style = space 9 | end_of_line = crlf 10 | # (Please don't specify an indent_size here; that has too many unintended consequences.) 11 | 12 | # Code files 13 | [*.{cs,csx,vb,vbx}] 14 | indent_size = 4 15 | 16 | # Xml project files 17 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] 18 | indent_size = 2 19 | 20 | # Xml config files 21 | [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] 22 | indent_size = 2 23 | 24 | # JSON files 25 | [*.json] 26 | indent_size = 2 27 | 28 | # Dotnet code style settings: 29 | [*.{cs, vb}] 30 | # Sort using and Import directives with System.* appearing first 31 | dotnet_sort_system_directives_first = true 32 | # Avoid "this." and "Me." if not necessary 33 | dotnet_style_qualification_for_field = false:suggestion 34 | dotnet_style_qualification_for_property = false:suggestion 35 | dotnet_style_qualification_for_method = false:suggestion 36 | dotnet_style_qualification_for_event = false:suggestion 37 | 38 | # Use language keywords instead of framework type names for type references 39 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 40 | dotnet_style_predefined_type_for_member_access = true:suggestion 41 | 42 | # Suggest more modern language features when available 43 | dotnet_style_object_initializer = true:suggestion 44 | dotnet_style_collection_initializer = true:suggestion 45 | dotnet_style_coalesce_expression = true:suggestion 46 | dotnet_style_null_propagation = true:suggestion 47 | dotnet_style_explicit_tuple_names = true:suggestion 48 | 49 | # CSharp code style settings: 50 | [*.cs] 51 | # Prefer "var" everywhere 52 | csharp_style_var_for_built_in_types = false:suggestion 53 | csharp_style_var_when_type_is_apparent = true:suggestion 54 | csharp_style_var_elsewhere = false:suggestion 55 | 56 | # Prefer method-like constructs to have a block body 57 | csharp_style_expression_bodied_methods = false:none 58 | csharp_style_expression_bodied_constructors = false:none 59 | csharp_style_expression_bodied_operators = false:none 60 | 61 | # Prefer property-like constructs to have an expression-body 62 | csharp_style_expression_bodied_properties = true:none 63 | csharp_style_expression_bodied_indexers = true:none 64 | csharp_style_expression_bodied_accessors = true:none 65 | 66 | # Suggest more modern language features when available 67 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 68 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 69 | csharp_style_inlined_variable_declaration = true:suggestion 70 | csharp_style_throw_expression = true:suggestion 71 | csharp_style_conditional_delegate_call = true:suggestion 72 | 73 | # Newline settings 74 | csharp_new_line_before_open_brace = all 75 | csharp_new_line_before_else = true 76 | csharp_new_line_before_catch = true 77 | csharp_new_line_before_finally = true 78 | csharp_new_line_before_members_in_object_initializers = true 79 | csharp_new_line_before_members_in_anonymous_types = true -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: madskristensen 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Installed product versions 2 | - Visual Studio: [example 2015 Professional] 3 | - This extension: [example 1.1.21] 4 | 5 | ### Description 6 | Replace this text with a short description 7 | 8 | ### Steps to recreate 9 | 1. Replace this 10 | 2. text with 11 | 3. the steps 12 | 4. to recreate 13 | 14 | ### Current behavior 15 | Explain what it's doing and why it's wrong 16 | 17 | ### Expected behavior 18 | Explain what it should be doing after it's fixed. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | packages 2 | 3 | # User files 4 | *.suo 5 | *.user 6 | *.sln.docstates 7 | .vs/ 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Rr]elease/ 12 | x64/ 13 | [Bb]in/ 14 | [Oo]bj/ 15 | 16 | # MSTest test Results 17 | [Tt]est[Rr]esult*/ 18 | [Bb]uild[Ll]og.* 19 | 20 | # NCrunch 21 | *.ncrunchsolution 22 | *.ncrunchproject 23 | _NCrunch_WebCompiler -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7.3 4 | 5 | 6 | -------------------------------------------------------------------------------- /EditorConfig.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26009.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EditorConfig", "src\EditorConfig.csproj", "{428EFC5A-7AC4-4CE4-8A37-D402B8A03EB4}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A710B3FB-9088-4A90-A822-AE25ACB69895}" 9 | ProjectSection(SolutionItems) = preProject 10 | .editorconfig = .editorconfig 11 | appveyor.yml = appveyor.yml 12 | CHANGELOG.md = CHANGELOG.md 13 | README.md = README.md 14 | EndProjectSection 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EditorConfigTest", "Test\EditorConfigTest\EditorConfigTest.csproj", "{D4005889-6273-4725-AF75-8A2EE92FA639}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {428EFC5A-7AC4-4CE4-8A37-D402B8A03EB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {428EFC5A-7AC4-4CE4-8A37-D402B8A03EB4}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {428EFC5A-7AC4-4CE4-8A37-D402B8A03EB4}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {428EFC5A-7AC4-4CE4-8A37-D402B8A03EB4}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {D4005889-6273-4725-AF75-8A2EE92FA639}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {D4005889-6273-4725-AF75-8A2EE92FA639}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {D4005889-6273-4725-AF75-8A2EE92FA639}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {D4005889-6273-4725-AF75-8A2EE92FA639}.Release|Any CPU.Build.0 = Release|Any CPU 32 | EndGlobalSection 33 | GlobalSection(SolutionProperties) = preSolution 34 | HideSolutionNode = FALSE 35 | EndGlobalSection 36 | GlobalSection(Performance) = preSolution 37 | HasPerformanceSessions = true 38 | EndGlobalSection 39 | EndGlobal 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016 Mads Kristensen 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /THIRD-PARTY-NOTICES.txt: -------------------------------------------------------------------------------- 1 | EditorConfig Language Service uses third-party libraries or other resources 2 | that may be distributed under licenses different than the EditorConfig 3 | Language Service software. 4 | 5 | In the event that we accidentally failed to list a required notice, please 6 | bring it to our attention by posting an issue. 7 | 8 | The attached notices are provided for information only. 9 | 10 | License notice for .NET Compiler Platform (Roslyn) 11 | -------------------------------------------------- 12 | 13 | The MIT License (MIT) 14 | 15 | Copyright (c) .NET Foundation and Contributors 16 | 17 | All rights reserved. 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in all 27 | copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 | SOFTWARE. 36 | -------------------------------------------------------------------------------- /Test/EditorConfigTest/CompletionTest.cs: -------------------------------------------------------------------------------- 1 | using EditorConfig; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace EditorConfigTest 5 | { 6 | [TestClass] 7 | public class CompletionTest 8 | { 9 | [TestMethod] 10 | public void GetHighlightedSpans() 11 | { 12 | var spans = FilteredCompletionSet.GetHighlightedSpans("dotnet_style_predefined_type_for_locals_parameters_members", "dottymem"); 13 | Assert.AreEqual(3, spans.Count); 14 | 15 | var ttw = FilteredCompletionSet.GetHighlightedSpans("trim_trailing_whitespace", "trimtrailingwhitespace"); 16 | Assert.AreEqual(3, ttw.Count); 17 | Assert.AreEqual(4, ttw[0].Length); 18 | 19 | var partlyNonMatch = FilteredCompletionSet.GetHighlightedSpans("dotnet_style_explicit_tuple_names", "dottymem"); 20 | Assert.AreEqual(0, partlyNonMatch.Count); 21 | 22 | var partlyNonMatch2 = FilteredCompletionSet.GetHighlightedSpans("dotnet_style_qualification_for_event", "dotmem"); 23 | Assert.AreEqual(0, partlyNonMatch2.Count); 24 | 25 | var partlyNonMatch3 = FilteredCompletionSet.GetHighlightedSpans("dotnet_style_qualification_for_method", "dotmem"); 26 | Assert.AreEqual(0, partlyNonMatch3.Count); 27 | 28 | var nonMatch = FilteredCompletionSet.GetHighlightedSpans("test", "l"); 29 | Assert.AreEqual(0, nonMatch.Count); 30 | 31 | var cha = FilteredCompletionSet.GetHighlightedSpans("charset", "CHAR"); 32 | Assert.AreEqual(1, cha.Count); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Test/EditorConfigTest/DocumentTest.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using EditorConfig; 5 | using Microsoft.VisualStudio.TestTools.UnitTesting; 6 | using Microsoft.VisualStudio.Text; 7 | 8 | namespace EditorConfigTest 9 | { 10 | [TestClass] 11 | public class DocumentTest 12 | { 13 | [TestMethod, TestCategory("MEF")] 14 | public async Task Parse() 15 | { 16 | ITextBuffer buffer = Mef.CreateTextBuffer(Samples.OneSectionStandard); 17 | var doc = EditorConfigDocument.FromTextBuffer(buffer); 18 | 19 | await doc.WaitForParsingComplete(); 20 | 21 | Assert.AreEqual(12, doc.ParseItems.Count); 22 | Assert.AreEqual(ItemType.Keyword, doc.ParseItems[0].ItemType); 23 | Assert.AreEqual(ItemType.Comment, doc.ParseItems[2].ItemType); 24 | 25 | Property root = doc.Properties[0]; 26 | Assert.AreEqual(1, doc.Properties.Count); 27 | Assert.IsTrue(root.IsValid); 28 | Assert.AreEqual(SchemaCatalog.Root, root.Keyword.Text); 29 | 30 | Section section = doc.Sections[0]; 31 | Assert.AreEqual("[*.cs]", section.Item.Text); 32 | Assert.AreEqual(4, section.Properties.Count); 33 | Assert.IsTrue(section.Properties.All(p => p.IsValid)); 34 | } 35 | 36 | [TestMethod, TestCategory("MEF")] 37 | public async Task MultipleValues() 38 | { 39 | ITextBuffer buffer = Mef.CreateTextBuffer(Samples.MultipleValuesSection); 40 | var doc = EditorConfigDocument.FromTextBuffer(buffer); 41 | 42 | await doc.WaitForParsingComplete(); 43 | 44 | Assert.AreEqual(3, doc.ParseItems.Count); 45 | Assert.AreEqual("accessors, indexers", doc.ParseItems.Last().Text); 46 | } 47 | 48 | [TestMethod, TestCategory("MEF")] 49 | public async Task Suppressions() 50 | { 51 | ITextBuffer buffer = Mef.CreateTextBuffer(Samples.Suppression); 52 | var doc = EditorConfigDocument.FromTextBuffer(buffer); 53 | 54 | await doc.WaitForParsingComplete(); 55 | 56 | Assert.AreEqual(3, doc.ParseItems.Count); 57 | Assert.AreEqual("EC101", doc.ParseItems[1].Text); 58 | Assert.AreEqual(12, doc.ParseItems[1].Span.Start); 59 | Assert.AreEqual(5, doc.ParseItems[1].Span.Length); 60 | } 61 | 62 | [TestMethod] 63 | public void NamingRules() 64 | { 65 | var file = new FileInfo(@"..\..\..\..\src\schema\EditorConfig.json"); 66 | SchemaCatalog.ParseJson(file.FullName); 67 | 68 | bool exist = SchemaCatalog.TryGetKeyword("dotnet_naming_rule.foo.symbols", out Keyword keyword); 69 | 70 | Assert.IsTrue(exist); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Test/EditorConfigTest/EditorConfigTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {D4005889-6273-4725-AF75-8A2EE92FA639} 7 | Library 8 | Properties 9 | EditorConfigTest 10 | EditorConfigTest 11 | v4.6 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 15.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | 22 | 23 | 24 | true 25 | full 26 | false 27 | bin\Debug\ 28 | DEBUG;TRACE 29 | prompt 30 | 4 31 | 32 | 33 | pdbonly 34 | true 35 | bin\Release\ 36 | TRACE 37 | prompt 38 | 4 39 | 40 | 41 | 42 | False 43 | ..\..\lib\Microsoft.VisualStudio.Platform.VSEditor.dll 44 | 45 | 46 | ..\..\lib\Microsoft.VisualStudio.Platform.VSEditor.Interop.dll 47 | True 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | {428efc5a-7ac4-4ce4-8a37-d402b8a03eb4} 68 | EditorConfig 69 | 70 | 71 | 72 | 73 | 15.0.0-beta4 74 | 75 | 76 | 1.3.2 77 | 78 | 79 | 1.3.2 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /Test/EditorConfigTest/Helpers/Extensions.cs: -------------------------------------------------------------------------------- 1 | using EditorConfig; 2 | using System.Threading.Tasks; 3 | 4 | namespace EditorConfigTest 5 | { 6 | public static class Extensions 7 | { 8 | public static async Task WaitForParsingComplete(this EditorConfigDocument document) 9 | { 10 | while (document.IsParsing) 11 | { 12 | await Task.Delay(2); 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Test/EditorConfigTest/Helpers/Mef.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Text; 2 | using Microsoft.VisualStudio.Utilities; 3 | using System.ComponentModel.Composition; 4 | using System.ComponentModel.Composition.Hosting; 5 | using System.IO; 6 | using System.Reflection; 7 | 8 | namespace EditorConfigTest 9 | { 10 | public class Mef 11 | { 12 | [Import] 13 | private ITextBufferFactoryService TextBufferService { get; set; } 14 | 15 | [Import] 16 | private IContentTypeRegistryService ContentTypeService { get; set; } 17 | 18 | public Mef() 19 | { 20 | string lib = new DirectoryInfo(@"..\..\..\..\lib\").FullName; 21 | 22 | var editor = Assembly.LoadFrom(lib + "Microsoft.VisualStudio.Platform.VSEditor.dll"); 23 | var interop = Assembly.LoadFrom(lib + "Microsoft.VisualStudio.Platform.VSEditor.interop.dll"); 24 | var text = Assembly.LoadFrom(lib + "Microsoft.VisualStudio.Text.Internal.dll"); 25 | var telemetry = Assembly.LoadFrom(lib + "Microsoft.VisualStudio.Telemetry.dll"); 26 | 27 | var catalog = new AggregateCatalog(); 28 | catalog.Catalogs.Add(new AssemblyCatalog(editor)); 29 | catalog.Catalogs.Add(new AssemblyCatalog(interop)); 30 | catalog.Catalogs.Add(new AssemblyCatalog(text)); 31 | catalog.Catalogs.Add(new AssemblyCatalog(telemetry)); 32 | 33 | catalog.Catalogs.Add(new AssemblyCatalog(typeof(DocumentTest).Assembly)); 34 | catalog.Catalogs.Add(new AssemblyCatalog(typeof(EditorConfig.EditorConfigDocument).Assembly)); 35 | 36 | var container = new CompositionContainer(catalog); 37 | container.SatisfyImportsOnce(this); 38 | } 39 | 40 | public static ITextBuffer CreateTextBuffer(string text) 41 | { 42 | var mef = new Mef(); 43 | return mef.TextBufferService.CreateTextBuffer(text, mef.ContentTypeService.UnknownContentType); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Test/EditorConfigTest/Helpers/Samples.cs: -------------------------------------------------------------------------------- 1 | namespace EditorConfigTest 2 | { 3 | public class Samples 4 | { 5 | public const string OneSectionStandard = @"root = true 6 | 7 | # comment 8 | [*.cs] 9 | indent_style = space 10 | indent_size = 4 11 | end_of_line = crlf 12 | insert_final_newline = true"; 13 | 14 | public const string MultipleValuesSection = @"[*.cs] 15 | csharp_new_line_before_open_brace = accessors, indexers"; 16 | 17 | public const string SeveritySimple = @"[*.cs] 18 | dotnet_style_qualification_for_event = true"; 19 | 20 | public const string Suppression = @"# Suppress: EC101 EC102"; 21 | 22 | public const string NamingRules = @"[*.cs] 23 | dotnet_naming_rule.foo.severity = warning 24 | dotnet_naming_rule.foo.symbols = fooSymbolsTitle 25 | dotnet_naming_rule.foo.style = fooStyleTitle"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Test/EditorConfigTest/ParseItemTest.cs: -------------------------------------------------------------------------------- 1 | using EditorConfig; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using Microsoft.VisualStudio.Text; 4 | 5 | namespace EditorConfigTest 6 | { 7 | [TestClass] 8 | public class ParseItemTest 9 | { 10 | [TestMethod] 11 | public void Equals() 12 | { 13 | var a = new ParseItem(default(EditorConfigDocument), ItemType.Keyword, new Span(10, 10), "a text"); 14 | var b = new ParseItem(default(EditorConfigDocument), ItemType.Section, new Span(20, 10), "b text"); 15 | var c = new ParseItem(default(EditorConfigDocument), ItemType.Keyword, new Span(10, 10), "a text"); 16 | 17 | Assert.IsTrue(a == c); 18 | Assert.IsFalse(a != c); 19 | Assert.IsTrue(a != b); 20 | Assert.IsFalse(a == b); 21 | Assert.IsTrue(a.GetHashCode() != b.GetHashCode()); 22 | Assert.IsTrue(a.Equals(a)); 23 | Assert.IsTrue(a.Equals(c)); 24 | Assert.IsFalse(a.Equals(b)); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Test/EditorConfigTest/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("EditorConfigTest")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("EditorConfigTest")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 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 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("d4005889-6273-4725-af75-8a2ee92fa639")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Test/EditorConfigTest/ValidationTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Threading.Tasks; 3 | using EditorConfig; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using Microsoft.VisualStudio.Text; 6 | 7 | namespace EditorConfigTest 8 | { 9 | [TestClass] 10 | public class ValidationTest 11 | { 12 | //[TestMethod, TestCategory("MEF")] 13 | //public async Task ValidateSeverity() 14 | //{ 15 | // EditorConfigPackage.ValidationOptions = new ValidationOptions(); 16 | // ITextBuffer buffer = Mef.CreateTextBuffer(Samples.SeveritySimple); 17 | // var doc = EditorConfigDocument.FromTextBuffer(buffer); 18 | // var validator = EditorConfigValidator.FromDocument(doc); 19 | 20 | // await validator.RequestValidationAsync(true); 21 | 22 | // await Task.Delay(1000); 23 | 24 | // Assert.IsTrue(doc.ParseItems[2].HasErrors); 25 | //} 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Test/EditorConfigTest/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2017 2 | 3 | install: 4 | - ps: (new-object Net.WebClient).DownloadString("https://raw.github.com/madskristensen/ExtensionScripts/master/AppVeyor/vsix.ps1") | iex 5 | 6 | before_build: 7 | - ps: Vsix-IncrementVsixVersion | Vsix-UpdateBuildVersion 8 | - ps: Vsix-TokenReplacement src\source.extension.cs 'Version = "([0-9\\.]+)"' 'Version = "{version}"' 9 | 10 | build_script: 11 | - nuget restore -Verbosity quiet 12 | - msbuild /p:configuration=Release /p:DeployExtension=false /p:ZipPackageCompressionLevel=normal /v:m 13 | 14 | test: 15 | categories: 16 | except: 17 | - MEF 18 | 19 | after_test: 20 | - ps: Vsix-PushArtifacts | Vsix-PublishToGallery 21 | -------------------------------------------------------------------------------- /art/classification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/classification.png -------------------------------------------------------------------------------- /art/context-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/context-menu.png -------------------------------------------------------------------------------- /art/csharp-analyzers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/csharp-analyzers.png -------------------------------------------------------------------------------- /art/editor-context-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/editor-context-menu.png -------------------------------------------------------------------------------- /art/formatting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/formatting.png -------------------------------------------------------------------------------- /art/inheritance-visualizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/inheritance-visualizer.png -------------------------------------------------------------------------------- /art/keyword-intellisense.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/keyword-intellisense.png -------------------------------------------------------------------------------- /art/light-bulb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/light-bulb.png -------------------------------------------------------------------------------- /art/navigation-dropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/navigation-dropdown.png -------------------------------------------------------------------------------- /art/quick-info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/quick-info.png -------------------------------------------------------------------------------- /art/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/settings.png -------------------------------------------------------------------------------- /art/snippets-context-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/snippets-context-menu.png -------------------------------------------------------------------------------- /art/snippets-expansion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/snippets-expansion.png -------------------------------------------------------------------------------- /art/suppress-comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/suppress-comment.png -------------------------------------------------------------------------------- /art/suppress-errorlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/suppress-errorlist.png -------------------------------------------------------------------------------- /art/suppress_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/suppress_error.png -------------------------------------------------------------------------------- /art/validation-duplicates-parent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/validation-duplicates-parent.png -------------------------------------------------------------------------------- /art/validation-duplicates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/validation-duplicates.png -------------------------------------------------------------------------------- /art/validation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/validation.png -------------------------------------------------------------------------------- /art/value-intellisense.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/art/value-intellisense.png -------------------------------------------------------------------------------- /lib/Microsoft.VisualStudio.Platform.VSEditor.Interop.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/lib/Microsoft.VisualStudio.Platform.VSEditor.Interop.dll -------------------------------------------------------------------------------- /lib/Microsoft.VisualStudio.Platform.VSEditor.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/lib/Microsoft.VisualStudio.Platform.VSEditor.dll -------------------------------------------------------------------------------- /lib/Microsoft.VisualStudio.Telemetry.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/lib/Microsoft.VisualStudio.Telemetry.dll -------------------------------------------------------------------------------- /lib/Microsoft.VisualStudio.Text.Internal.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/lib/Microsoft.VisualStudio.Text.Internal.dll -------------------------------------------------------------------------------- /src/Adornments/InheritanceAdornmentProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Text; 2 | using Microsoft.VisualStudio.Text.Editor; 3 | using Microsoft.VisualStudio.Utilities; 4 | using System.ComponentModel.Composition; 5 | 6 | namespace EditorConfig 7 | { 8 | [Export(typeof(IWpfTextViewCreationListener))] 9 | [ContentType(Constants.LanguageName)] 10 | [TextViewRole(PredefinedTextViewRoles.PrimaryDocument)] 11 | class AdornmentProvider : IWpfTextViewCreationListener 12 | { 13 | [Import] 14 | public ITextDocumentFactoryService DocumentService { get; set; } 15 | 16 | public void TextViewCreated(IWpfTextView textView) 17 | { 18 | if (DocumentService.TryGetTextDocument(textView.TextBuffer, out ITextDocument doc)) 19 | { 20 | textView.Properties.GetOrCreateSingletonProperty(() => new InheritanceAdornment(textView, doc)); 21 | } 22 | } 23 | } 24 | 25 | class InheritanceAdornmentLayer 26 | { 27 | public const string LayerName = "EditorConfig Inheritance Layer"; 28 | 29 | [Export(typeof(AdornmentLayerDefinition))] 30 | [Name(LayerName)] 31 | [Order(Before = PredefinedAdornmentLayers.Caret)] 32 | public AdornmentLayerDefinition editorAdornmentLayer = null; 33 | } 34 | } -------------------------------------------------------------------------------- /src/BraceCompletion/BraceCompletionContext.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using Microsoft.VisualStudio.Text.BraceCompletion; 3 | 4 | namespace EditorConfig 5 | { 6 | [Export(typeof(IBraceCompletionContext))] 7 | internal class BraceCompletionContext : IBraceCompletionContext 8 | { 9 | public bool AllowOverType(IBraceCompletionSession session) 10 | { 11 | return true; 12 | } 13 | 14 | public void Finish(IBraceCompletionSession session) 15 | { 16 | } 17 | 18 | public void OnReturn(IBraceCompletionSession session) 19 | { 20 | } 21 | 22 | public void Start(IBraceCompletionSession session) 23 | { 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/BraceCompletion/BraceCompletionContextProvider.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using System.Diagnostics; 3 | using Microsoft.VisualStudio.Text; 4 | using Microsoft.VisualStudio.Text.BraceCompletion; 5 | using Microsoft.VisualStudio.Text.Editor; 6 | using Microsoft.VisualStudio.Utilities; 7 | using Microsoft.VisualStudio.Text.Classification; 8 | using Microsoft.VisualStudio.Language.StandardClassification; 9 | using System.Collections.Generic; 10 | 11 | namespace EditorConfig 12 | { 13 | [Export(typeof(IBraceCompletionContextProvider))] 14 | [BracePair('(', ')')] 15 | [BracePair('[', ']')] 16 | [BracePair('{', '}')] 17 | [ContentType(Constants.LanguageName)] 18 | internal sealed class BraceCompletionContextProvider : IBraceCompletionContextProvider 19 | { 20 | [Import] 21 | IClassifierAggregatorService ClassifierService { get; set; } 22 | 23 | public bool TryCreateContext(ITextView textView, SnapshotPoint openingPoint, char openingBrace, char closingBrace, out IBraceCompletionContext context) 24 | { 25 | if (IsValidBraceCompletionContext(openingPoint)) 26 | { 27 | context = new BraceCompletionContext(); 28 | return true; 29 | } 30 | else 31 | { 32 | context = null; 33 | return false; 34 | } 35 | } 36 | 37 | private bool IsValidBraceCompletionContext(SnapshotPoint openingPoint) 38 | { 39 | Debug.Assert(openingPoint.Position >= 0, "SnapshotPoint.Position should always be zero or positive."); 40 | 41 | if (openingPoint.Position > 0) 42 | { 43 | IList classificationSpans = ClassifierService.GetClassifier(openingPoint.Snapshot.TextBuffer) 44 | .GetClassificationSpans(new SnapshotSpan(openingPoint - 1, 1)); 45 | 46 | foreach (ClassificationSpan span in classificationSpans) 47 | { 48 | if (span.ClassificationType.IsOfType(PredefinedClassificationTypeNames.Comment)) 49 | { 50 | return false; 51 | } 52 | if (span.ClassificationType.IsOfType(PredefinedClassificationTypeNames.String)) 53 | { 54 | return false; 55 | } 56 | } 57 | } 58 | return true; 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /src/BraceCompletion/BraceMatchingTaggerProvider.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using Microsoft.VisualStudio.Text; 3 | using Microsoft.VisualStudio.Text.Editor; 4 | using Microsoft.VisualStudio.Text.Tagging; 5 | using Microsoft.VisualStudio.Utilities; 6 | 7 | namespace EditorConfig 8 | { 9 | [Export(typeof(IViewTaggerProvider))] 10 | [ContentType(Constants.LanguageName)] 11 | [TagType(typeof(TextMarkerTag))] 12 | class BraceMatchingTaggerProvider : IViewTaggerProvider 13 | { 14 | public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag 15 | { 16 | if (!EditorConfigPackage.Language.Preferences.EnableShowMatchingBrace) 17 | return null; 18 | 19 | //provide highlighting only on the top-level buffer 20 | if (textView.TextBuffer != buffer) 21 | return null; 22 | 23 | return new BraceMatchingTagger(textView, buffer) as ITagger; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Classifier/EditorConfigClassifier.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Language.StandardClassification; 2 | using Microsoft.VisualStudio.Text; 3 | using Microsoft.VisualStudio.Text.Classification; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace EditorConfig 8 | { 9 | internal class EditorConfigClassifier : IClassifier 10 | { 11 | private static Dictionary _map; 12 | private EditorConfigDocument _document; 13 | private ITextBuffer _buffer; 14 | 15 | public EditorConfigClassifier(IClassificationTypeRegistryService registry, ITextBuffer buffer) 16 | { 17 | _map = _map ?? new Dictionary { 18 | { ItemType.Comment, registry.GetClassificationType(PredefinedClassificationTypeNames.Comment)}, 19 | { ItemType.Section, registry.GetClassificationType(PredefinedClassificationTypeNames.String)}, 20 | { ItemType.Keyword, registry.GetClassificationType(PredefinedClassificationTypeNames.Identifier)}, 21 | { ItemType.Value, registry.GetClassificationType(PredefinedClassificationTypeNames.Keyword)}, 22 | { ItemType.Severity, registry.GetClassificationType(PredefinedClassificationTypeNames.SymbolDefinition)}, 23 | { ItemType.Suppression, registry.GetClassificationType(PredefinedClassificationTypeNames.ExcludedCode)}, 24 | }; 25 | 26 | _buffer = buffer; 27 | _document = EditorConfigDocument.FromTextBuffer(buffer); 28 | } 29 | 30 | public IList GetClassificationSpans(SnapshotSpan span) 31 | { 32 | var list = new List(); 33 | 34 | if (_document.IsParsing) 35 | return list; 36 | 37 | IEnumerable parseItems = _document.ItemsInSpan(span); 38 | 39 | foreach (ParseItem item in parseItems) 40 | { 41 | if (_map.ContainsKey(item.ItemType)) 42 | { 43 | var snapshotSpan = new SnapshotSpan(span.Snapshot, item.Span); 44 | list.Add(new ClassificationSpan(snapshotSpan, _map[item.ItemType])); 45 | } 46 | } 47 | 48 | return list; 49 | } 50 | 51 | public event EventHandler ClassificationChanged 52 | { 53 | add { } 54 | remove { } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Classifier/EditorConfigProvider.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using Microsoft.VisualStudio.Text; 3 | using Microsoft.VisualStudio.Text.Classification; 4 | using Microsoft.VisualStudio.Utilities; 5 | 6 | namespace EditorConfig 7 | { 8 | [Export(typeof(IClassifierProvider))] 9 | [ContentType(Constants.LanguageName)] 10 | internal class EditorConfigProvider : IClassifierProvider 11 | { 12 | [Import] 13 | private IClassificationTypeRegistryService ClassificationRegistry { get; set; } 14 | 15 | public IClassifier GetClassifier(ITextBuffer buffer) 16 | { 17 | return buffer.Properties.GetOrCreateSingletonProperty(() => new EditorConfigClassifier(ClassificationRegistry, buffer)); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/CodeExpansions/Snippets/basicdocument.snippet: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 |
5 | Basic document 6 | basicdocument 7 | Code snippet for a basic .editorconfig document 8 | Mads Kristensen 9 | 10 | Expansion 11 | 12 |
13 | 14 | 15 | 24 | 25 | 26 |
27 |
-------------------------------------------------------------------------------- /src/CodeExpansions/Snippets/csharpstyle.snippet: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 |
5 | C# code style settings 6 | csharpstyle 7 | Code snippet for default C# code style settings 8 | Mads Kristensen 9 | 10 | Expansion 11 | 12 |
13 | 14 | 15 | 49 | 50 | 51 |
52 |
-------------------------------------------------------------------------------- /src/CodeExpansions/Snippets/dotnetstyle.snippet: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 |
5 | Dotnet code style settings 6 | netstyle 7 | Code snippet for default .NET code style settings 8 | Mads Kristensen 9 | 10 | Expansion 11 | 12 |
13 | 14 | 15 | 35 | 36 | 37 |
38 |
-------------------------------------------------------------------------------- /src/CommandTable.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // This file was generated by Extensibility Tools v1.10.188 4 | // 5 | // ------------------------------------------------------------------------------ 6 | namespace EditorConfig 7 | { 8 | using System; 9 | 10 | /// 11 | /// Helper class that exposes all GUIDs used across VS Package. 12 | /// 13 | internal sealed partial class PackageGuids 14 | { 15 | public const string guidEditorConfigPackageString = "6736c72d-7a27-49f0-9153-413ff47963ef"; 16 | public const string guidEditorFactoryString = "13cabf99-9eae-4ecc-a6f4-89f3ad54dc83"; 17 | public const string guidEditorConfigPackageCmdSetString = "13cabf99-9eae-4ecc-a6f4-89f3ad54dc83"; 18 | public const string guidWorkspaceExplorerToolWindowPackageCmdSetString = "cfb400f1-5c60-4f3c-856e-180d28def0b7"; 19 | public const string iconsString = "666770e6-562f-46d7-a555-3a0cdffe94d2"; 20 | public static Guid guidEditorConfigPackage = new Guid(guidEditorConfigPackageString); 21 | public static Guid guidEditorFactory = new Guid(guidEditorFactoryString); 22 | public static Guid guidEditorConfigPackageCmdSet = new Guid(guidEditorConfigPackageCmdSetString); 23 | public static Guid guidWorkspaceExplorerToolWindowPackageCmdSet = new Guid(guidWorkspaceExplorerToolWindowPackageCmdSetString); 24 | public static Guid icons = new Guid(iconsString); 25 | } 26 | /// 27 | /// Helper class that encapsulates all CommandIDs uses across VS Package. 28 | /// 29 | internal sealed partial class PackageIds 30 | { 31 | public const int AddGroup = 0x0001; 32 | public const int AddGroupAnyCode = 0x0002; 33 | public const int EditorContextMenu = 0x0003; 34 | public const int ErrorListGroup = 0x0004; 35 | public const int CreateEditorConfigFileId = 0x0100; 36 | public const int CreateEditorConfigFileAnyCodeId = 0x0200; 37 | public const int OpenSettingsId = 0x0300; 38 | public const int NavigateToParentId = 0x0400; 39 | public const int SuppressErrorId = 0x0500; 40 | public const int idmAddNew = 0x2200; 41 | public const int logo = 0x0001; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Commands/BaseCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.OLE.Interop; 2 | using System; 3 | 4 | namespace EditorConfig 5 | { 6 | abstract class BaseCommand : IOleCommandTarget 7 | { 8 | public IOleCommandTarget Next { get; set; } 9 | 10 | public abstract int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut); 11 | 12 | public abstract int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Commands/CreateEditorConfigFileAnyCode.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio; 2 | using Microsoft.VisualStudio.OLE.Interop; 3 | using Microsoft.VisualStudio.Shell; 4 | using Microsoft.VisualStudio.Workspace.VSIntegration.UI; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.ComponentModel.Composition; 8 | using System.IO; 9 | using System.Windows; 10 | 11 | namespace EditorConfig.Commands 12 | { 13 | [Export(typeof(INodeExtender))] 14 | public class CreateEditorConfigFileAnyCodeProvider : INodeExtender 15 | { 16 | private IWorkspaceCommandHandler _handler = new CreateEditorConfigFileAnyCode(); 17 | public IChildrenSource ProvideChildren(WorkspaceVisualNodeBase parentNode) => null; 18 | 19 | public IWorkspaceCommandHandler ProvideCommandHandler(WorkspaceVisualNodeBase parentNode) 20 | { 21 | if (parentNode is IFolderNode) 22 | { 23 | return _handler; 24 | } 25 | 26 | return null; 27 | } 28 | } 29 | 30 | public class CreateEditorConfigFileAnyCode : IWorkspaceCommandHandler 31 | { 32 | public bool IgnoreOnMultiselect => true; 33 | 34 | public int Priority => 100; 35 | 36 | public int Exec(List selection, Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) 37 | { 38 | ThreadHelper.ThrowIfNotOnUIThread(); 39 | 40 | if (IsSupportedCommand(pguidCmdGroup, nCmdID)) 41 | { 42 | if (selection.Count == 1 && selection[0] is IFolderNode folder) 43 | { 44 | string fileName = Path.Combine(folder.FullPath, Constants.FileName); 45 | 46 | if (File.Exists(fileName)) 47 | { 48 | MessageBox.Show(Resources.Text.EditorConfigFileAlreadyExist, Vsix.Name, MessageBoxButton.OK, MessageBoxImage.Information); 49 | } 50 | else 51 | { 52 | File.WriteAllText(fileName, Constants.DefaultFileContent); 53 | VsHelpers.OpenFile(fileName); 54 | } 55 | 56 | return VSConstants.S_OK; 57 | } 58 | } 59 | 60 | return (int)Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_NOTSUPPORTED; 61 | } 62 | 63 | public bool QueryStatus(List selection, Guid pguidCmdGroup, uint nCmdID, ref uint cmdf, ref string customTitle) 64 | { 65 | if (selection.Count != 1 || selection[0] is IFileNode) 66 | { 67 | return false; 68 | } 69 | 70 | if (IsSupportedCommand(pguidCmdGroup, nCmdID)) 71 | { 72 | cmdf = (uint)(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED); 73 | return true; 74 | } 75 | 76 | return selection[0].Parent.QueryStatus(pguidCmdGroup, nCmdID, ref cmdf, ref customTitle); 77 | } 78 | 79 | private static bool IsSupportedCommand(Guid pguidCmdGroup, uint nCmdID) 80 | { 81 | return pguidCmdGroup == PackageGuids.guidEditorConfigPackageCmdSet && nCmdID == PackageIds.CreateEditorConfigFileAnyCodeId; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Commands/F1Help.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio; 2 | using Microsoft.VisualStudio.OLE.Interop; 3 | using System; 4 | using Microsoft.VisualStudio.Shell; 5 | using Microsoft.VisualStudio.Text.Editor; 6 | using Microsoft.VisualStudio.TextManager.Interop; 7 | using System.Text.RegularExpressions; 8 | 9 | namespace EditorConfig 10 | { 11 | internal sealed class F1Help : BaseCommand 12 | { 13 | private Guid _commandGroup = typeof(VSConstants.VSStd97CmdID).GUID; 14 | private const uint _commandId = (uint)VSConstants.VSStd97CmdID.F1Help; 15 | private IVsTextView _vsTextView; 16 | private IWpfTextView _view; 17 | 18 | public F1Help(IVsTextView textViewAdapter, IWpfTextView view) 19 | { 20 | _vsTextView = textViewAdapter; 21 | _view = view; 22 | } 23 | 24 | public override int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) 25 | { 26 | if (pguidCmdGroup == _commandGroup && nCmdID == _commandId) 27 | { 28 | _vsTextView.GetCaretPos(out int line, out int column); 29 | string curLine = _view.TextSnapshot.GetLineFromLineNumber(line).GetText(); 30 | 31 | var pattern = new Regex(@"([\w .]+)="); 32 | if (pattern.IsMatch(curLine)) 33 | { 34 | GroupCollection groups = pattern.Match(curLine).Groups; 35 | string ruleName = groups[1].Value.ToString().Trim(); 36 | 37 | SchemaCatalog.TryGetKeyword(ruleName, out Keyword keyword); 38 | if (keyword != null && keyword.DocumentationLink != null) 39 | { 40 | VsShellUtilities.OpenSystemBrowser(keyword.DocumentationLink); 41 | } 42 | else 43 | { 44 | VsShellUtilities.OpenSystemBrowser(Constants.Homepage); 45 | } 46 | } 47 | else 48 | { 49 | VsShellUtilities.OpenSystemBrowser(Constants.Homepage); 50 | } 51 | return VSConstants.S_OK; 52 | } 53 | 54 | ThreadHelper.ThrowIfNotOnUIThread(); 55 | 56 | return Next.Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); 57 | } 58 | 59 | public override int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) 60 | { 61 | if (pguidCmdGroup == _commandGroup && prgCmds[0].cmdID == _commandId) 62 | { 63 | prgCmds[0].cmdf = (uint)OLECMDF.OLECMDF_ENABLED | (uint)OLECMDF.OLECMDF_SUPPORTED; 64 | return VSConstants.S_OK; 65 | } 66 | 67 | ThreadHelper.ThrowIfNotOnUIThread(); 68 | 69 | return Next.QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /src/Commands/HideDefaultCommands.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio; 2 | using Microsoft.VisualStudio.OLE.Interop; 3 | using Microsoft.VisualStudio.Shell; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace EditorConfig 8 | { 9 | internal sealed class HideDefaultCommands : BaseCommand 10 | { 11 | private static Guid _commandGuid = typeof(VSConstants.VSStd97CmdID).GUID; 12 | private static HashSet _commands = new HashSet 13 | { 14 | (uint)VSConstants.VSStd97CmdID.GotoDefn, 15 | (uint)VSConstants.VSStd97CmdID.GotoDecl, 16 | (uint)VSConstants.VSStd97CmdID.GotoRef, 17 | (uint)VSConstants.VSStd97CmdID.FindReferences, 18 | (uint)VSConstants.VSStd97CmdID.RunToCursor, 19 | }; 20 | 21 | public override int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) 22 | { 23 | ThreadHelper.ThrowIfNotOnUIThread(); 24 | 25 | return Next.Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); 26 | } 27 | 28 | public override int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) 29 | { 30 | if (pguidCmdGroup == _commandGuid && _commands.Contains(prgCmds[0].cmdID)) 31 | { 32 | prgCmds[0].cmdf = (uint)OLECMDF.OLECMDF_SUPPORTED | (uint)OLECMDF.OLECMDF_INVISIBLE; 33 | return VSConstants.S_OK; 34 | } 35 | 36 | ThreadHelper.ThrowIfNotOnUIThread(); 37 | 38 | return Next.QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/Commands/NavigateToParent.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio; 2 | using Microsoft.VisualStudio.OLE.Interop; 3 | using Microsoft.VisualStudio.Shell; 4 | using Microsoft.VisualStudio.Shell.Interop; 5 | using Microsoft.VisualStudio.Text; 6 | using System; 7 | 8 | namespace EditorConfig 9 | { 10 | internal sealed class NavigateToParent : BaseCommand 11 | { 12 | private Guid _commandGroup = PackageGuids.guidEditorConfigPackageCmdSet; 13 | private const uint _commandId = PackageIds.NavigateToParentId; 14 | private ITextBuffer _buffer; 15 | 16 | public NavigateToParent(ITextBuffer buffer) 17 | { 18 | _buffer = buffer; 19 | } 20 | 21 | public override int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) 22 | { 23 | ThreadHelper.ThrowIfNotOnUIThread(); 24 | 25 | if (pguidCmdGroup == _commandGroup && nCmdID == _commandId) 26 | { 27 | var document = EditorConfigDocument.FromTextBuffer(_buffer); 28 | EditorConfigDocument parent = document?.Parent; 29 | 30 | if (parent != null) 31 | { 32 | VsHelpers.PreviewDocument(parent.FileName); 33 | } 34 | else 35 | { 36 | var statusBar = Package.GetGlobalService(typeof(SVsStatusbar)) as IVsStatusbar; 37 | statusBar.IsFrozen(out int frozen); 38 | 39 | if (frozen == 0) 40 | { 41 | statusBar.SetText("This is a root document with no inheritance"); 42 | } 43 | } 44 | 45 | return VSConstants.S_OK; 46 | } 47 | 48 | return Next.Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); 49 | } 50 | 51 | 52 | public override int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) 53 | { 54 | if (pguidCmdGroup == _commandGroup && prgCmds[0].cmdID == _commandId) 55 | { 56 | var document = EditorConfigDocument.FromTextBuffer(_buffer); 57 | EditorConfigDocument parent = document?.Parent; 58 | 59 | if (parent != null) 60 | { 61 | prgCmds[0].cmdf = (uint)OLECMDF.OLECMDF_ENABLED | (uint)OLECMDF.OLECMDF_SUPPORTED; 62 | return VSConstants.S_OK; 63 | } 64 | 65 | return VSConstants.S_OK; 66 | } 67 | 68 | ThreadHelper.ThrowIfNotOnUIThread(); 69 | 70 | return Next.QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/Commands/OpenSettings.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio; 2 | using Microsoft.VisualStudio.Shell; 3 | using System; 4 | using System.ComponentModel.Design; 5 | 6 | namespace EditorConfig 7 | { 8 | internal sealed class OpenSettings 9 | { 10 | private readonly Package _package; 11 | private readonly OleMenuCommandService _commandService; 12 | 13 | private OpenSettings(Package package, OleMenuCommandService commandService) 14 | { 15 | _package = package ?? throw new ArgumentNullException(nameof(package)); 16 | _commandService = commandService ?? throw new ArgumentNullException(nameof(commandService)); 17 | 18 | var cmdId = new CommandID(PackageGuids.guidEditorConfigPackageCmdSet, PackageIds.OpenSettingsId); 19 | var menuItem = new OleMenuCommand(Execute, cmdId); 20 | menuItem.BeforeQueryStatus += BeforeQueryStatus; 21 | commandService.AddCommand(menuItem); 22 | } 23 | 24 | private void BeforeQueryStatus(object sender, EventArgs e) 25 | { 26 | var button = (OleMenuCommand)sender; 27 | button.Enabled = button.Visible = VsHelpers.DTE.ActiveDocument?.Language == Constants.LanguageName; 28 | } 29 | 30 | public static OpenSettings Instance 31 | { 32 | get; 33 | private set; 34 | } 35 | 36 | private IServiceProvider ServiceProvider 37 | { 38 | get { return _package; } 39 | } 40 | 41 | public static void Initialize(Package package, OleMenuCommandService commandService) 42 | { 43 | Instance = new OpenSettings(package, commandService); 44 | } 45 | 46 | private void Execute(object sender, EventArgs e) 47 | { 48 | Guid cmdGroup = typeof(VSConstants.VSStd97CmdID).GUID; 49 | var cmd = new CommandID(cmdGroup, VSConstants.cmdidToolsOptions); 50 | _commandService.GlobalInvoke(cmd, typeof(FormatterOptions).GUID.ToString()); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Completion/CompletionElementProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Language.Intellisense; 2 | using Microsoft.VisualStudio.Utilities; 3 | using System.ComponentModel.Composition; 4 | using System.Windows; 5 | 6 | namespace EditorConfig 7 | { 8 | [Export(typeof(IUIElementProvider))] 9 | [Name("EditorConfigCompletionTooltipCustomization")] 10 | [ContentType(Constants.LanguageName)] 11 | public class CompletionElementProvider : IUIElementProvider 12 | { 13 | public UIElement GetUIElement(Completion itemToRender, ICompletionSession context, UIElementType elementType) 14 | { 15 | if (elementType == UIElementType.Tooltip && 16 | itemToRender.Properties.TryGetProperty("item", out ITooltip item) && 17 | !string.IsNullOrEmpty(item.Description)) 18 | { 19 | return new Shared.EditorTooltip(item); 20 | } 21 | 22 | return null; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Completion/CompletionOptions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Shell; 2 | using System.ComponentModel; 3 | 4 | namespace EditorConfig 5 | { 6 | public class CompletionOptions : DialogPage 7 | { 8 | // General 9 | private const string _intellisense = "Intellisense"; 10 | 11 | [Category(_intellisense)] 12 | [DisplayName("Auto-insert delimiters")] 13 | [Description("This will automatically insert \"=\" and \":\" characters on commit.")] 14 | [DefaultValue(true)] 15 | public bool AutoInsertDelimiters { get; set; } = true; 16 | 17 | [Category(_intellisense)] 18 | [DisplayName("Show undocumented properties")] 19 | [Description("This will show undocumented properties in Intellisense.")] 20 | [DefaultValue(false)] 21 | public bool ShowHiddenKeywords { get; set; } 22 | 23 | public override void SaveSettingsToStorage() 24 | { 25 | Telemetry.TrackOperation("CompletionOptionsSaved"); 26 | base.SaveSettingsToStorage(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Completion/CompletionSourceProvider.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using Microsoft.VisualStudio.Language.Intellisense; 3 | using Microsoft.VisualStudio.Text; 4 | using Microsoft.VisualStudio.Text.Classification; 5 | using Microsoft.VisualStudio.Text.Operations; 6 | using Microsoft.VisualStudio.Utilities; 7 | 8 | namespace EditorConfig 9 | { 10 | [Export(typeof(ICompletionSourceProvider))] 11 | [ContentType(Constants.LanguageName)] 12 | [Name("Editor Config")] 13 | public class EditorConfigCompletionSourceProvider : ICompletionSourceProvider 14 | { 15 | [Import] 16 | ITextStructureNavigatorSelectorService NavigatorService { get; set; } 17 | 18 | public ICompletionSource TryCreateCompletionSource(ITextBuffer textBuffer) 19 | { 20 | return textBuffer.Properties.GetOrCreateSingletonProperty(() => new EditorConfigCompletionSource(textBuffer, NavigatorService)); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace EditorConfig 2 | { 3 | public class Constants 4 | { 5 | public const string LanguageName = "EditorConfig"; 6 | public const string FileName = ".editorconfig"; 7 | public const string Homepage = "http://editorconfig.org"; 8 | public const string DefaultFileContent = "[*]\r\nend_of_line = crlf\r\n\r\n[*.xml]\r\nindent_style = space"; 9 | public const string HelpLink = "https://github.com/madskristensen/EditorConfigLanguage/wiki/Error-codes#{0}"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/DragDrop/EditorConfigDropHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Text.Editor; 2 | using Microsoft.VisualStudio.Text.Editor.DragDrop; 3 | using Microsoft.VisualStudio.Text.Operations; 4 | using System; 5 | using System.IO; 6 | using System.Windows; 7 | using Microsoft.VisualStudio.Text; 8 | using System.Collections.Specialized; 9 | 10 | namespace EditorConfig 11 | { 12 | internal class EditorConfigDropHandler : IDropHandler 13 | { 14 | private IWpfTextView _view; 15 | private ITextBufferUndoManager _undoManager; 16 | private string _ext; 17 | 18 | const string _template = "[*{0}]"; 19 | 20 | public EditorConfigDropHandler(IWpfTextView view, ITextBufferUndoManager undoManager) 21 | { 22 | _view = view; 23 | _undoManager = undoManager; 24 | } 25 | 26 | public DragDropPointerEffects HandleDataDropped(DragDropInfo dragDropInfo) 27 | { 28 | try 29 | { 30 | 31 | SnapshotPoint position = dragDropInfo.VirtualBufferPosition.Position; 32 | string header = string.Format(_template, _ext); 33 | 34 | ITextSnapshotLine line = _view.TextBuffer.CurrentSnapshot.GetLineFromPosition(position); 35 | 36 | if (!line.Extent.IsEmpty) 37 | header = Environment.NewLine + header; 38 | 39 | using (ITextUndoTransaction transaction = _undoManager.TextBufferUndoHistory.CreateTransaction($"Dragged {_ext}")) 40 | using (ITextEdit edit = _view.TextBuffer.CreateEdit()) 41 | { 42 | edit.Insert(position, header); 43 | edit.Apply(); 44 | transaction.Complete(); 45 | } 46 | 47 | Telemetry.TrackUserTask("FileDragged"); 48 | } 49 | catch (Exception ex) 50 | { 51 | Telemetry.TrackException("DragDrop", ex); 52 | } 53 | 54 | return DragDropPointerEffects.Copy; 55 | } 56 | 57 | public void HandleDragCanceled() 58 | { } 59 | 60 | public DragDropPointerEffects HandleDragStarted(DragDropInfo dragDropInfo) 61 | { 62 | return DragDropPointerEffects.All; 63 | } 64 | 65 | public DragDropPointerEffects HandleDraggingOver(DragDropInfo dragDropInfo) 66 | { 67 | return DragDropPointerEffects.All; 68 | } 69 | 70 | public bool IsDropEnabled(DragDropInfo dragDropInfo) 71 | { 72 | string draggedFileName = GetDraggedFilename(dragDropInfo); 73 | _ext = Path.GetExtension(draggedFileName); 74 | 75 | return !string.IsNullOrWhiteSpace(_ext); 76 | } 77 | 78 | private static string GetDraggedFilename(DragDropInfo info) 79 | { 80 | var data = new DataObject(info.Data); 81 | 82 | if (info.Data.GetDataPresent("FileDrop")) 83 | { 84 | // The drag and drop operation came from the file system 85 | StringCollection files = data.GetFileDropList(); 86 | 87 | if (files != null && files.Count == 1) 88 | { 89 | return files[0]; 90 | } 91 | } 92 | else if (info.Data.GetDataPresent("CF_VSSTGPROJECTITEMS")) 93 | { 94 | // The drag and drop operation came from the VS solution explorer 95 | return data.GetText(); 96 | } 97 | 98 | return null; 99 | } 100 | } 101 | } -------------------------------------------------------------------------------- /src/DragDrop/EditorConfigDropHandlerProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Text.Editor; 2 | using Microsoft.VisualStudio.Text.Editor.DragDrop; 3 | using Microsoft.VisualStudio.Text.Operations; 4 | using Microsoft.VisualStudio.Utilities; 5 | using System.ComponentModel.Composition; 6 | 7 | namespace EditorConfig 8 | { 9 | [Export(typeof(IDropHandlerProvider))] 10 | [DropFormat("CF_VSSTGPROJECTITEMS")] 11 | [DropFormat("FileDrop")] 12 | [Name("EditorConfigDropHandler")] 13 | [ContentType(Constants.LanguageName)] 14 | [Order(Before = "DefaultFileDropHandler")] 15 | internal class EditorConfigDropHandlerProvider : IDropHandlerProvider 16 | { 17 | [Import(typeof(ITextBufferUndoManagerProvider))] 18 | private ITextBufferUndoManagerProvider UndoProvider { get; set; } 19 | 20 | public IDropHandler GetAssociatedDropHandler(IWpfTextView view) 21 | { 22 | ITextBufferUndoManager undoManager = UndoProvider.GetTextBufferUndoManager(view.TextBuffer); 23 | 24 | return view.Properties.GetOrCreateSingletonProperty(() => new EditorConfigDropHandler(view, undoManager)); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/EditorConfigPackage.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio; 2 | using Microsoft.VisualStudio.Shell; 3 | using Microsoft.VisualStudio.Shell.Interop; 4 | using System; 5 | using System.ComponentModel.Design; 6 | using System.Runtime.InteropServices; 7 | using System.Threading; 8 | using Task = System.Threading.Tasks.Task; 9 | 10 | namespace EditorConfig 11 | { 12 | [Guid(PackageGuids.guidEditorConfigPackageString)] 13 | [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] 14 | [InstalledProductRegistration("#110", "#112", Vsix.Version, IconResourceID = 400)] 15 | 16 | [ProvideLanguageService(typeof(EditorConfigLanguage), Constants.LanguageName, 101, ShowCompletion = true, EnableAsyncCompletion = true, EnableAdvancedMembersOption = true, HideAdvancedMembersByDefault = false, QuickInfo = true, ShowDropDownOptions = true, DefaultToInsertSpaces = true, EnableCommenting = true, AutoOutlining = true, EnableLineNumbers = true, MatchBraces = true, MatchBracesAtCaret = true, ShowMatchingBrace = true)] 17 | [ProvideLanguageExtension(typeof(EditorConfigLanguage), Constants.FileName)] 18 | [ProvideLanguageEditorOptionPage(typeof(FormatterOptions), Constants.LanguageName, null, "Formatting", "#101", new[] { "editorconfig", "formatting" })] 19 | [ProvideLanguageEditorOptionPage(typeof(ValidationOptions), Constants.LanguageName, null, "Validation", "#102", new[] { "editorconfig", "validation" })] 20 | [ProvideLanguageEditorOptionPage(typeof(CompletionOptions), Constants.LanguageName, null, "Intellisense", "#103", new[] { "editorconfig", "intellisenes", "completion" })] 21 | [ProvideLanguageCodeExpansion(typeof(EditorConfigLanguage), Constants.LanguageName, 0, Constants.LanguageName, null, SearchPaths = @"$PackageFolder$\CodeExpansions\Snippets")] 22 | [ProvideEditorFactory(typeof(EditorFactory), 110, CommonPhysicalViewAttributes = (int)__VSPHYSICALVIEWATTRIBUTES.PVA_SupportsPreview, TrustLevel = __VSEDITORTRUSTLEVEL.ETL_AlwaysTrusted)] 23 | [ProvideEditorLogicalView(typeof(EditorFactory), VSConstants.LOGVIEWID.TextView_string, IsTrusted = true)] 24 | 25 | [ProvideEditorExtension(typeof(EditorFactory), Constants.FileName, 1000)] 26 | [ProvideBraceCompletion(Constants.LanguageName)] 27 | [ProvideMenuResource("Menus.ctmenu", 1)] 28 | public sealed class EditorConfigPackage : AsyncPackage 29 | { 30 | public static EditorConfigLanguage Language 31 | { 32 | get; 33 | private set; 34 | } 35 | 36 | public static FormatterOptions FormatterOptions 37 | { 38 | get; 39 | private set; 40 | } 41 | 42 | public static ValidationOptions ValidationOptions 43 | { 44 | get; 45 | private set; 46 | } 47 | 48 | public static CompletionOptions CompletionOptions 49 | { 50 | get; 51 | private set; 52 | } 53 | 54 | protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) 55 | { 56 | Language = new EditorConfigLanguage(this); 57 | FormatterOptions = (FormatterOptions)GetDialogPage(typeof(FormatterOptions)); 58 | ValidationOptions = (ValidationOptions)GetDialogPage(typeof(ValidationOptions)); 59 | CompletionOptions = (CompletionOptions)GetDialogPage(typeof(CompletionOptions)); 60 | 61 | var serviceContainer = this as IServiceContainer; 62 | serviceContainer.AddService(typeof(EditorConfigLanguage), Language, true); 63 | 64 | var editorFactory = new EditorFactory(this, typeof(EditorConfigLanguage).GUID); 65 | RegisterEditorFactory(editorFactory); 66 | 67 | if (await GetServiceAsync(typeof(IMenuCommandService)) is OleMenuCommandService commandService) 68 | { 69 | CreateEditorConfigFile.Initialize(this, commandService); 70 | OpenSettings.Initialize(this, commandService); 71 | SuppressError.Initialize(this, commandService); 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Formatting/FormatterCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio; 2 | using Microsoft.VisualStudio.OLE.Interop; 3 | using Microsoft.VisualStudio.Shell; 4 | using Microsoft.VisualStudio.Text.Editor; 5 | using Microsoft.VisualStudio.Text.Operations; 6 | using System; 7 | 8 | namespace EditorConfig 9 | { 10 | internal sealed class FormatterCommand : BaseCommand 11 | { 12 | private ITextBufferUndoManager _undoManager; 13 | private IWpfTextView _view; 14 | 15 | public FormatterCommand(IWpfTextView textView, ITextBufferUndoManager undoManager) 16 | { 17 | _view = textView; 18 | _undoManager = undoManager; 19 | } 20 | 21 | public override int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) 22 | { 23 | if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.FORMATDOCUMENT) 24 | { 25 | FormatDocument(); 26 | return VSConstants.S_OK; 27 | } 28 | 29 | ThreadHelper.ThrowIfNotOnUIThread(); 30 | 31 | return Next.Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); 32 | } 33 | 34 | private void FormatDocument() 35 | { 36 | using (ITextUndoTransaction transaction = _undoManager.TextBufferUndoHistory.CreateTransaction(Resources.Text.FormatDocument)) 37 | { 38 | EditorConfigFormatter formatter = _view.Properties.GetOrCreateSingletonProperty(() => new EditorConfigFormatter(_view.TextBuffer)); 39 | bool changed = formatter.Format(); 40 | 41 | if (changed) 42 | transaction.Complete(); 43 | else 44 | transaction.Cancel(); 45 | } 46 | } 47 | 48 | public override int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) 49 | { 50 | if (pguidCmdGroup == VSConstants.VSStd2K && prgCmds[0].cmdID == (uint)VSConstants.VSStd2KCmdID.FORMATDOCUMENT) 51 | { 52 | prgCmds[0].cmdf = (uint)OLECMDF.OLECMDF_ENABLED | (uint)OLECMDF.OLECMDF_SUPPORTED; 53 | return VSConstants.S_OK; 54 | } 55 | 56 | ThreadHelper.ThrowIfNotOnUIThread(); 57 | 58 | return Next.QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /src/Formatting/FormatterOptions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Shell; 2 | using System; 3 | using System.ComponentModel; 4 | 5 | namespace EditorConfig 6 | { 7 | public class FormatterOptions : DialogPage 8 | { 9 | // Formatting 10 | private const string _properties = "Properties"; 11 | 12 | [Category(_properties)] 13 | [DisplayName("Align values mode")] 14 | [Description("Determins if the = character should be aligned by section, document or not at all")] 15 | [DefaultValue(FormattingType.Section)] 16 | [TypeConverter(typeof(EnumConverter))] 17 | public FormattingType FormattingType { get; set; } = FormattingType.Section; 18 | 19 | [Category(_properties)] 20 | [DisplayName("Spaces before =")] 21 | [Description("Space characters to add in front of the = character")] 22 | [DefaultValue(1)] 23 | public int SpacesBeforeEquals { get; set; } = 1; 24 | 25 | [Category(_properties)] 26 | [DisplayName("Spaces after =")] 27 | [Description("Space characters to add after the = character")] 28 | [DefaultValue(1)] 29 | public int SpacesAfterEquals { get; set; } = 1; 30 | 31 | // Severity 32 | private const string _severity = "Severity"; 33 | 34 | [Category(_severity)] 35 | [DisplayName("Spaces before :")] 36 | [Description("[C# only] Space characters to add in front of the : character used to specify Severity")] 37 | [DefaultValue(1)] 38 | public int SpacesBeforeColon { get; set; } = 1; 39 | 40 | [Category(_severity)] 41 | [DisplayName("Spaces after :")] 42 | [Description("[C# only] Space characters to add after the : character used to specify Severity")] 43 | [DefaultValue(1)] 44 | public int SpacesAfterColon { get; set; } = 1; 45 | 46 | public override void SaveSettingsToStorage() 47 | { 48 | Telemetry.TrackOperation("FormattingOptionsSaved"); 49 | base.SaveSettingsToStorage(); 50 | Saved?.Invoke(this, EventArgs.Empty); 51 | } 52 | 53 | public static event EventHandler Saved; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Formatting/FormattingType.cs: -------------------------------------------------------------------------------- 1 | namespace EditorConfig 2 | { 3 | public enum FormattingType 4 | { 5 | None, 6 | Section, 7 | Document 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/LanguageService/Colorizer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Package; 2 | using Microsoft.VisualStudio.TextManager.Interop; 3 | 4 | namespace EditorConfig 5 | { 6 | public class EditorConfigColorizer : Colorizer 7 | { 8 | public EditorConfigColorizer(LanguageService svc, IVsTextLines buffer, IScanner scanner) : 9 | base(svc, buffer, scanner) 10 | { } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/LanguageService/ContentTypes.cs: -------------------------------------------------------------------------------- 1 | //using System.ComponentModel.Composition; 2 | //using Microsoft.VisualStudio.Utilities; 3 | 4 | //namespace EditorConfig 5 | //{ 6 | // public class ContentTypes 7 | // { 8 | // [Export(typeof(ContentTypes))] 9 | // [Name(Constants.LanguageName)] 10 | // [BaseDefinition("text")] 11 | // public ContentTypes IEditorConfigContentType { get; set; } 12 | // } 13 | //} 14 | -------------------------------------------------------------------------------- /src/LanguageService/LanguageService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Package; 2 | using Microsoft.VisualStudio.Shell; 3 | using Microsoft.VisualStudio.TextManager.Interop; 4 | using System; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace EditorConfig 8 | { 9 | [Guid(LanguageGuid)] 10 | public class EditorConfigLanguage : LanguageService 11 | { 12 | public const string LanguageGuid = "f99a05b5-311b-4772-92fc-6441a78ca26f"; 13 | private LanguagePreferences preferences = null; 14 | 15 | public EditorConfigLanguage(object site) 16 | { 17 | ThreadHelper.ThrowIfNotOnUIThread(); 18 | 19 | SetSite(site); 20 | } 21 | 22 | public override Source CreateSource(IVsTextLines buffer) 23 | { 24 | return new EditorConfigSource(this, buffer, new EditorConfigColorizer(this, buffer, null)); 25 | } 26 | 27 | public override TypeAndMemberDropdownBars CreateDropDownHelper(IVsTextView forView) 28 | { 29 | if (Preferences.ShowNavigationBar) 30 | return new DropDownBars(this, forView); 31 | 32 | return null; 33 | } 34 | 35 | public override LanguagePreferences GetLanguagePreferences() 36 | { 37 | if (preferences == null) 38 | { 39 | preferences = new LanguagePreferences(Site, typeof(EditorConfigLanguage).GUID, Name); 40 | 41 | if (preferences != null) 42 | { 43 | preferences.Init(); 44 | 45 | preferences.EnableCodeSense = true; 46 | preferences.EnableMatchBraces = true; 47 | preferences.EnableMatchBracesAtCaret = true; 48 | preferences.EnableShowMatchingBrace = true; 49 | preferences.EnableCommenting = true; 50 | preferences.HighlightMatchingBraceFlags = _HighlightMatchingBraceFlags.HMB_USERECTANGLEBRACES; 51 | preferences.LineNumbers = true; 52 | preferences.MaxErrorMessages = 100; 53 | preferences.AutoOutlining = true; 54 | preferences.MaxRegionTime = 2000; 55 | preferences.ShowNavigationBar = true; 56 | preferences.InsertTabs = false; 57 | preferences.IndentSize = 2; 58 | preferences.ShowNavigationBar = true; 59 | preferences.EnableAsyncCompletion = true; 60 | 61 | preferences.WordWrap = false; 62 | preferences.WordWrapGlyphs = true; 63 | 64 | preferences.AutoListMembers = true; 65 | preferences.EnableQuickInfo = true; 66 | preferences.ParameterInformation = true; 67 | preferences.HideAdvancedMembers = false; 68 | } 69 | } 70 | 71 | return preferences; 72 | } 73 | 74 | public override IScanner GetScanner(IVsTextLines buffer) 75 | { 76 | return null; 77 | } 78 | 79 | public override AuthoringScope ParseSource(ParseRequest req) 80 | { 81 | return null; 82 | } 83 | 84 | public override string GetFormatFilterList() 85 | { 86 | return $"EditorConfig File (*{Constants.FileName})|*{Constants.FileName}"; 87 | } 88 | 89 | public override string Name => Constants.LanguageName; 90 | 91 | public sealed override void Dispose() 92 | { 93 | Dispose(true); 94 | GC.SuppressFinalize(this); 95 | } 96 | 97 | private void Dispose(bool dispose) 98 | { 99 | try 100 | { 101 | if (preferences != null) 102 | { 103 | preferences.Dispose(); 104 | preferences = null; 105 | } 106 | } 107 | finally 108 | { 109 | base.Dispose(); 110 | } 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/LanguageService/Source.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Package; 2 | using Microsoft.VisualStudio.TextManager.Interop; 3 | 4 | namespace EditorConfig 5 | { 6 | internal class EditorConfigSource : Source 7 | { 8 | public EditorConfigSource(LanguageService service, IVsTextLines textLines, Colorizer colorizer) 9 | : base(service, textLines, colorizer) 10 | { } 11 | 12 | public override CommentInfo GetCommentFormat() 13 | { 14 | return new CommentInfo 15 | { 16 | UseLineComments = true, 17 | LineStart = "#" 18 | }; 19 | } 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/Monikers.imagemanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Outlining/OutliningTagger.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Shell; 2 | using Microsoft.VisualStudio.Text; 3 | using Microsoft.VisualStudio.Text.Tagging; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using Task = System.Threading.Tasks.Task; 8 | 9 | namespace EditorConfig 10 | { 11 | internal sealed class OutliningTagger : ITagger 12 | { 13 | private readonly ITextBuffer _buffer; 14 | private ITextSnapshot _snapshot; 15 | private EditorConfigDocument _document; 16 | 17 | public OutliningTagger(ITextBuffer buffer) 18 | { 19 | _buffer = buffer; 20 | _snapshot = buffer.CurrentSnapshot; 21 | 22 | _document = EditorConfigDocument.FromTextBuffer(buffer); 23 | _document.Parsed += DocumentChanged; 24 | 25 | StartParsing(); 26 | } 27 | 28 | public List Regions { get; private set; } = new List(); 29 | 30 | public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) 31 | { 32 | if (spans.Count == 0 || !Regions.Any()) 33 | yield break; 34 | 35 | IEnumerable currentRegions = Regions; 36 | ITextSnapshot currentSnapshot = _snapshot; 37 | SnapshotSpan entire = new SnapshotSpan(spans[0].Start, spans[spans.Count - 1].End).TranslateTo(currentSnapshot, SpanTrackingMode.EdgeExclusive); 38 | int startLineNumber = entire.Start.GetContainingLine().LineNumber; 39 | int endLineNumber = entire.End.GetContainingLine().LineNumber; 40 | 41 | foreach (Region region in currentRegions) 42 | { 43 | if (region.StartLine <= endLineNumber && region.EndLine >= startLineNumber) 44 | { 45 | ITextSnapshotLine startLine = currentSnapshot.GetLineFromLineNumber(region.StartLine); 46 | string text = startLine.GetText(); 47 | string hover = entire.Snapshot.GetText(region.StartOffset, region.EndOffset - region.StartOffset); 48 | 49 | yield return new TagSpan( 50 | new SnapshotSpan(currentSnapshot, region.StartOffset, region.EndOffset - region.StartOffset), 51 | new OutliningRegionTag(false, false, text, hover)); 52 | } 53 | } 54 | } 55 | 56 | public event EventHandler TagsChanged; 57 | 58 | void DocumentChanged(object sender, EventArgs e) 59 | { 60 | StartParsing(); 61 | } 62 | 63 | private void StartParsing() 64 | { 65 | ThreadHelper.JoinableTaskFactory.StartOnIdle( 66 | () => 67 | { 68 | if (TagsChanged == null || _document.IsParsing) 69 | return Task.CompletedTask; 70 | 71 | Regions.Clear(); 72 | ReParse(); 73 | TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(new SnapshotSpan(_snapshot, 0, _snapshot.Length))); 74 | return Task.CompletedTask; 75 | }, 76 | VsTaskRunContext.UIThreadIdlePriority); 77 | } 78 | 79 | void ReParse() 80 | { 81 | ITextSnapshot newSnapshot = _buffer.CurrentSnapshot; 82 | var newRegions = new List(); 83 | 84 | foreach (Section section in _document.Sections) 85 | { 86 | ITextSnapshotLine startLine = newSnapshot.GetLineFromPosition(section.Span.Start); 87 | ITextSnapshotLine endLine = newSnapshot.GetLineFromPosition(section.Span.End); 88 | 89 | var region = new Region 90 | { 91 | StartLine = startLine.LineNumber, 92 | StartOffset = startLine.Start, 93 | EndLine = endLine.LineNumber, 94 | EndOffset = endLine.End 95 | }; 96 | 97 | newRegions.Add(region); 98 | } 99 | 100 | _snapshot = newSnapshot; 101 | Regions = newRegions.Where(line => line.StartLine != line.EndLine).ToList(); 102 | } 103 | } 104 | 105 | class Region 106 | { 107 | public int StartLine { get; set; } 108 | public int StartOffset { get; set; } 109 | public int EndLine { get; set; } 110 | public int EndOffset { get; set; } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Outlining/OutliningTaggerProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Text; 2 | using Microsoft.VisualStudio.Text.Tagging; 3 | using Microsoft.VisualStudio.Utilities; 4 | using System.ComponentModel.Composition; 5 | 6 | namespace EditorConfig 7 | { 8 | [Export(typeof(ITaggerProvider))] 9 | [TagType(typeof(IOutliningRegionTag))] 10 | [ContentType(Constants.LanguageName)] 11 | internal sealed class OutliningTaggerProvider : ITaggerProvider 12 | { 13 | public ITagger CreateTagger(ITextBuffer buffer) where T : ITag 14 | { 15 | return buffer.Properties.GetOrCreateSingletonProperty(() => new OutliningTagger(buffer)) as ITagger; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Parser/EditorConfigDocument.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Text; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace EditorConfig 7 | { 8 | /// A representation of the .editorconfig document. 9 | sealed partial class EditorConfigDocument : IDisposable 10 | { 11 | private EditorConfigDocument(ITextBuffer buffer) 12 | { 13 | TextBuffer = buffer; 14 | 15 | InitializeParser(); 16 | InitializeInheritance(); 17 | } 18 | 19 | /// The ITextBuffer associated with the document. 20 | public ITextBuffer TextBuffer { get; } 21 | 22 | /// A list of all the parse items in the document. 23 | public List ParseItems { get; private set; } = new List(); 24 | 25 | /// A list of all the sections in the document. 26 | public List
Sections { get; private set; } = new List
(); 27 | 28 | /// A list of all the properties in the root of the document. 29 | public List Properties { get; private set; } = new List(); 30 | 31 | /// A list of all the error suppressions in the document. 32 | public List Suppressions { get; private set; } = new List(); 33 | 34 | /// The root property of the document if one is specified 35 | public Property Root 36 | { 37 | get 38 | { 39 | return Properties.FirstOrDefault(p => p.Keyword.Text.Equals(SchemaCatalog.Root)); 40 | } 41 | } 42 | 43 | /// A list of all the sections in the document. 44 | public static EditorConfigDocument FromTextBuffer(ITextBuffer buffer) 45 | { 46 | return buffer.Properties.GetOrCreateSingletonProperty(() => new EditorConfigDocument(buffer)); 47 | } 48 | 49 | /// Returns all the parse items contained within the specified span. 50 | public IEnumerable ItemsInSpan(Span span) 51 | { 52 | return ParseItems?.Where(i => span.Contains(i.Span)); 53 | } 54 | 55 | /// Returns the ParseItem located at the specified position. 56 | public ParseItem ItemAtPosition(int position) 57 | { 58 | return ParseItems?.FirstOrDefault(p => p.Span.Contains(position - 1)); 59 | } 60 | 61 | /// Returns the Property located at the specified position. 62 | public Property PropertyAtPosition(int position) 63 | { 64 | foreach (Property property in Properties) 65 | { 66 | if (property.Span.Contains(position - 1)) 67 | return property; 68 | } 69 | 70 | foreach (Property property in Sections.SelectMany(s => s.Properties)) 71 | { 72 | if (property.Span.Contains(position - 1)) 73 | return property; 74 | } 75 | 76 | return null; 77 | } 78 | 79 | /// Returns a list of all rules included in the current or parent document(s). 80 | public List GetAllIncludedRules() 81 | { 82 | EditorConfigDocument curDoc = this; 83 | var rules = new List(); 84 | while (curDoc != null) 85 | { 86 | foreach (ParseItem parseItem in curDoc.ParseItems) 87 | { 88 | string parseItemStr = parseItem.Text; 89 | if (!rules.Contains(parseItemStr) && parseItem.ItemType == ItemType.Keyword) 90 | { 91 | rules.Add(parseItemStr); 92 | } 93 | } 94 | curDoc = curDoc.Parent; 95 | } 96 | return rules; 97 | } 98 | 99 | public void Dispose() 100 | { 101 | DisposeParser(); 102 | DisposeInheritance(); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/Parser/EditorConfigDocumentInheritance.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.ComponentModelHost; 2 | using Microsoft.VisualStudio.Shell; 3 | using Microsoft.VisualStudio.Text; 4 | using Microsoft.VisualStudio.Utilities; 5 | using System; 6 | using System.ComponentModel.Composition; 7 | using System.IO; 8 | 9 | namespace EditorConfig 10 | { 11 | public partial class EditorConfigDocument 12 | { 13 | private IContentType _contentType; 14 | private EditorConfigDocument _parent; 15 | 16 | [Import] 17 | private ITextDocumentFactoryService DocumentService { get; set; } 18 | 19 | /// The absolute file path to the .editorconfig document. 20 | public string FileName { get; private set; } 21 | 22 | /// Returns a parent document if one exist. 23 | public EditorConfigDocument Parent 24 | { 25 | get 26 | { 27 | if (Root != null && Root.IsValid && Root.Value.Text.Is("true") && Root.Severity == null) 28 | return null; 29 | 30 | if (_parent == null) 31 | _parent = InheritsFrom(); 32 | 33 | return _parent; 34 | } 35 | } 36 | 37 | private void InitializeInheritance() 38 | { 39 | VsHelpers.SatisfyImportsOnce(this); 40 | 41 | var componentModel = (IComponentModel)Package.GetGlobalService(typeof(SComponentModel)); 42 | 43 | if (componentModel == null) 44 | return; 45 | 46 | IContentTypeRegistryService contentTypeRegistry = componentModel.DefaultExportProvider.GetExportedValue(); 47 | _contentType = contentTypeRegistry.GetContentType(Constants.LanguageName); 48 | 49 | if (DocumentService.TryGetTextDocument(TextBuffer, out ITextDocument doc)) 50 | { 51 | FileName = doc.FilePath; 52 | } 53 | } 54 | 55 | private EditorConfigDocument InheritsFrom() 56 | { 57 | var file = new FileInfo(FileName); 58 | DirectoryInfo parent = file.Directory.Parent; 59 | 60 | while (parent != null) 61 | { 62 | string parentFileName = Path.Combine(parent.FullName, Constants.FileName); 63 | 64 | if (File.Exists(parentFileName)) 65 | { 66 | ITextDocument doc = DocumentService.CreateAndLoadTextDocument(parentFileName, _contentType); 67 | return new EditorConfigDocument(doc.TextBuffer) { FileName = parentFileName }; 68 | } 69 | 70 | parent = parent.Parent; 71 | } 72 | 73 | return null; 74 | } 75 | 76 | private void DisposeInheritance() 77 | { 78 | if (_parent != null) 79 | { 80 | _parent.Dispose(); 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Parser/ParseItem.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Text; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System; 5 | 6 | namespace EditorConfig 7 | { 8 | /// A building block of the document. 9 | public class ParseItem 10 | { 11 | public ParseItem(EditorConfigDocument document, ItemType type, Span span, string text) 12 | { 13 | Document = document; 14 | ItemType = type; 15 | Span = span; 16 | Text = text; 17 | } 18 | 19 | /// The document this item belongs to. 20 | public EditorConfigDocument Document { get; set; } 21 | 22 | /// The span of this item in the text buffer. 23 | public Span Span { get; set; } 24 | 25 | /// The type of item. 26 | public ItemType ItemType { get; set; } 27 | 28 | /// The text of this item in the text buffer. 29 | public string Text { get; set; } 30 | 31 | /// A list of validation errors. 32 | public List Errors { get; } = new List(); 33 | 34 | /// True if the item contains errors; otherwise false. 35 | public bool HasErrors 36 | { 37 | get { return Errors.Any(); } 38 | } 39 | 40 | /// Adds an error to the Errors list if it doesn't already contain it. 41 | public void AddError(DisplayError error) 42 | { 43 | if (!Errors.Any(e => e.Name == error.Name)) 44 | Errors.Add(error); 45 | } 46 | 47 | public override string ToString() 48 | { 49 | return ItemType + ": " + Text; 50 | } 51 | 52 | public override int GetHashCode() 53 | { 54 | int textHash = string.IsNullOrEmpty(Text) ? 1 : Text.GetHashCode(); 55 | return Span.GetHashCode() ^ textHash; 56 | } 57 | 58 | public override bool Equals(object obj) 59 | { 60 | if (!(obj is ParseItem other)) 61 | return false; 62 | 63 | return Equals(other); 64 | } 65 | 66 | public bool Equals(ParseItem other) 67 | { 68 | if (other == null) 69 | return false; 70 | 71 | if (Span != other.Span) 72 | return false; 73 | 74 | return Text.Is(other.Text); 75 | } 76 | 77 | public static bool operator ==(ParseItem a, ParseItem b) 78 | { 79 | if (ReferenceEquals(a, b)) 80 | return true; 81 | 82 | if (((object)a == null) || ((object)b == null)) 83 | return false; 84 | 85 | return a.Equals(b); 86 | } 87 | 88 | public static bool operator !=(ParseItem a, ParseItem b) 89 | { 90 | return !(a == b); 91 | } 92 | } 93 | 94 | public enum ItemType 95 | { 96 | Comment, 97 | Section, 98 | Keyword, 99 | Value, 100 | Severity, 101 | Suppression, 102 | Unknown 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/Parser/Property.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Text; 2 | 3 | namespace EditorConfig 4 | { 5 | /// A property is a keyword/value pair with an optional severity. 6 | public class Property 7 | { 8 | public Property(ParseItem keyword) 9 | { 10 | Keyword = keyword; 11 | } 12 | 13 | /// The keyword is the name of the property. 14 | public ParseItem Keyword { get; set; } 15 | 16 | /// The value is what comes after the = character. 17 | public ParseItem Value { get; set; } 18 | 19 | /// This applies to C# and .NET specific keywords only. 20 | public ParseItem Severity { get; set; } 21 | 22 | /// The full span of the property including the value and severity. 23 | public Span Span 24 | { 25 | get 26 | { 27 | ParseItem last = Severity ?? Value ?? Keyword; 28 | return Span.FromBounds(Keyword.Span.Start, last.Span.End); 29 | } 30 | } 31 | 32 | /// Returns true if there are no syntax errors on the property. 33 | public bool IsValid 34 | { 35 | get 36 | { 37 | return Keyword != null && Value != null; 38 | } 39 | } 40 | 41 | public override string ToString() 42 | { 43 | string text = Keyword.Text; 44 | 45 | if (Value != null) 46 | text += $" = {Value.Text}"; 47 | 48 | if (Severity != null) 49 | text += $" : {Severity.Text}"; 50 | 51 | return text; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Parser/Section.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Text; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace EditorConfig 6 | { 7 | /// A section is a globbing pattern matching one or more files. 8 | public class Section 9 | { 10 | public Section(ParseItem section) 11 | { 12 | Item = section; 13 | Properties = new List(); 14 | } 15 | 16 | /// The ParseItem containing the section display text. 17 | public ParseItem Item { get; } 18 | 19 | /// A list of properties under the Section. 20 | public IList Properties { get; } 21 | 22 | /// The full span of the section including the properties. 23 | public Span Span 24 | { 25 | get 26 | { 27 | Property last = Properties.LastOrDefault(); 28 | return last != null ? new Span(Item.Span.Start, last.Span.End - Item.Span.Start) : Item.Span; 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using EditorConfig; 2 | using Microsoft.VisualStudio.Shell; 3 | using System; 4 | using System.Reflection; 5 | using System.Runtime.CompilerServices; 6 | using System.Runtime.InteropServices; 7 | 8 | [assembly: AssemblyTitle(Vsix.Name)] 9 | [assembly: AssemblyDescription(Vsix.Description)] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany(Vsix.Author)] 12 | [assembly: AssemblyProduct(Vsix.Name)] 13 | [assembly: AssemblyCopyright(Vsix.Author)] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | [assembly: ProvideCodeBase(AssemblyName = "EditorConfig")] 17 | 18 | [assembly: InternalsVisibleTo("EditorConfigTest")] 19 | 20 | [assembly: ComVisible(false)] 21 | [assembly: CLSCompliant(false)] 22 | 23 | [assembly: AssemblyVersion(Vsix.Version)] 24 | [assembly: AssemblyFileVersion(Vsix.Version)] 25 | -------------------------------------------------------------------------------- /src/ProvideBraceCompletionAttribute.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Shell; 2 | using System; 3 | using System.Globalization; 4 | 5 | namespace EditorConfig 6 | { 7 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] 8 | public class ProvideBraceCompletionAttribute : RegistrationAttribute 9 | { 10 | private string languageName; 11 | public ProvideBraceCompletionAttribute(string languageName) 12 | { 13 | this.languageName = languageName; 14 | } 15 | 16 | public override void Register(RegistrationContext context) 17 | { 18 | string keyName = string.Format(CultureInfo.InvariantCulture, "{0}\\{1}\\{2}", "Languages", "Language Services", languageName); 19 | using (Key langKey = context.CreateKey(keyName)) 20 | { 21 | langKey.SetValue("ShowBraceCompletion", 1); 22 | } 23 | } 24 | 25 | public override void Unregister(RegistrationContext context) 26 | { 27 | string keyName = string.Format(CultureInfo.InvariantCulture, "{0}\\{1}\\{2}", "Languages", "Language Services", languageName); 28 | context.RemoveKey(keyName); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/QuickInfo/EditorConfigQuickInfo.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Language.Intellisense; 2 | using Microsoft.VisualStudio.Text; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace EditorConfig 8 | { 9 | internal class EditorConfigQuickInfo : IQuickInfoSource 10 | { 11 | private ITextBuffer _buffer; 12 | private EditorConfigDocument _document; 13 | 14 | public EditorConfigQuickInfo(ITextBuffer buffer) 15 | { 16 | _buffer = buffer; 17 | _document = EditorConfigDocument.FromTextBuffer(buffer); 18 | } 19 | 20 | public void AugmentQuickInfoSession(IQuickInfoSession session, IList qiContent, out ITrackingSpan applicableToSpan) 21 | { 22 | applicableToSpan = null; 23 | 24 | SnapshotPoint? point = session.GetTriggerPoint(_buffer.CurrentSnapshot); 25 | 26 | if (session == null || qiContent == null || !point.HasValue || point.Value.Position >= point.Value.Snapshot.Length) 27 | return; 28 | 29 | ParseItem item = _document.ItemAtPosition(point.Value); 30 | 31 | if (item == null) 32 | return; 33 | 34 | applicableToSpan = point.Value.Snapshot.CreateTrackingSpan(item.Span, SpanTrackingMode.EdgeNegative); 35 | 36 | if (item.Errors.Any()) 37 | { 38 | foreach (DisplayError error in item.Errors) 39 | { 40 | qiContent.Add(new Shared.EditorTooltip(error)); 41 | return; 42 | } 43 | } 44 | 45 | Property property = _document.PropertyAtPosition(point.Value); 46 | 47 | SchemaCatalog.TryGetKeyword(property?.Keyword?.Text, out Keyword keyword); 48 | 49 | // Keyword 50 | if (keyword != null && item.ItemType == ItemType.Keyword) 51 | { 52 | qiContent.Add(new Shared.EditorTooltip(keyword)); 53 | } 54 | 55 | // Value 56 | else if (keyword != null && item.ItemType == ItemType.Value) 57 | { 58 | Value value = keyword.Values.FirstOrDefault(v => v.Name.Is(item.Text)); 59 | 60 | if (value != null && !string.IsNullOrEmpty(value.Description)) 61 | qiContent.Add(new Shared.EditorTooltip(value)); 62 | } 63 | 64 | // Severity 65 | else if (item.ItemType == ItemType.Severity && SchemaCatalog.TryGetSeverity(item.Text, out Severity severity)) 66 | { 67 | qiContent.Add(new Shared.EditorTooltip(severity)); 68 | } 69 | 70 | // Suppression 71 | else if (item.ItemType == ItemType.Suppression && ErrorCatalog.TryGetErrorCode(item.Text, out var code)) 72 | { 73 | qiContent.Add(new Shared.EditorTooltip(code)); 74 | } 75 | } 76 | 77 | public void Dispose() 78 | { 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/QuickInfo/EditorConfigQuickInfoController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.VisualStudio.Language.Intellisense; 3 | using Microsoft.VisualStudio.Text; 4 | using Microsoft.VisualStudio.Text.Editor; 5 | 6 | namespace EditorConfig 7 | { 8 | internal class EditorConfigQuickInfoController : IIntellisenseController 9 | { 10 | private ITextView m_textView; 11 | private IList m_subjectBuffers; 12 | private EditorConfigQuickInfoControllerProvider m_provider; 13 | 14 | internal EditorConfigQuickInfoController(ITextView textView, IList subjectBuffers, EditorConfigQuickInfoControllerProvider provider) 15 | { 16 | m_textView = textView; 17 | m_subjectBuffers = subjectBuffers; 18 | m_provider = provider; 19 | 20 | m_textView.MouseHover += OnTextViewMouseHover; 21 | } 22 | 23 | private void OnTextViewMouseHover(object sender, MouseHoverEventArgs e) 24 | { 25 | //find the mouse position by mapping down to the subject buffer 26 | SnapshotPoint? point = m_textView.BufferGraph.MapDownToFirstMatch 27 | (new SnapshotPoint(m_textView.TextSnapshot, e.Position), 28 | PointTrackingMode.Positive, 29 | snapshot => m_subjectBuffers.Contains(snapshot.TextBuffer), 30 | PositionAffinity.Predecessor); 31 | 32 | if (point != null) 33 | { 34 | ITrackingPoint triggerPoint = point.Value.Snapshot.CreateTrackingPoint(point.Value.Position, PointTrackingMode.Positive); 35 | 36 | if (!m_provider.QuickInfoBroker.IsQuickInfoActive(m_textView)) 37 | { 38 | m_provider.QuickInfoBroker.TriggerQuickInfo(m_textView, triggerPoint, true); 39 | } 40 | } 41 | } 42 | 43 | public void Detach(ITextView textView) 44 | { 45 | if (m_textView == textView) 46 | { 47 | m_textView.MouseHover -= OnTextViewMouseHover; 48 | m_textView = null; 49 | } 50 | } 51 | 52 | public void ConnectSubjectBuffer(ITextBuffer subjectBuffer) 53 | { 54 | } 55 | 56 | public void DisconnectSubjectBuffer(ITextBuffer subjectBuffer) 57 | { 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/QuickInfo/EditorConfigQuickInfoControllerProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.Composition; 3 | using Microsoft.VisualStudio.Language.Intellisense; 4 | using Microsoft.VisualStudio.Text; 5 | using Microsoft.VisualStudio.Text.Editor; 6 | using Microsoft.VisualStudio.Utilities; 7 | 8 | namespace EditorConfig 9 | { 10 | [Export(typeof(IIntellisenseControllerProvider))] 11 | [Name("EditorConfig QuickInfo Controller")] 12 | [ContentType(Constants.LanguageName)] 13 | public class EditorConfigQuickInfoControllerProvider : IIntellisenseControllerProvider 14 | { 15 | [Import] 16 | public IQuickInfoBroker QuickInfoBroker { get; set; } 17 | 18 | public IIntellisenseController TryCreateIntellisenseController(ITextView textView, IList subjectBuffers) 19 | { 20 | if (EditorConfigPackage.Language.Preferences.EnableQuickInfo && subjectBuffers.Count > 0) 21 | { 22 | return textView.Properties.GetOrCreateSingletonProperty(() => new EditorConfigQuickInfoController(textView, subjectBuffers, this)); 23 | } 24 | 25 | return null; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/QuickInfo/EditorConfigQuickInfoSourceProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Language.Intellisense; 2 | using Microsoft.VisualStudio.Text; 3 | using Microsoft.VisualStudio.Text.Classification; 4 | using Microsoft.VisualStudio.Utilities; 5 | using System.ComponentModel.Composition; 6 | 7 | namespace EditorConfig 8 | { 9 | [Export(typeof(IQuickInfoSourceProvider))] 10 | [Name("EditorConfig QuickInfo Source")] 11 | [Order(Before = "Default Quick Info Presenter")] 12 | [ContentType(Constants.LanguageName)] 13 | internal class EditorConfigQuickInfoSourceProvider : IQuickInfoSourceProvider 14 | { 15 | public IQuickInfoSource TryCreateQuickInfoSource(ITextBuffer textBuffer) 16 | { 17 | return textBuffer.Properties.GetOrCreateSingletonProperty(() => new EditorConfigQuickInfo(textBuffer)); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Resources/ButtonIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/src/Resources/ButtonIcon.png -------------------------------------------------------------------------------- /src/Resources/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/src/Resources/Icon.png -------------------------------------------------------------------------------- /src/Schema/Category.cs: -------------------------------------------------------------------------------- 1 | namespace EditorConfig 2 | { 3 | public enum Category 4 | { 5 | None, 6 | Standard, 7 | CSharp, 8 | DotNet, 9 | VisualBasic 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Schema/EditorConfig-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema", 3 | "type": "object", 4 | 5 | "definitions": { 6 | "keyword": { 7 | "type": "object", 8 | "required": [ "name", "description", "values", "defaultValue" ], 9 | "additionalProperties": false, 10 | 11 | "properties": { 12 | "description": { 13 | "type": "string" 14 | }, 15 | "hidden": { 16 | "enum": [ true ] 17 | }, 18 | "multiple": { 19 | "type": "boolean" 20 | }, 21 | "name": { 22 | "type": "string" 23 | }, 24 | "severity": { 25 | "type": "boolean" 26 | }, 27 | "unsupported": { 28 | "enum": [ true ] 29 | }, 30 | "values": { 31 | "type": "array" 32 | }, 33 | "defaultValue": { 34 | "type": "array" 35 | }, 36 | "defaultSeverity": { 37 | "enum": [ "none", "silent", "suggestion", "warning", "error" ] 38 | }, 39 | "documentationLink": { 40 | "type": "string" 41 | } 42 | } 43 | }, 44 | "severities": { 45 | "type": "object", 46 | "required": ["name", "description"], 47 | "additionalProperties": false, 48 | 49 | "properties": { 50 | "name": { 51 | "type": "string" 52 | }, 53 | "description": { 54 | "type": "string" 55 | } 56 | } 57 | } 58 | }, 59 | 60 | "properties": { 61 | "properties": { 62 | "type": "array", 63 | "items": { 64 | "$ref": "#/definitions/keyword" 65 | } 66 | }, 67 | "severities": { 68 | "type": "array", 69 | "items": { 70 | "$ref": "#/definitions/severities" 71 | } 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /src/Schema/Keyword.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Imaging; 2 | using Microsoft.VisualStudio.Imaging.Interop; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace EditorConfig 8 | { 9 | /// The keyword is the name-part of a property. 10 | public class Keyword : ITooltip 11 | { 12 | public Keyword(string name, string description, IEnumerable values, IEnumerable defaultValue, bool unsupported, bool hidden, bool multiple, bool severity, string defaultSeverity, string documentationLink) 13 | { 14 | Name = name; 15 | Description = description; 16 | Values = values.Select(v => new Value(v)); 17 | DefaultValue = defaultValue.Select(v => new Value(v)); 18 | IsSupported = !unsupported; 19 | IsVisible = !hidden; 20 | SupportsMultipleValues = multiple; 21 | RequiresSeverity = severity; 22 | DefaultSeverity = defaultSeverity; 23 | DocumentationLink = documentationLink; 24 | } 25 | 26 | /// The keyword of the property. 27 | public string Name { get; } 28 | 29 | /// The description of the property. 30 | public string Description { get; } 31 | 32 | /// A list of values applicable to the property. 33 | public IEnumerable Values { get; } 34 | 35 | public IEnumerable DefaultValue { get; } 36 | 37 | /// True if the property is supported by Visual Studio. 38 | public bool IsSupported { get; } 39 | 40 | /// True if the property shows up in Intellisense. 41 | public bool IsVisible { get; } 42 | 43 | /// True if the value can be a comman separated list. 44 | public bool SupportsMultipleValues { get; } 45 | 46 | public bool RequiresSeverity { get; } 47 | 48 | public string DefaultSeverity { get; } 49 | 50 | /// Link to the property's documentation. Null if no documentation. 51 | public string DocumentationLink { get; } 52 | 53 | /// The category is used in the Intellisense filters. 54 | public Category Category 55 | { 56 | get 57 | { 58 | if (!string.IsNullOrWhiteSpace(Name)) 59 | { 60 | if (Name.StartsWith("csharp_", StringComparison.OrdinalIgnoreCase)) 61 | return Category.CSharp; 62 | else if (Name.StartsWith("dotnet_", StringComparison.OrdinalIgnoreCase)) 63 | return Category.DotNet; 64 | else if (Name.StartsWith("visual_basic_", StringComparison.OrdinalIgnoreCase)) 65 | return Category.VisualBasic; 66 | else 67 | return Category.Standard; 68 | } 69 | 70 | return Category.None; 71 | } 72 | } 73 | 74 | /// The image moniker that represents the property. 75 | public ImageMoniker Moniker 76 | { 77 | get 78 | { 79 | switch (Category) 80 | { 81 | case Category.CSharp: 82 | return KnownMonikers.CSFileNode; 83 | case Category.DotNet: 84 | return KnownMonikers.DotNET; 85 | case Category.VisualBasic: 86 | return KnownMonikers.VBFileNode; 87 | } 88 | 89 | return KnownMonikers.Property; 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Schema/SchemaCatalog.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Linq; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Reflection; 8 | 9 | namespace EditorConfig 10 | { 11 | /// Contains all the information about the properties of EditorConfig. 12 | public static class SchemaCatalog 13 | { 14 | /// The name of the root keyword. 15 | public const string Root = "root"; 16 | 17 | static SchemaCatalog() 18 | { 19 | ParseJson(); 20 | } 21 | 22 | /// A list of all keywords including the ones marked as hidden. 23 | public static IEnumerable AllKeywords { get; private set; } 24 | 25 | /// A list of all visible keywords. 26 | public static IEnumerable VisibleKeywords { get; private set; } 27 | 28 | /// A list of all severities. 29 | public static IEnumerable Severities { get; private set; } 30 | 31 | /// Tries to get a keyword by name. 32 | public static bool TryGetKeyword(string name, out Keyword keyword) 33 | { 34 | if (name is null) 35 | { 36 | keyword = null; 37 | return false; 38 | } 39 | 40 | keyword = AllKeywords.FirstOrDefault(c => c.Name.Is(name)); 41 | if (keyword is object) 42 | return true; 43 | 44 | if (name.StartsWith("dotnet_naming_", StringComparison.OrdinalIgnoreCase) && name.IndexOf('.') > 0) 45 | { 46 | string[] parts = name.Split('.'); 47 | 48 | if (parts.Length >= 3) 49 | { 50 | string first = $"{parts[0]}."; 51 | string last = $".{parts[parts.Length - 1]}"; 52 | keyword = AllKeywords.FirstOrDefault(c => c.Name.StartsWith(first, StringComparison.OrdinalIgnoreCase) && c.Name.EndsWith(last, StringComparison.OrdinalIgnoreCase)); 53 | } 54 | } 55 | else if (name.StartsWith("dotnet_diagnostic.", StringComparison.OrdinalIgnoreCase)) 56 | { 57 | string[] parts = name.Split('.'); 58 | if (parts.Length == 3 59 | && parts[0] == "dotnet_diagnostic" 60 | && parts[2] == "severity") 61 | { 62 | keyword = AllKeywords.FirstOrDefault(c => c.Name.Is("dotnet_diagnostic..severity")); 63 | } 64 | } 65 | else if (name.StartsWith("dotnet_analyzer_diagnostic.", StringComparison.OrdinalIgnoreCase)) 66 | { 67 | string[] parts = name.Split('.'); 68 | if (parts.Length == 3 69 | && parts[0] == "dotnet_analyzer_diagnostic" 70 | && parts[1].StartsWith("category-", StringComparison.OrdinalIgnoreCase) 71 | && parts[2] == "severity") 72 | { 73 | keyword = AllKeywords.FirstOrDefault(c => c.Name.Is("dotnet_analyzer_diagnostic.category-.severity")); 74 | } 75 | } 76 | 77 | return keyword != null; 78 | } 79 | 80 | /// Tries to get a severity by name. 81 | public static bool TryGetSeverity(string name, out Severity severity) 82 | { 83 | severity = Severities.FirstOrDefault(s => s.Name.Is(name)); 84 | return severity != null; 85 | } 86 | 87 | internal static void ParseJson(string file = null) 88 | { 89 | if (string.IsNullOrEmpty(file)) 90 | { 91 | string assembly = Assembly.GetExecutingAssembly().Location; 92 | string folder = Path.GetDirectoryName(assembly); 93 | file = Path.Combine(folder, "schema\\EditorConfig.json"); 94 | } 95 | 96 | if (File.Exists(file)) 97 | { 98 | var obj = JObject.Parse(File.ReadAllText(file)); 99 | 100 | Severities = JsonConvert.DeserializeObject>(obj["severities"].ToString()); 101 | AllKeywords = JsonConvert.DeserializeObject>(obj["properties"].ToString()); 102 | VisibleKeywords = AllKeywords.Where(p => p.IsVisible); 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/Schema/Severity.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Imaging; 2 | using Microsoft.VisualStudio.Imaging.Interop; 3 | 4 | namespace EditorConfig 5 | { 6 | /// The severity determines how the property is enforced by Visual Studio. 7 | public class Severity : ITooltip 8 | { 9 | public Severity(string name, string description) 10 | { 11 | Name = name; 12 | Description = description; 13 | } 14 | 15 | /// The severity name. 16 | public string Name { get; } 17 | 18 | /// The severity description. 19 | public string Description { get; } 20 | 21 | /// True if Visual Studio supports the severity. 22 | public bool IsSupported => true; 23 | 24 | /// The image moniker shown by Intellisense and the adornment next to the severity. 25 | public ImageMoniker Moniker 26 | { 27 | get 28 | { 29 | switch (Name) 30 | { 31 | case "none": 32 | return KnownMonikers.None; 33 | case "suggestion": 34 | return KnownMonikers.StatusInformation; 35 | case "warning": 36 | return KnownMonikers.StatusWarning; 37 | case "error": 38 | return KnownMonikers.StatusError; 39 | } 40 | 41 | return KnownMonikers.UnknownMember; 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Schema/Value.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Imaging; 2 | using Microsoft.VisualStudio.Imaging.Interop; 3 | using System; 4 | 5 | namespace EditorConfig 6 | { 7 | /// The value of a property. 8 | public class Value : ITooltip 9 | { 10 | private bool _isUnset; 11 | 12 | public Value(string name) 13 | { 14 | _isUnset = name.Is("unset"); 15 | 16 | Name = name; 17 | Description = GetDescription(); 18 | IsSupported = !_isUnset; 19 | Moniker = KnownMonikers.EnumerationItemPublic; 20 | } 21 | 22 | /// The value text. 23 | public string Name { get; } 24 | 25 | /// The value description. 26 | public string Description { get; } 27 | 28 | /// The image moniker shown in Intellisense and QuickInfo. 29 | public ImageMoniker Moniker { get; } 30 | 31 | /// True if the value is supported by Visual Studio. 32 | public bool IsSupported { get; } 33 | 34 | private string GetDescription() 35 | { 36 | if (_isUnset) 37 | return Resources.Text.ValueUnset; 38 | 39 | return null; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Shared/EditorTooltip.xaml: -------------------------------------------------------------------------------- 1 |  8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 25 | 26 | -------------------------------------------------------------------------------- /src/Shared/EditorTooltip.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.PlatformUI; 2 | using System.Windows.Controls; 3 | 4 | namespace EditorConfig.Shared 5 | { 6 | /// 7 | /// Interaction logic for EditorTooltip.xaml 8 | /// 9 | public partial class EditorTooltip : UserControl 10 | { 11 | private const int _iconSize = 32; 12 | 13 | internal EditorTooltip(ITooltip item) 14 | { 15 | InitializeComponent(); 16 | 17 | Loaded += (s, e) => 18 | { 19 | ItemName.Content = PrettifyName(item); 20 | ItemName.SetResourceReference(TextBlock.ForegroundProperty, EnvironmentColors.SystemMenuTextBrushKey); 21 | 22 | string description = item.Description; 23 | 24 | if (!item.IsSupported) 25 | description += $"\r\n\r\n{EditorConfig.Resources.Text.NotSupportedByVS}"; 26 | 27 | Description.Text = description; 28 | Description.SetResourceReference(TextBlock.ForegroundProperty, EnvironmentColors.SystemMenuTextBrushKey); 29 | 30 | Glyph.Source = item.Moniker.ToBitmap(_iconSize); 31 | }; 32 | } 33 | 34 | private static string PrettifyName(ITooltip item) 35 | { 36 | string text = item.Name 37 | .Replace("_", " ") 38 | .Replace("dotnet", ".NET") 39 | .Replace("csharp", "C#"); 40 | 41 | if (text.Length > 0) 42 | text = text[0].ToString().ToUpperInvariant() + text.Substring(1); 43 | 44 | return text; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Shared/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EditorConfig 4 | { 5 | public static class Extensions 6 | { 7 | /// Performs a OrdinalIgnoreCase comparison between two strings. 8 | public static bool Is(this string a, string b) 9 | { 10 | return string.Equals(a, b, StringComparison.OrdinalIgnoreCase); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Shared/ITooltip.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Imaging.Interop; 2 | 3 | namespace EditorConfig 4 | { 5 | public interface ITooltip 6 | { 7 | /// The name to display in bold letters in the tooltip. 8 | string Name { get; } 9 | 10 | /// The description of the tooltip. 11 | string Description { get; } 12 | 13 | /// The image moniker to represent the tooltip. 14 | ImageMoniker Moniker { get; } 15 | 16 | /// True if its supported by Visual Studio. 17 | bool IsSupported { get; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Shared/JoinableTaskFactoryExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft; 3 | using Microsoft.VisualStudio.Shell; 4 | using Microsoft.VisualStudio.Threading; 5 | using Task = System.Threading.Tasks.Task; 6 | 7 | namespace EditorConfig 8 | { 9 | internal static class JoinableTaskFactoryExtensions 10 | { 11 | /// 12 | /// Schedules a delegate for background execution on the UI thread without inheriting any claim to the UI thread from its caller. 13 | /// 14 | /// The factory to use for creating the task. 15 | /// The async delegate to invoke on the UI thread sometime in the future. 16 | /// The priority to use when switching to the UI thread or resuming after a yielding await. 17 | /// The that represents the on-idle operation. 18 | public static JoinableTask StartOnIdle(this JoinableTaskFactory joinableTaskFactory, Func asyncMethod, VsTaskRunContext priority = VsTaskRunContext.UIThreadBackgroundPriority) 19 | { 20 | Requires.NotNull(joinableTaskFactory, nameof(joinableTaskFactory)); 21 | Requires.NotNull(asyncMethod, nameof(asyncMethod)); 22 | 23 | // Avoid inheriting any context from any ambient JoinableTask that is scheduling this work. 24 | using (joinableTaskFactory.Context.SuppressRelevance()) 25 | { 26 | return joinableTaskFactory.RunAsync( 27 | priority, 28 | async () => 29 | { 30 | // We always yield, so as to not inline execution of the delegate if the caller is already on the UI thread. 31 | await Task.Yield(); 32 | 33 | // In case the caller wasn't on the UI thread, switch to it. It no-ops if we're already there. 34 | await joinableTaskFactory.SwitchToMainThreadAsync(); 35 | 36 | await asyncMethod(); 37 | }); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Shared/Telemetry.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Telemetry; 2 | using System; 3 | 4 | namespace EditorConfig 5 | { 6 | public static class Telemetry 7 | { 8 | private const string _namespace = "WebTools/EditorConfig/"; 9 | 10 | public static void TrackUserTask(string name, TelemetryResult result = TelemetryResult.Success) 11 | { 12 | string actualName = name.Replace(" ", "_"); 13 | TelemetryService.DefaultSession.PostUserTask(_namespace + actualName, result); 14 | } 15 | 16 | public static void TrackOperation(string name, TelemetryResult result = TelemetryResult.Success) 17 | { 18 | string actualName = name.Replace(" ", "_"); 19 | TelemetryService.DefaultSession.PostOperation(_namespace + actualName, result); 20 | } 21 | 22 | public static void TrackException(string name, Exception exception) 23 | { 24 | if (string.IsNullOrWhiteSpace(name) || exception == null) 25 | return; 26 | 27 | string actualName = name.Replace(" ", "_"); 28 | TelemetryService.DefaultSession.PostFault(_namespace + actualName, exception.Message, exception); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Shared/TextViewUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.VisualStudio; 4 | using Microsoft.VisualStudio.Editor; 5 | using Microsoft.VisualStudio.Shell; 6 | using Microsoft.VisualStudio.Shell.Interop; 7 | using Microsoft.VisualStudio.Text.Editor; 8 | using Microsoft.VisualStudio.TextManager.Interop; 9 | 10 | namespace EditorConfig 11 | { 12 | public static class TextViewUtil 13 | { 14 | public static bool TryGetWpfTextView(string filePath, out IWpfTextView view) 15 | { 16 | ThreadHelper.ThrowIfNotOnUIThread(); 17 | 18 | view = null; 19 | IVsTextView vTextView = FindTextViewFor(filePath); 20 | 21 | if (vTextView is IVsUserData userData) 22 | { 23 | IWpfTextViewHost viewHost; 24 | Guid guidViewHost = DefGuidList.guidIWpfTextViewHost; 25 | userData.GetData(ref guidViewHost, out object holder); 26 | viewHost = (IWpfTextViewHost)holder; 27 | view = viewHost.TextView; 28 | return true; 29 | } 30 | 31 | return false; 32 | } 33 | 34 | private static IVsTextView FindTextViewFor(string filePath) 35 | { 36 | ThreadHelper.ThrowIfNotOnUIThread(); 37 | 38 | IVsWindowFrame frame = FindWindowFrame(filePath); 39 | if (frame != null) 40 | { 41 | if (GetTextViewFromFrame(frame, out IVsTextView textView)) 42 | { 43 | return textView; 44 | } 45 | } 46 | 47 | return null; 48 | } 49 | 50 | private static IEnumerable EnumerateDocumentWindowFrames() 51 | { 52 | ThreadHelper.ThrowIfNotOnUIThread(); 53 | 54 | if (Package.GetGlobalService(typeof(SVsUIShell)) is IVsUIShell shell) 55 | { 56 | int hr = shell.GetDocumentWindowEnum(out IEnumWindowFrames framesEnum); 57 | 58 | if (hr == VSConstants.S_OK && framesEnum != null) 59 | { 60 | IVsWindowFrame[] frames = new IVsWindowFrame[1]; 61 | 62 | while (framesEnum.Next(1, frames, out uint fetched) == VSConstants.S_OK && fetched == 1) 63 | { 64 | yield return frames[0]; 65 | } 66 | } 67 | } 68 | } 69 | 70 | private static IVsWindowFrame FindWindowFrame(string filePath) 71 | { 72 | ThreadHelper.ThrowIfNotOnUIThread(); 73 | 74 | foreach (IVsWindowFrame currentFrame in EnumerateDocumentWindowFrames()) 75 | { 76 | if (IsFrameForFilePath(currentFrame, filePath)) 77 | { 78 | return currentFrame; 79 | } 80 | } 81 | 82 | return null; 83 | } 84 | 85 | private static bool GetPhysicalPathFromFrame(IVsWindowFrame frame, out string frameFilePath) 86 | { 87 | ThreadHelper.ThrowIfNotOnUIThread(); 88 | 89 | int hr = frame.GetProperty((int)__VSFPROPID.VSFPROPID_pszMkDocument, out object propertyValue); 90 | 91 | if (hr == VSConstants.S_OK && propertyValue != null) 92 | { 93 | frameFilePath = propertyValue.ToString(); 94 | return true; 95 | } 96 | 97 | frameFilePath = null; 98 | return false; 99 | } 100 | 101 | private static bool GetTextViewFromFrame(IVsWindowFrame frame, out IVsTextView textView) 102 | { 103 | textView = VsShellUtilities.GetTextView(frame); 104 | 105 | return textView != null; 106 | } 107 | 108 | private static bool IsFrameForFilePath(IVsWindowFrame frame, string filePath) 109 | { 110 | ThreadHelper.ThrowIfNotOnUIThread(); 111 | 112 | if (GetPhysicalPathFromFrame(frame, out string frameFilePath)) 113 | { 114 | return string.Equals(filePath, frameFilePath, StringComparison.OrdinalIgnoreCase); 115 | } 116 | 117 | return false; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/SignatureHelp/SectionParameter.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Language.Intellisense; 2 | using Microsoft.VisualStudio.Text; 3 | 4 | namespace EditorConfig 5 | { 6 | 7 | internal class GenericParameter : IParameter 8 | { 9 | private SectionSignature _signature; 10 | 11 | public GenericParameter(SectionSignature signature) 12 | { 13 | _signature = signature; 14 | } 15 | 16 | public string Documentation 17 | { 18 | get { return null; } 19 | } 20 | 21 | public Span Locus 22 | { 23 | get { return new Span(0, _signature.PropertyName.Length); } 24 | } 25 | 26 | public string Name 27 | { 28 | get { return _signature.PropertyName; } 29 | } 30 | 31 | public Span PrettyPrintedLocus 32 | { 33 | get { return Locus; } 34 | } 35 | 36 | public ISignature Signature 37 | { 38 | get { return _signature; } 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/SignatureHelp/SectionSignatureHelpSource.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Language.Intellisense; 2 | using Microsoft.VisualStudio.Text; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace EditorConfig 8 | { 9 | internal class SectionSignatureHelpSource : ISignatureHelpSource 10 | { 11 | private ITextBuffer _buffer; 12 | private ITrackingSpan _span; 13 | 14 | public SectionSignatureHelpSource(ITextBuffer textBuffer) 15 | { 16 | _buffer = textBuffer; 17 | } 18 | 19 | public void AugmentSignatureHelpSession(ISignatureHelpSession session, IList signatures) 20 | { 21 | SnapshotPoint? point = session.GetTriggerPoint(_buffer.CurrentSnapshot); 22 | 23 | if (!point.HasValue) 24 | return; 25 | 26 | ITextSnapshotLine line = point.Value.GetContainingLine(); 27 | string lineText = line.GetText().Trim(); 28 | 29 | if (!lineText.StartsWith("[", StringComparison.Ordinal)) 30 | return; 31 | 32 | _span = _buffer.CurrentSnapshot.CreateTrackingSpan(line.Extent, SpanTrackingMode.EdgeNegative); 33 | 34 | signatures.Add(new SectionSignature("[*.cs]", "Matches multiple files with a .cs file extension", _span, session)); 35 | signatures.Add(new SectionSignature("[*.vb]", "Matches multiple files with a .vb file extension", _span, session)); 36 | signatures.Add(new SectionSignature("[*.{cs,vb}]", "Matches multiple files with brace expansion notation", _span, session)); 37 | signatures.Add(new SectionSignature("[app/**.js]", "Matches all .js files under lib directory", _span, session)); 38 | signatures.Add(new SectionSignature("[{package.json,.npmrc}]", "Matches the exact files - either package.json or .npmrc", _span, session)); 39 | } 40 | 41 | public ISignature GetBestMatch(ISignatureHelpSession session) 42 | { 43 | if (session.Signatures.Count != 4) 44 | return session.Signatures.FirstOrDefault(); 45 | 46 | string text = _span.GetText(_buffer.CurrentSnapshot); 47 | 48 | if (text.Contains("[{")) 49 | return session.Signatures.ElementAt(3); 50 | 51 | if (text.Contains("{")) 52 | return session.Signatures.ElementAt(1); 53 | 54 | if (text.Contains("**")) 55 | return session.Signatures.ElementAt(2); 56 | 57 | return session.Signatures.ElementAt(0); 58 | } 59 | 60 | public void Dispose() 61 | { 62 | // Nothing to dispose 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/SignatureHelp/SignatureHelpController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio; 2 | using Microsoft.VisualStudio.Language.Intellisense; 3 | using Microsoft.VisualStudio.OLE.Interop; 4 | using Microsoft.VisualStudio.Shell; 5 | using Microsoft.VisualStudio.Text.Editor; 6 | using System; 7 | using System.Runtime.InteropServices; 8 | using Task = System.Threading.Tasks.Task; 9 | 10 | namespace EditorConfig 11 | { 12 | internal sealed class SignatureHelpCommand : BaseCommand 13 | { 14 | private Guid _commandGroup = typeof(VSConstants.VSStd2KCmdID).GUID; 15 | private const uint _commandId = (uint)VSConstants.VSStd2KCmdID.TYPECHAR; 16 | private IWpfTextView _view; 17 | private ISignatureHelpBroker _signaturehelpBroker; 18 | private IQuickInfoBroker _quickInfoBroker; 19 | private ISignatureHelpSession _session; 20 | 21 | public SignatureHelpCommand(IWpfTextView view, ISignatureHelpBroker signaturehelpBroker, IQuickInfoBroker quickInfoBroker) 22 | { 23 | _view = view; 24 | _signaturehelpBroker = signaturehelpBroker; 25 | _quickInfoBroker = quickInfoBroker; 26 | } 27 | 28 | public override int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) 29 | { 30 | if (pguidCmdGroup == _commandGroup && nCmdID == _commandId && EditorConfigPackage.Language.Preferences.ParameterInformation) 31 | { 32 | char typedChar = (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn); 33 | 34 | if (typedChar == 27 && _session != null) 35 | { 36 | DismissSession(); 37 | } 38 | else if (typedChar == '[') 39 | { 40 | TriggerSession(); 41 | } 42 | } 43 | else if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.RETURN) 44 | { 45 | DismissSession(); 46 | } 47 | else if (pguidCmdGroup == VSConstants.VSStd2K && nCmdID == (uint)VSConstants.VSStd2KCmdID.PARAMINFO) 48 | { 49 | TriggerSession(); 50 | } 51 | 52 | ThreadHelper.ThrowIfNotOnUIThread(); 53 | 54 | return Next.Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); 55 | } 56 | 57 | private void TriggerSession() 58 | { 59 | if (_session == null || _session.IsDismissed) 60 | { 61 | if (_quickInfoBroker.IsQuickInfoActive(_view)) 62 | _quickInfoBroker.GetSessions(_view)[0].Dismiss(); 63 | 64 | ThreadHelper.JoinableTaskFactory.StartOnIdle( 65 | () => 66 | { 67 | _session = _signaturehelpBroker.TriggerSignatureHelp(_view); 68 | if (_session != null) 69 | _session.Match(); 70 | 71 | return Task.CompletedTask; 72 | }, 73 | VsTaskRunContext.UIThreadNormalPriority); 74 | } 75 | } 76 | 77 | private void DismissSession() 78 | { 79 | if (_session != null) 80 | { 81 | _session.Dismiss(); 82 | _session = null; 83 | } 84 | } 85 | 86 | public override int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) 87 | { 88 | if (pguidCmdGroup == _commandGroup && prgCmds[0].cmdID == _commandId) 89 | { 90 | prgCmds[0].cmdf = (uint)OLECMDF.OLECMDF_ENABLED | (uint)OLECMDF.OLECMDF_SUPPORTED; 91 | return VSConstants.S_OK; 92 | } 93 | 94 | ThreadHelper.ThrowIfNotOnUIThread(); 95 | 96 | return Next.QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText); 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /src/SignatureHelp/SignatureHelpSourceProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Language.Intellisense; 2 | using Microsoft.VisualStudio.Text; 3 | using Microsoft.VisualStudio.Utilities; 4 | using System.ComponentModel.Composition; 5 | 6 | namespace EditorConfig 7 | { 8 | [Export(typeof(ISignatureHelpSourceProvider))] 9 | [Name("EditorConfig section Signature Help Source")] 10 | [ContentType(Constants.LanguageName)] 11 | [Order(Before = "default")] 12 | internal class SectionSignatureHelpSourceProvider : ISignatureHelpSourceProvider 13 | { 14 | public ISignatureHelpSource TryCreateSignatureHelpSource(ITextBuffer textBuffer) 15 | { 16 | return textBuffer.Properties.GetOrCreateSingletonProperty(() => new SectionSignatureHelpSource(textBuffer)); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/SuggestedActions/AddMissingRulesActionAll.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text; 3 | using System.Threading; 4 | using Microsoft.VisualStudio.Text; 5 | using Microsoft.VisualStudio.Text.Editor; 6 | 7 | namespace EditorConfig 8 | { 9 | class AddMissingRulesActionAll : BaseSuggestedAction 10 | { 11 | private List _missingRules; 12 | private EditorConfigDocument _document; 13 | private ITextView _view; 14 | 15 | public AddMissingRulesActionAll(List missingRules, EditorConfigDocument document, ITextView view) 16 | { 17 | _missingRules = missingRules; 18 | _document = document; 19 | _view = view; 20 | } 21 | public override string DisplayText 22 | { 23 | get { return "All"; } 24 | } 25 | 26 | public override void Execute(CancellationToken cancellationToken) 27 | { 28 | SnapshotPoint caretPost = _view.Caret.Position.BufferPosition; 29 | 30 | using (ITextEdit edit = _view.TextBuffer.CreateEdit()) 31 | { 32 | AddMissingRules(_document, _missingRules, edit); 33 | 34 | if (edit.HasEffectiveChanges) 35 | edit.Apply(); 36 | } 37 | 38 | _view.Caret.MoveTo(new SnapshotPoint(_view.TextBuffer.CurrentSnapshot, caretPost)); 39 | } 40 | 41 | internal static void AddMissingRules(EditorConfigDocument document, List missingRules, ITextEdit edit) 42 | { 43 | var sb = new StringBuilder(); 44 | sb.AppendLine(); 45 | 46 | bool firstRule = true; 47 | string curHeader = ""; 48 | foreach (Keyword curRule in missingRules) 49 | { 50 | if (firstRule) 51 | { 52 | curHeader = GetHeader(curRule); 53 | sb.AppendLine(curHeader); 54 | firstRule = false; 55 | } 56 | else if (!curHeader.Equals(GetHeader(curRule))) 57 | { 58 | curHeader = GetHeader(curRule); 59 | sb.AppendLine(); 60 | sb.AppendLine(curHeader); 61 | } 62 | 63 | sb.Append(curRule.Name + " = "); 64 | IEnumerator defaultValues = curRule.DefaultValue.GetEnumerator(); 65 | bool firstValue = true; 66 | while (defaultValues.MoveNext()) 67 | { 68 | if (firstValue) 69 | { 70 | firstValue = false; 71 | } 72 | else 73 | { 74 | sb.Append(","); 75 | } 76 | sb.Append(defaultValues.Current.Name); 77 | } 78 | 79 | if (curRule.RequiresSeverity) 80 | { 81 | sb.Append(":" + curRule.DefaultSeverity); 82 | } 83 | sb.AppendLine(); 84 | }; 85 | 86 | edit.Insert(document.TextBuffer.CurrentSnapshot.Length, sb.ToString()); 87 | } 88 | 89 | private static string GetHeader(Keyword curRule) 90 | { 91 | switch (curRule.Category) 92 | { 93 | case Category.CSharp: 94 | return "[*.cs]"; 95 | case Category.DotNet: 96 | return "[*.{cs,vb}]"; 97 | case Category.VisualBasic: 98 | return "[*.vb]"; 99 | default: 100 | return "[*]"; 101 | } 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/SuggestedActions/AddMissingRulesActionCSharp.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | using Microsoft.VisualStudio.Text; 4 | using Microsoft.VisualStudio.Text.Editor; 5 | 6 | namespace EditorConfig 7 | { 8 | class AddMissingRulesActionCSharp : BaseSuggestedAction 9 | { 10 | private List _missingRules; 11 | private EditorConfigDocument _document; 12 | private ITextView _view; 13 | 14 | public AddMissingRulesActionCSharp(List missingRules, EditorConfigDocument document, ITextView view) 15 | { 16 | _missingRules = missingRules; 17 | _document = document; 18 | _view = view; 19 | } 20 | 21 | public override string DisplayText 22 | { 23 | get { return "C#"; } 24 | } 25 | 26 | public override void Execute(CancellationToken cancellationToken) 27 | { 28 | SnapshotPoint caretPost = _view.Caret.Position.BufferPosition; 29 | 30 | using (ITextEdit edit = _view.TextBuffer.CreateEdit()) 31 | { 32 | AddMissingRulesActionAll.AddMissingRules(_document, _missingRules, edit); 33 | 34 | if (edit.HasEffectiveChanges) 35 | edit.Apply(); 36 | } 37 | 38 | _view.Caret.MoveTo(new SnapshotPoint(_view.TextBuffer.CurrentSnapshot, caretPost)); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/SuggestedActions/AddMissingRulesActionDotNet.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | using Microsoft.VisualStudio.Text; 4 | using Microsoft.VisualStudio.Text.Editor; 5 | 6 | namespace EditorConfig 7 | { 8 | class AddMissingRulesActionDotNet : BaseSuggestedAction 9 | { 10 | private List _missingRules; 11 | private EditorConfigDocument _document; 12 | private ITextView _view; 13 | 14 | public AddMissingRulesActionDotNet(List missingRules, EditorConfigDocument document, ITextView view) 15 | { 16 | _missingRules = missingRules; 17 | _document = document; 18 | _view = view; 19 | } 20 | 21 | public override string DisplayText 22 | { 23 | get { return ".NET"; } 24 | } 25 | 26 | public override void Execute(CancellationToken cancellationToken) 27 | { 28 | SnapshotPoint caretPost = _view.Caret.Position.BufferPosition; 29 | 30 | using (ITextEdit edit = _view.TextBuffer.CreateEdit()) 31 | { 32 | AddMissingRulesActionAll.AddMissingRules(_document, _missingRules, edit); 33 | 34 | if (edit.HasEffectiveChanges) 35 | edit.Apply(); 36 | } 37 | 38 | _view.Caret.MoveTo(new SnapshotPoint(_view.TextBuffer.CurrentSnapshot, caretPost)); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/SuggestedActions/AddMissingRulesActionVB.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using Microsoft.VisualStudio.Text; 5 | using Microsoft.VisualStudio.Text.Editor; 6 | 7 | namespace EditorConfig 8 | { 9 | class AddMissingRulesActionVB : BaseSuggestedAction 10 | { 11 | private List _missingRules; 12 | private EditorConfigDocument _document; 13 | private ITextView _view; 14 | 15 | public AddMissingRulesActionVB(List missingRules, EditorConfigDocument document, ITextView view) 16 | { 17 | _missingRules = missingRules; 18 | _document = document; 19 | _view = view; 20 | } 21 | 22 | public override string DisplayText 23 | { 24 | get { return "VB"; } 25 | } 26 | 27 | public override void Execute(CancellationToken cancellationToken) 28 | { 29 | SnapshotPoint caretPost = _view.Caret.Position.BufferPosition; 30 | 31 | using (ITextEdit edit = _view.TextBuffer.CreateEdit()) 32 | { 33 | AddMissingRulesActionAll.AddMissingRules(_document, _missingRules, edit); 34 | 35 | if (edit.HasEffectiveChanges) 36 | edit.Apply(); 37 | } 38 | 39 | _view.Caret.MoveTo(new SnapshotPoint(_view.TextBuffer.CurrentSnapshot, caretPost)); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/SuggestedActions/BaseSuggestedAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using EnvDTE; 6 | using Microsoft.VisualStudio.Imaging.Interop; 7 | using Microsoft.VisualStudio.Language.Intellisense; 8 | using Microsoft.VisualStudio.Shell; 9 | 10 | namespace EditorConfig 11 | { 12 | abstract class BaseSuggestedAction : ISuggestedAction 13 | { 14 | public abstract string DisplayText { get; } 15 | 16 | public virtual bool IsEnabled { get; } = true; 17 | 18 | public virtual bool HasActionSets 19 | { 20 | get { return false; } 21 | } 22 | 23 | public virtual bool HasPreview 24 | { 25 | get { return false; } 26 | } 27 | 28 | public string IconAutomationText 29 | { 30 | get { return null; } 31 | } 32 | 33 | public virtual ImageMoniker IconMoniker 34 | { 35 | get { return default(ImageMoniker); } 36 | } 37 | 38 | public string InputGestureText 39 | { 40 | get { return null; } 41 | } 42 | 43 | public virtual void Dispose() 44 | { 45 | // nothing to dispose 46 | } 47 | 48 | public virtual Task> GetActionSetsAsync(CancellationToken cancellationToken) 49 | { 50 | return System.Threading.Tasks.Task.FromResult>(null); 51 | } 52 | 53 | public Task GetPreviewAsync(CancellationToken cancellationToken) 54 | { 55 | return null; 56 | } 57 | 58 | public void Invoke(CancellationToken cancellationToken) 59 | { 60 | ThreadHelper.ThrowIfNotOnUIThread(); 61 | 62 | var dte = Package.GetGlobalService(typeof(DTE)) as DTE; 63 | 64 | try 65 | { 66 | dte.UndoContext.Open(DisplayText); 67 | Execute(cancellationToken); 68 | Telemetry.TrackUserTask("LightBulb-" + DisplayText); 69 | } 70 | finally 71 | { 72 | dte.UndoContext.Close(); 73 | } 74 | } 75 | 76 | public abstract void Execute(CancellationToken cancellationToken); 77 | 78 | public bool TryGetTelemetryId(out Guid telemetryId) 79 | { 80 | telemetryId = Guid.Empty; 81 | return false; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/SuggestedActions/DeleteSectionAction.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using Microsoft.VisualStudio.Imaging; 3 | using Microsoft.VisualStudio.Imaging.Interop; 4 | using Microsoft.VisualStudio.Text; 5 | using System.Linq; 6 | 7 | namespace EditorConfig 8 | { 9 | class DeleteSectionAction : BaseSuggestedAction 10 | { 11 | private ITextBuffer _buffer; 12 | private Section _section; 13 | 14 | public DeleteSectionAction(ITextBuffer buffer, Section section) 15 | { 16 | _buffer = buffer; 17 | _section = section; 18 | } 19 | 20 | public override string DisplayText 21 | { 22 | get { return "Remove Section"; } 23 | } 24 | 25 | public override ImageMoniker IconMoniker 26 | { 27 | get { return KnownMonikers.Cancel; } 28 | } 29 | 30 | public override void Execute(CancellationToken cancellationToken) 31 | { 32 | ITextSnapshotLine first = _buffer.CurrentSnapshot.GetLineFromPosition(_section.Span.Start); 33 | ITextSnapshotLine last = _buffer.CurrentSnapshot.GetLineFromPosition(_section.Span.End); 34 | 35 | if (_buffer.CurrentSnapshot.LineCount > last.LineNumber + 1) 36 | { 37 | ITextSnapshotLine nextLine = _buffer.CurrentSnapshot.GetLineFromLineNumber(last.LineNumber + 1); 38 | if (nextLine.Extent.IsEmpty) 39 | last = nextLine; 40 | } 41 | 42 | using (ITextEdit edit = _buffer.CreateEdit()) 43 | { 44 | edit.Delete(Span.FromBounds(first.Start, last.EndIncludingLineBreak)); 45 | edit.Apply(); 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/SuggestedActions/RemoveDuplicatePropertiesAction.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Imaging; 2 | using Microsoft.VisualStudio.Imaging.Interop; 3 | using Microsoft.VisualStudio.Text; 4 | using Microsoft.VisualStudio.Text.Editor; 5 | using System.Linq; 6 | using System.Threading; 7 | using System.Collections.Generic; 8 | 9 | namespace EditorConfig 10 | { 11 | class RemoveDuplicatePropertiesAction : BaseSuggestedAction 12 | { 13 | private Section _section; 14 | private ITextView _view; 15 | 16 | public RemoveDuplicatePropertiesAction(Section section, ITextView view) 17 | { 18 | _section = section; 19 | _view = view; 20 | } 21 | 22 | public override string DisplayText 23 | { 24 | get { return "Remove duplicates"; } 25 | } 26 | 27 | public override ImageMoniker IconMoniker 28 | { 29 | get { return KnownMonikers.CleanData; } 30 | } 31 | 32 | public override bool IsEnabled 33 | { 34 | get 35 | { 36 | return _section.Properties.Any(p => p.Keyword.Errors.Any(e => e.Name == ErrorCatalog.DuplicateProperty.Code || e.Name == ErrorCatalog.ParentDuplicateProperty.Code)); 37 | } 38 | } 39 | 40 | public override void Execute(CancellationToken cancellationToken) 41 | { 42 | SnapshotPoint caretPost = _view.Caret.Position.BufferPosition; 43 | IEnumerable duplicates = _section.Properties.Where(p => p.Keyword.Errors.Any(e => e.Name == ErrorCatalog.DuplicateProperty.Code || e.Name == ErrorCatalog.ParentDuplicateProperty.Code)); 44 | 45 | using (ITextEdit edit = _view.TextBuffer.CreateEdit()) 46 | { 47 | foreach (Property dupe in duplicates.Reverse()) 48 | { 49 | ITextSnapshotLine line = _view.TextBuffer.CurrentSnapshot.GetLineFromPosition(dupe.Span.Start); 50 | edit.Delete(line.ExtentIncludingLineBreak); 51 | } 52 | 53 | if (edit.HasEffectiveChanges) 54 | edit.Apply(); 55 | } 56 | 57 | _view.Caret.MoveTo(new SnapshotPoint(_view.TextBuffer.CurrentSnapshot, caretPost)); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/SuggestedActions/SortAllPropertiesAction.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Imaging; 2 | using Microsoft.VisualStudio.Imaging.Interop; 3 | using Microsoft.VisualStudio.Text; 4 | using Microsoft.VisualStudio.Text.Editor; 5 | using System.Threading; 6 | 7 | namespace EditorConfig 8 | { 9 | class SortAllPropertiesAction : BaseSuggestedAction 10 | { 11 | private EditorConfigDocument _document; 12 | private ITextView _view; 13 | 14 | public SortAllPropertiesAction(EditorConfigDocument document, ITextView view) 15 | { 16 | _document = document; 17 | _view = view; 18 | } 19 | 20 | public override string DisplayText 21 | { 22 | get { return "Sort Properties in All Sections"; } 23 | } 24 | 25 | public override ImageMoniker IconMoniker 26 | { 27 | get { return KnownMonikers.SortAscending; } 28 | } 29 | 30 | public override void Execute(CancellationToken cancellationToken) 31 | { 32 | SnapshotPoint caretPost = _view.Caret.Position.BufferPosition; 33 | 34 | using (ITextEdit edit = _document.TextBuffer.CreateEdit()) 35 | { 36 | foreach (Section section in _document.Sections) 37 | { 38 | SortPropertiesAction.SortSection(section, edit); 39 | } 40 | 41 | if (edit.HasEffectiveChanges) 42 | edit.Apply(); 43 | } 44 | 45 | _view.Caret.MoveTo(new SnapshotPoint(_view.TextBuffer.CurrentSnapshot, caretPost)); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/SuggestedActions/SortPropertiesAction.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Imaging; 2 | using Microsoft.VisualStudio.Imaging.Interop; 3 | using Microsoft.VisualStudio.Text; 4 | using Microsoft.VisualStudio.Text.Editor; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Collections.Generic; 9 | 10 | namespace EditorConfig 11 | { 12 | class SortPropertiesAction : BaseSuggestedAction 13 | { 14 | private Section _section; 15 | private ITextView _view; 16 | 17 | public SortPropertiesAction(Section section, ITextView view) 18 | { 19 | _section = section; 20 | _view = view; 21 | } 22 | 23 | public override string DisplayText 24 | { 25 | get { return "Sort Properties in Section"; } 26 | } 27 | 28 | public override ImageMoniker IconMoniker 29 | { 30 | get { return KnownMonikers.SortAscending; } 31 | } 32 | 33 | public override void Execute(CancellationToken cancellationToken) 34 | { 35 | SnapshotPoint caretPost = _view.Caret.Position.BufferPosition; 36 | 37 | using (ITextEdit edit = _view.TextBuffer.CreateEdit()) 38 | { 39 | SortSection(_section, edit); 40 | 41 | if (edit.HasEffectiveChanges) 42 | edit.Apply(); 43 | } 44 | 45 | _view.Caret.MoveTo(new SnapshotPoint(_view.TextBuffer.CurrentSnapshot, caretPost)); 46 | } 47 | 48 | public static void SortSection(Section section, ITextEdit edit) 49 | { 50 | Property first = section.Properties.FirstOrDefault(); 51 | Property last = section.Properties.LastOrDefault(); 52 | 53 | if (first == null) 54 | return; 55 | 56 | IEnumerable bufferLines = edit.Snapshot.Lines.Where(l => l.Start >= first.Span.Start && l.End <= last.Span.End); 57 | IEnumerable lines = bufferLines.Select(b => b.GetText()); 58 | 59 | IOrderedEnumerable properties = lines.OrderBy(l => l.IndexOf("csharp_") + l.IndexOf("dotnet_")) 60 | .ThenBy(p => p); 61 | 62 | var sb = new StringBuilder(); 63 | sb.AppendLine(section.Item.Text); 64 | 65 | foreach (string property in properties.Where(p => !string.IsNullOrWhiteSpace(p))) 66 | { 67 | sb.AppendLine(property); 68 | } 69 | 70 | edit.Replace(section.Span, sb.ToString().TrimEnd()); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/SuggestedActions/SuggestedActionsSource.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Language.Intellisense; 2 | using Microsoft.VisualStudio.Text; 3 | using Microsoft.VisualStudio.Text.Editor; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace EditorConfig 11 | { 12 | class SuggestedActionsSource : ISuggestedActionsSource 13 | { 14 | private ITextView _view; 15 | private EditorConfigDocument _document; 16 | private Section _section; 17 | 18 | public SuggestedActionsSource(ITextView view, ITextBuffer buffer) 19 | { 20 | _view = view; 21 | _document = EditorConfigDocument.FromTextBuffer(buffer); 22 | } 23 | 24 | public Task HasSuggestedActionsAsync(ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, CancellationToken cancellationToken) 25 | { 26 | _section = _document.Sections.FirstOrDefault(s => s.Span.Contains(range.Start)); 27 | 28 | return Task.FromResult(_section != null); 29 | } 30 | 31 | public IEnumerable GetSuggestedActions(ISuggestedActionCategorySet requestedActionCategories, SnapshotSpan range, CancellationToken cancellationToken) 32 | { 33 | var list = new List(); 34 | 35 | if (_section != null) 36 | { 37 | var removeDuplicate = new RemoveDuplicatePropertiesAction(_section, _view); 38 | if (removeDuplicate.IsEnabled) 39 | list.AddRange(CreateActionSet(removeDuplicate)); 40 | 41 | var sortProperties = new SortPropertiesAction(_section, _view); 42 | var sortAllProperties = new SortAllPropertiesAction(_document, _view); 43 | list.AddRange(CreateActionSet(sortProperties, sortAllProperties)); 44 | 45 | var deleteSection = new DeleteSectionAction(range.Snapshot.TextBuffer, _section); 46 | list.AddRange(CreateActionSet(deleteSection)); 47 | 48 | // Suppressions 49 | IEnumerable items = _document.ItemsInSpan(range).Where(p => p.HasErrors); 50 | if (items.Any()) 51 | { 52 | IEnumerable errors = items.SelectMany(i => i.Errors); 53 | var actions = new List(); 54 | 55 | foreach ( DisplayError error in errors ) 56 | { 57 | var action = new SuppressErrorAction(_document, error.Name); 58 | 59 | if ( action.IsEnabled ) 60 | actions.Add(action); 61 | } 62 | list.AddRange(CreateActionSet(actions.ToArray())); 63 | } 64 | 65 | // Missing rules 66 | List missingRules = AddMissingRulesAction.FindMissingRulesAll(_document.GetAllIncludedRules()); 67 | if (missingRules.Count() != 0) 68 | { 69 | var addMissingRules = new AddMissingRulesAction(missingRules, _document, _view); 70 | list.AddRange(CreateActionSet(addMissingRules)); 71 | } 72 | } 73 | 74 | return list; 75 | } 76 | 77 | public IEnumerable CreateActionSet(params BaseSuggestedAction[] actions) 78 | { 79 | return new[] { new SuggestedActionSet(actions) }; 80 | } 81 | 82 | public void Dispose() 83 | { 84 | } 85 | 86 | public bool TryGetTelemetryId(out Guid telemetryId) 87 | { 88 | // This is a sample provider and doesn't participate in LightBulb telemetry 89 | telemetryId = Guid.Empty; 90 | return false; 91 | } 92 | 93 | 94 | public event EventHandler SuggestedActionsChanged 95 | { 96 | add { } 97 | remove { } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/SuggestedActions/SuggestedActionsSourceProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Language.Intellisense; 2 | using Microsoft.VisualStudio.Text; 3 | using Microsoft.VisualStudio.Text.Editor; 4 | using Microsoft.VisualStudio.Utilities; 5 | using System.ComponentModel.Composition; 6 | 7 | namespace EditorConfig 8 | { 9 | [Export(typeof(ISuggestedActionsSourceProvider))] 10 | [Name("Editor Config Suggested Actions")] 11 | [ContentType(Constants.LanguageName)] 12 | class SuggestedActionsSourceProvider : ISuggestedActionsSourceProvider 13 | { 14 | public ISuggestedActionsSource CreateSuggestedActionsSource(ITextView textView, ITextBuffer buffer) 15 | { 16 | return textView.Properties.GetOrCreateSingletonProperty(() => new SuggestedActionsSource(textView, buffer)); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/SuggestedActions/SuppressErrorAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading; 4 | using Microsoft.VisualStudio.Imaging; 5 | using Microsoft.VisualStudio.Imaging.Interop; 6 | 7 | namespace EditorConfig 8 | { 9 | class SuppressErrorAction : BaseSuggestedAction 10 | { 11 | private const string _suppressFormat = "# Suppress: {0}"; 12 | private EditorConfigDocument _document; 13 | string _errorCode; 14 | 15 | public SuppressErrorAction(EditorConfigDocument document, string errorCode) 16 | { 17 | _document = document; 18 | _errorCode = errorCode; 19 | } 20 | 21 | public override string DisplayText 22 | { 23 | get { return $"Suppress {_errorCode}"; } 24 | } 25 | 26 | public override ImageMoniker IconMoniker => KnownMonikers.ValidationRule; 27 | 28 | public override bool IsEnabled 29 | { 30 | get 31 | { 32 | return !_document.Suppressions.Contains(_errorCode, StringComparer.OrdinalIgnoreCase); 33 | } 34 | } 35 | 36 | public override void Execute(CancellationToken cancellationToken) 37 | { 38 | var validator = EditorConfigValidator.FromDocument(_document); 39 | validator.SuppressError(_errorCode); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Validation/Commands/SuppressError.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Shell; 2 | using Microsoft.VisualStudio.Shell.TableControl; 3 | using Microsoft.VisualStudio.Shell.TableManager; 4 | using Microsoft.VisualStudio.Text.Editor; 5 | using System; 6 | using System.ComponentModel.Design; 7 | 8 | namespace EditorConfig 9 | { 10 | internal sealed class SuppressError 11 | { 12 | private readonly Package _package; 13 | private Error _selectedError; 14 | private string _filePath; 15 | 16 | private SuppressError(Package package, OleMenuCommandService commandService) 17 | { 18 | _package = package ?? throw new ArgumentNullException(nameof(package)); 19 | 20 | var cmdId = new CommandID(PackageGuids.guidEditorConfigPackageCmdSet, PackageIds.SuppressErrorId); 21 | var menuItem = new OleMenuCommand(Execute, cmdId); 22 | menuItem.BeforeQueryStatus += BeforeQueryStatus; 23 | commandService.AddCommand(menuItem); 24 | } 25 | 26 | public static SuppressError Instance 27 | { 28 | get; 29 | private set; 30 | } 31 | 32 | private IServiceProvider ServiceProvider 33 | { 34 | get { return _package; } 35 | } 36 | 37 | public static void Initialize(Package package, OleMenuCommandService commandService) 38 | { 39 | Instance = new SuppressError(package, commandService); 40 | } 41 | 42 | private void BeforeQueryStatus(object sender, EventArgs e) 43 | { 44 | var button = (OleMenuCommand)sender; 45 | button.Enabled = button.Visible = false; 46 | 47 | var errorList = VsHelpers.DTE.ToolWindows.ErrorList as IErrorList; 48 | ITableEntryHandle entry = errorList.TableControl.SelectedEntry; 49 | 50 | if (entry == null || !entry.TryGetValue(StandardTableKeyNames.ErrorCode, out string content)) 51 | return; 52 | 53 | if (!ErrorCatalog.TryGetErrorCode(content, out _selectedError)) 54 | return; 55 | 56 | if (entry == null || !entry.TryGetValue(StandardTableKeyNames.DocumentName, out _filePath)) 57 | return; 58 | 59 | button.Visible = button.Enabled = true; 60 | button.Text = "Suppress " + _selectedError.Code; 61 | } 62 | 63 | private void Execute(object sender, EventArgs e) 64 | { 65 | ThreadHelper.ThrowIfNotOnUIThread(); 66 | 67 | try 68 | { 69 | if (TextViewUtil.TryGetWpfTextView(_filePath, out IWpfTextView view)) 70 | { 71 | var document = EditorConfigDocument.FromTextBuffer(view.TextBuffer); 72 | var validator = EditorConfigValidator.FromDocument(document); 73 | validator.SuppressError(_selectedError.Code); 74 | } 75 | } 76 | catch (Exception ex) 77 | { 78 | Telemetry.TrackException("SuppressError", ex); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Validation/Error.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Imaging; 2 | using Microsoft.VisualStudio.Imaging.Interop; 3 | using System; 4 | using System.Linq; 5 | 6 | namespace EditorConfig 7 | { 8 | public class Error : ITooltip 9 | { 10 | private Func _isSupported; 11 | 12 | public Error(string code, ErrorCategory type, string format, Func isSupported) 13 | { 14 | Code = code; 15 | Category = type; 16 | DescriptionFormat = format; 17 | Description = string.Format(format, "x", "y", "z", "a", "b", "c"); 18 | _isSupported = isSupported; 19 | } 20 | 21 | /// The error code is displayed in the Error List. 22 | public string Code { get; } 23 | 24 | /// A short description of the error. 25 | public string Description { get; set; } 26 | 27 | public string DescriptionFormat { get; } 28 | 29 | /// The error category determines how to display the error in the Error List. 30 | public ErrorCategory Category { get; } 31 | 32 | string ITooltip.Name => Code; 33 | public ImageMoniker Moniker => KnownMonikers.ValidationRule; 34 | public bool IsSupported => _isSupported(); 35 | 36 | public void Run(ParseItem item, Action action) 37 | { 38 | Run(item, true, action); 39 | } 40 | 41 | public void Run(ParseItem item, bool enabled, Action action) 42 | { 43 | if (enabled && item != null && !item.HasErrors && IsSupported && !item.Document.Suppressions.Contains(Code, StringComparer.OrdinalIgnoreCase)) 44 | { 45 | action.Invoke(new DisplayError(this, item)); 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Validation/ErrorCatalog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace EditorConfig 6 | { 7 | public static class ErrorCatalog 8 | { 9 | private static ValidationOptions _o = EditorConfigPackage.ValidationOptions; 10 | private static List _errors = new List(); 11 | 12 | public static IReadOnlyList All 13 | { 14 | get 15 | { 16 | return _errors; 17 | } 18 | } 19 | 20 | public static Error DuplicateProperty { get; } = 21 | Create("EC101", ErrorCategory.Warning, Resources.Text.ValidationDuplicateProperty, () => _o.EnableDuplicateProperties); 22 | public static Error DuplicateSection { get; } = 23 | Create("EC102", ErrorCategory.Warning, Resources.Text.ValidationDuplicateSection, () => _o.EnableDuplicateSections); 24 | public static Error GlobbingNoMatch { get; } = 25 | Create("EC103", ErrorCategory.Suggestion, Resources.Text.ValidationNoMatch, () => _o.EnableGlobbingMatcher); 26 | public static Error MissingSeverity { get; } = 27 | Create("EC104", ErrorCategory.Error, Resources.Text.ValidationMissingSeverity); 28 | public static Error MissingValue { get; } = 29 | Create("EC105", ErrorCategory.Error, Resources.Text.ValidationMissingPropertyValue); 30 | public static Error OnlyRootAllowd { get; } = 31 | Create("EC106", ErrorCategory.Error, Resources.Text.ValidateOnlyRootAllowed); 32 | public static Error ParentDuplicateProperty { get; } = 33 | Create("EC107", ErrorCategory.Suggestion, Resources.Text.ValidationParentPropertyDuplicate, () => _o.EnableDuplicateFoundInParent); 34 | public static Error RootInSection { get; } = 35 | Create("EC108", ErrorCategory.Warning, Resources.Text.ValidationRootInSection); 36 | public static Error SectionSyntaxError { get; } = 37 | Create("EC109", ErrorCategory.Error, Resources.Text.ValidationSectionSyntaxError); 38 | public static Error SeverityNotApplicable { get; } = 39 | Create("EC110", ErrorCategory.Error, Resources.Text.ValidationSeverityNotApplicable); 40 | public static Error UnknownElement { get; } = 41 | Create("EC111", ErrorCategory.Error, Resources.Text.ValidationUnknownElement); 42 | public static Error UnknownKeyword { get; } = 43 | Create("EC112", ErrorCategory.Warning, Resources.Text.ValidateUnknownKeyword, () => _o.EnableUnknownProperties); 44 | public static Error UnknownSeverity { get; } = 45 | Create("EC113", ErrorCategory.Warning, Resources.Text.ValidationInvalidSeverity); 46 | public static Error UnknownValue { get; } = 47 | Create("EC114", ErrorCategory.Warning, Resources.Text.InvalidValue, () => _o.EnableUnknownValues); 48 | public static Error TabWidthUnneeded { get; } = 49 | Create("EC115", ErrorCategory.Suggestion, Resources.Text.ValidationTabWidthUnneeded); 50 | public static Error IndentSizeUnneeded { get; } = 51 | Create("EC116", ErrorCategory.Suggestion, Resources.Text.ValidationIndentSizeUnneeded); 52 | public static Error SpaceInSection { get; } = 53 | Create("EC117", ErrorCategory.Suggestion, Resources.Text.ValidationSpaceInSection, () => !_o.AllowSpacesInSections); 54 | public static Error UnknownStyle { get; } = 55 | Create("EC118", ErrorCategory.Error, Resources.Text.ValidationUnknownStyle); 56 | public static Error UnusedStyle { get; } = 57 | Create("EC119", ErrorCategory.Suggestion, Resources.Text.ValidationUnusedStyle); 58 | public static Error NamingRuleReordered { get; } = 59 | Create("EC120", ErrorCategory.Warning, Resources.Text.NamingRuleReordered); 60 | 61 | public static bool TryGetErrorCode(string code, out Error errorCode) 62 | { 63 | errorCode = All.FirstOrDefault(c => c.Code.Equals(code)); 64 | return errorCode != null; 65 | } 66 | 67 | private static Error Create(string errorCode, ErrorCategory type, string message) 68 | { 69 | return Create(errorCode, type, message, () => true); 70 | } 71 | 72 | private static Error Create(string errorCode, ErrorCategory type, string message, Func isSupported) 73 | { 74 | var ec = new Error(errorCode, type, message, isSupported); 75 | _errors.Add(ec); 76 | 77 | return ec; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Validation/ErrorCategory.cs: -------------------------------------------------------------------------------- 1 | namespace EditorConfig 2 | { 3 | /// The error type determines how the error is represented in the Error List. 4 | public enum ErrorCategory 5 | { 6 | Error, 7 | Warning, 8 | Suggestion, 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Validation/ErrorList/DisplayError.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Imaging; 2 | using Microsoft.VisualStudio.Imaging.Interop; 3 | using Microsoft.VisualStudio.Text; 4 | 5 | namespace EditorConfig 6 | { 7 | public class DisplayError : ITooltip 8 | { 9 | private Error _error; 10 | private ParseItem _item; 11 | 12 | public DisplayError(Error error, ParseItem item) 13 | { 14 | _error = error; 15 | _item = item; 16 | Description = _error.Description; 17 | } 18 | 19 | /// The error code is displayed in the Error List. 20 | public string Name => _error.Code; 21 | 22 | /// A short description of the error. 23 | public string Description { get; private set; } 24 | 25 | /// The error category determines how to display the error in the Error List. 26 | public ErrorCategory Category => _error.Category; 27 | 28 | /// A URL pointing to documentation about the error. 29 | public string HelpLink => string.Format(Constants.HelpLink, Name.ToLowerInvariant()); 30 | 31 | /// The line number containing the error. 32 | public int Line { get; private set; } = 0; 33 | 34 | /// The column number containing the error. 35 | public int Column { get; private set; } = 0; 36 | 37 | public ImageMoniker Moniker => _error.Moniker; 38 | 39 | public bool IsSupported => _error.IsSupported; 40 | 41 | /// Register the error on the specified ParseItem. 42 | public void Register(params string[] tokens) 43 | { 44 | Register(_item, tokens); 45 | } 46 | 47 | /// Register the error on the specified ParseItem. 48 | public void Register(ParseItem item, params string[] tokens) 49 | { 50 | var span = new SnapshotSpan(item.Document.TextBuffer.CurrentSnapshot, item.Span); 51 | ITextSnapshotLine line = span.Snapshot.GetLineFromPosition(span.Start); 52 | 53 | Line = line.LineNumber; 54 | Column = span.Start.Position - line.Start.Position; 55 | Description = string.Format(_error.DescriptionFormat, tokens); 56 | 57 | item.AddError(this); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Validation/ErrorList/ErrorList.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using Microsoft.VisualStudio.Shell; 3 | using Microsoft.VisualStudio.Text; 4 | using Microsoft.VisualStudio.Text.Editor; 5 | using Microsoft.VisualStudio.Utilities; 6 | using System; 7 | using System.ComponentModel.Composition; 8 | using System.Linq; 9 | 10 | namespace EditorConfig 11 | { 12 | [Export(typeof(IWpfTextViewCreationListener))] 13 | [ContentType(Constants.LanguageName)] 14 | [TextViewRole(PredefinedTextViewRoles.PrimaryDocument)] 15 | public class ErrorList : IWpfTextViewCreationListener 16 | { 17 | private EditorConfigValidator _validator; 18 | private EditorConfigDocument _document; 19 | private Project _project; 20 | private string _file; 21 | 22 | [Import] 23 | private ITextDocumentFactoryService _documentService = null; 24 | 25 | public void TextViewCreated(IWpfTextView view) 26 | { 27 | ThreadHelper.ThrowIfNotOnUIThread(); 28 | 29 | if (_documentService.TryGetTextDocument(view.TextBuffer, out var doc)) 30 | { 31 | _file = doc.FilePath; 32 | view.Properties.AddProperty("file", doc.FilePath); 33 | } 34 | 35 | _document = EditorConfigDocument.FromTextBuffer(view.TextBuffer); 36 | _validator = EditorConfigValidator.FromDocument(_document); 37 | _project = VsHelpers.DTE.Solution?.FindProjectItem(_file)?.ContainingProject; 38 | 39 | view.Closed += ViewClosed; 40 | _validator.Validated += Validated; 41 | } 42 | 43 | private void Validated(object sender, EventArgs e) 44 | { 45 | UpdateErrorList(); 46 | } 47 | 48 | private void UpdateErrorList() 49 | { 50 | if (_document.IsParsing) 51 | return; 52 | 53 | ParseItem[] items = _document.ParseItems.Where(p => p.HasErrors).ToArray(); 54 | 55 | TableDataSource.Instance.CleanErrors(_file); 56 | TableDataSource.Instance.AddErrors(items, _project?.Name, _file); 57 | } 58 | 59 | private void ViewClosed(object sender, EventArgs e) 60 | { 61 | var view = (IWpfTextView)sender; 62 | view.Closed -= ViewClosed; 63 | 64 | if (view.Properties.TryGetProperty("file", out string file)) 65 | { 66 | TableDataSource.Instance.CleanErrors(file); 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Validation/ErrorList/SinkManager.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Shell.TableManager; 2 | using System.Linq; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace EditorConfig 7 | { 8 | class SinkManager : IDisposable 9 | { 10 | private readonly ITableDataSink _sink; 11 | private TableDataSource _errorList; 12 | private List _snapshots = new List(); 13 | 14 | internal SinkManager(TableDataSource errorList, ITableDataSink sink) 15 | { 16 | _sink = sink; 17 | _errorList = errorList; 18 | 19 | errorList.AddSinkManager(this); 20 | } 21 | 22 | internal void Clear() 23 | { 24 | _sink.RemoveAllSnapshots(); 25 | } 26 | 27 | internal void UpdateSink(IEnumerable snapshots) 28 | { 29 | foreach (TableEntriesSnapshot snapshot in snapshots) 30 | { 31 | TableEntriesSnapshot existing = _snapshots.FirstOrDefault(s => s.Url == snapshot.Url); 32 | 33 | if (existing != null) 34 | { 35 | _snapshots.Remove(existing); 36 | _sink.ReplaceSnapshot(existing, snapshot); 37 | } 38 | else 39 | { 40 | _sink.AddSnapshot(snapshot); 41 | } 42 | 43 | _snapshots.Add(snapshot); 44 | } 45 | } 46 | 47 | internal void RemoveSnapshots(IEnumerable urls) 48 | { 49 | foreach (string url in urls) 50 | { 51 | TableEntriesSnapshot existing = _snapshots.FirstOrDefault(s => s.Url == url); 52 | 53 | if (existing != null) 54 | { 55 | _snapshots.Remove(existing); 56 | _sink.RemoveSnapshot(existing); 57 | } 58 | } 59 | } 60 | 61 | public void Dispose() 62 | { 63 | // Called when the person who subscribed to the data source disposes of the cookie (== this object) they were given. 64 | _errorList.RemoveSinkManager(this); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Validation/ErrorList/TableEntriesSnapshot.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using Microsoft.VisualStudio.Shell.Interop; 3 | using Microsoft.VisualStudio.Shell.TableManager; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace EditorConfig 8 | { 9 | class TableEntriesSnapshot : TableEntriesSnapshotBase 10 | { 11 | private string _projectName; 12 | 13 | internal TableEntriesSnapshot(IEnumerable result, string projectName, string fileName) 14 | { 15 | _projectName = projectName; 16 | 17 | Errors = result.SelectMany(p => p.Errors).ToList(); 18 | Url = fileName; 19 | } 20 | 21 | public List Errors { get; private set; } 22 | 23 | public override int VersionNumber { get; } = 1; 24 | 25 | public override int Count 26 | { 27 | get { return Errors.Count; } 28 | } 29 | 30 | public string Url { get; private set; } 31 | 32 | public override bool TryGetValue(int index, string columnName, out object content) 33 | { 34 | if (index < 0 || index >= Errors.Count) 35 | { 36 | content = null; 37 | return false; 38 | } 39 | 40 | DisplayError error = Errors[index]; 41 | 42 | switch (columnName) 43 | { 44 | case StandardTableKeyNames.DocumentName: 45 | content = Url; 46 | return true; 47 | case StandardTableKeyNames.ErrorCategory: 48 | content = vsTaskCategories.vsTaskCategoryMisc; 49 | return true; 50 | case StandardTableKeyNames.Line: 51 | content = error.Line; 52 | return true; 53 | case StandardTableKeyNames.Column: 54 | content = error.Column; 55 | return true; 56 | case StandardTableKeyNames.FullText: 57 | case StandardTableKeyNames.Text: 58 | content = error.Description; 59 | return true; 60 | case StandardTableKeyNames.ErrorSeverity: 61 | content = GetSeverity(error); 62 | return true; 63 | case StandardTableKeyNames.Priority: 64 | content = vsTaskPriority.vsTaskPriorityMedium; 65 | return true; 66 | case StandardTableKeyNames.ErrorSource: 67 | content = ErrorSource.Other; 68 | return true; 69 | case StandardTableKeyNames.BuildTool: 70 | content = Vsix.Name; 71 | return true; 72 | case StandardTableKeyNames.ErrorCode: 73 | content = error.Name; 74 | return true; 75 | case StandardTableKeyNames.ProjectName: 76 | content = _projectName; 77 | return true; 78 | case StandardTableKeyNames.HelpLink: 79 | content = error.HelpLink; 80 | return true; 81 | default: 82 | content = null; 83 | return false; 84 | } 85 | } 86 | 87 | private __VSERRORCATEGORY GetSeverity(DisplayError error) 88 | { 89 | switch (error.Category) 90 | { 91 | case ErrorCategory.Error: 92 | return __VSERRORCATEGORY.EC_ERROR; 93 | case ErrorCategory.Warning: 94 | return __VSERRORCATEGORY.EC_WARNING; 95 | default: 96 | return __VSERRORCATEGORY.EC_MESSAGE; 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Validation/NamingStyles/Accessibility.cs: -------------------------------------------------------------------------------- 1 | namespace EditorConfig.Validation.NamingStyles 2 | { 3 | public enum Accessibility 4 | { 5 | NotApplicable, 6 | Private, 7 | ProtectedAndInternal, 8 | Protected, 9 | Internal, 10 | ProtectedOrInternal, 11 | Public, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Validation/NamingStyles/ModifierKind.cs: -------------------------------------------------------------------------------- 1 | namespace EditorConfig.Validation.NamingStyles 2 | { 3 | public enum ModifierKind 4 | { 5 | IsAbstract, 6 | IsStatic, 7 | IsAsync, 8 | IsReadOnly, 9 | IsConst, 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Validation/NamingStyles/NamingRule.cs: -------------------------------------------------------------------------------- 1 | namespace EditorConfig.Validation.NamingStyles 2 | { 3 | internal readonly struct NamingRule 4 | { 5 | public readonly string Name; 6 | public readonly SymbolSpecification SymbolSpecification; 7 | public readonly NamingStyle NamingStyle; 8 | public readonly ReportDiagnostic EnforcementLevel; 9 | 10 | public NamingRule(string name, SymbolSpecification symbolSpecification, NamingStyle namingStyle, ReportDiagnostic enforcementLevel) 11 | { 12 | Name = name; 13 | SymbolSpecification = symbolSpecification; 14 | NamingStyle = namingStyle; 15 | EnforcementLevel = enforcementLevel; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Validation/NamingStyles/NamingStyle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EditorConfig.Validation.NamingStyles 4 | { 5 | internal readonly struct NamingStyle 6 | { 7 | public NamingStyle(Guid id) 8 | { 9 | ID = id; 10 | } 11 | 12 | public Guid ID { get; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Validation/NamingStyles/NamingStylePreferences.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Immutable; 3 | using System.Linq; 4 | 5 | namespace EditorConfig.Validation.NamingStyles 6 | { 7 | internal class NamingStylePreferences 8 | { 9 | public readonly ImmutableArray SymbolSpecifications; 10 | public readonly ImmutableArray NamingStyles; 11 | public readonly ImmutableArray NamingRules; 12 | 13 | private readonly Lazy _lazyRules; 14 | 15 | internal NamingStylePreferences( 16 | ImmutableArray symbolSpecifications, 17 | ImmutableArray namingStyles, 18 | ImmutableArray namingRules) 19 | { 20 | SymbolSpecifications = symbolSpecifications; 21 | NamingStyles = namingStyles; 22 | NamingRules = namingRules; 23 | 24 | _lazyRules = new Lazy(CreateRules, isThreadSafe: true); 25 | } 26 | 27 | public NamingStyleRules Rules => _lazyRules.Value; 28 | 29 | internal NamingStyle GetNamingStyle(Guid namingStyleID) 30 | => NamingStyles.Single(s => s.ID == namingStyleID); 31 | 32 | internal SymbolSpecification GetSymbolSpecification(Guid symbolSpecificationID) 33 | => SymbolSpecifications.Single(s => s.ID == symbolSpecificationID); 34 | 35 | private NamingStyleRules CreateRules() 36 | => new NamingStyleRules(NamingRules.Select(r => r.GetRule(this)).ToImmutableArray()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Validation/NamingStyles/NamingStyleRules.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | 3 | namespace EditorConfig.Validation.NamingStyles 4 | { 5 | internal readonly struct NamingStyleRules 6 | { 7 | public NamingStyleRules(ImmutableArray namingRules) 8 | { 9 | NamingRules = namingRules; 10 | } 11 | 12 | public ImmutableArray NamingRules { get; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Validation/NamingStyles/ReportDiagnostic.cs: -------------------------------------------------------------------------------- 1 | namespace EditorConfig.Validation.NamingStyles 2 | { 3 | internal enum ReportDiagnostic 4 | { 5 | /// 6 | /// Report a diagnostic by default. 7 | /// 8 | Default = 0, 9 | 10 | /// 11 | /// Report a diagnostic as an error. 12 | /// 13 | Error = 1, 14 | 15 | /// 16 | /// Report a diagnostic as a warning even though /warnaserror is specified. 17 | /// 18 | Warn = 2, 19 | 20 | /// 21 | /// Report a diagnostic as an info. 22 | /// 23 | Info = 3, 24 | 25 | /// 26 | /// Report a diagnostic as hidden. 27 | /// 28 | Hidden = 4, 29 | 30 | /// 31 | /// Suppress a diagnostic. 32 | /// 33 | Suppress = 5, 34 | } 35 | } -------------------------------------------------------------------------------- /src/Validation/NamingStyles/SerializableNamingRule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EditorConfig.Validation.NamingStyles 4 | { 5 | internal sealed class SerializableNamingRule 6 | { 7 | public string Name; 8 | public Guid SymbolSpecificationID; 9 | public Guid NamingStyleID; 10 | public ReportDiagnostic EnforcementLevel; 11 | 12 | public NamingRule GetRule(NamingStylePreferences info) 13 | { 14 | return new NamingRule( 15 | Name, 16 | info.GetSymbolSpecification(SymbolSpecificationID), 17 | info.GetNamingStyle(NamingStyleID), 18 | EnforcementLevel); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Validation/NamingStyles/SymbolKindOrTypeKind.cs: -------------------------------------------------------------------------------- 1 | namespace EditorConfig.Validation.NamingStyles 2 | { 3 | internal enum SymbolKindOrTypeKind 4 | { 5 | #region Symbol kinds 6 | 7 | Namespace, 8 | Event, 9 | Field, 10 | Local, 11 | Method, 12 | Parameter, 13 | Property, 14 | 15 | #endregion 16 | 17 | #region Type kinds 18 | 19 | Class, 20 | Delegate, 21 | Enum, 22 | Interface, 23 | Module, 24 | Pointer, 25 | Struct, 26 | TypeParameter, 27 | 28 | #endregion 29 | 30 | #region Method kinds 31 | 32 | Ordinary, 33 | LocalFunction, 34 | 35 | #endregion 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Validation/NamingStyles/SymbolSpecification.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Immutable; 3 | 4 | namespace EditorConfig.Validation.NamingStyles 5 | { 6 | internal sealed class SymbolSpecification 7 | { 8 | internal static readonly ImmutableArray DefaultApplicableSymbolKindList = ImmutableArray.Create( 9 | SymbolKindOrTypeKind.Namespace, 10 | SymbolKindOrTypeKind.Class, 11 | SymbolKindOrTypeKind.Struct, 12 | SymbolKindOrTypeKind.Interface, 13 | SymbolKindOrTypeKind.Delegate, 14 | SymbolKindOrTypeKind.Enum, 15 | SymbolKindOrTypeKind.Module, 16 | SymbolKindOrTypeKind.Pointer, 17 | SymbolKindOrTypeKind.Property, 18 | SymbolKindOrTypeKind.Ordinary, 19 | SymbolKindOrTypeKind.LocalFunction, 20 | SymbolKindOrTypeKind.Field, 21 | SymbolKindOrTypeKind.Event, 22 | SymbolKindOrTypeKind.Parameter, 23 | SymbolKindOrTypeKind.TypeParameter, 24 | SymbolKindOrTypeKind.Local); 25 | 26 | internal static readonly ImmutableArray DefaultApplicableAccessibilityList = ImmutableArray.Create( 27 | Accessibility.NotApplicable, 28 | Accessibility.Public, 29 | Accessibility.Internal, 30 | Accessibility.Private, 31 | Accessibility.Protected, 32 | Accessibility.ProtectedAndInternal, 33 | Accessibility.ProtectedOrInternal); 34 | 35 | internal static readonly ImmutableArray DefaultRequiredModifierList = ImmutableArray.Empty; 36 | 37 | public Guid ID { get; } 38 | public string Name { get; } 39 | 40 | public ImmutableArray ApplicableSymbolKindList { get; } 41 | public ImmutableArray ApplicableAccessibilityList { get; } 42 | public ImmutableArray RequiredModifierList { get; } 43 | 44 | public SymbolSpecification( 45 | Guid? id, 46 | string symbolSpecName, 47 | ImmutableArray symbolKindList, 48 | ImmutableArray accessibilityList, 49 | ImmutableArray modifiers) 50 | { 51 | ID = id ?? Guid.NewGuid(); 52 | Name = symbolSpecName; 53 | ApplicableSymbolKindList = symbolKindList.IsDefault ? DefaultApplicableSymbolKindList : symbolKindList; 54 | ApplicableAccessibilityList = accessibilityList.IsDefault ? DefaultApplicableAccessibilityList : accessibilityList; 55 | RequiredModifierList = modifiers.IsDefault ? DefaultRequiredModifierList : modifiers; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Validation/Tagger/ErrorFormatDefinition.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.VisualStudio.Text.Adornments; 4 | using Microsoft.VisualStudio.Text.Classification; 5 | using Microsoft.VisualStudio.Utilities; 6 | using System.ComponentModel.Composition; 7 | using System.Windows.Media; 8 | 9 | namespace EditorConfig 10 | { 11 | public class ErrorFormatDefinition 12 | { 13 | public const string Suggestion = Constants.LanguageName + " Suggestion"; 14 | 15 | [Export(typeof(ErrorTypeDefinition))] 16 | [Name(Suggestion)] 17 | [DisplayName(Suggestion)] 18 | internal static ErrorTypeDefinition MessageDefinition = null; 19 | 20 | [Export(typeof(EditorFormatDefinition))] 21 | [Name(Suggestion)] 22 | [Order(After = Priority.High)] 23 | [UserVisible(true)] 24 | internal class MessageFormat : EditorFormatDefinition 25 | { 26 | public MessageFormat() 27 | { 28 | DisplayName = Suggestion; 29 | ForegroundColor = (Color)ColorConverter.ConvertFromString("#CCc0c0c0"); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Validation/Tagger/ErrorTagger.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Shell; 2 | using Microsoft.VisualStudio.Text; 3 | using Microsoft.VisualStudio.Text.Adornments; 4 | using Microsoft.VisualStudio.Text.Editor; 5 | using Microsoft.VisualStudio.Text.Tagging; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using Task = System.Threading.Tasks.Task; 10 | 11 | namespace EditorConfig 12 | { 13 | class ErrorTagger : ITagger, IDisposable 14 | { 15 | private EditorConfigDocument _document; 16 | private IWpfTextView _view; 17 | private EditorConfigValidator _validator; 18 | private bool _hasLoaded; 19 | 20 | public ErrorTagger(IWpfTextView view) 21 | { 22 | _view = view; 23 | 24 | _document = EditorConfigDocument.FromTextBuffer(view.TextBuffer); 25 | _validator = EditorConfigValidator.FromDocument(_document); 26 | _validator.Validated += DocumentValidated; 27 | 28 | ThreadHelper.JoinableTaskFactory.StartOnIdle( 29 | () => 30 | { 31 | _hasLoaded = true; 32 | var span = new SnapshotSpan(view.TextBuffer.CurrentSnapshot, 0, view.TextBuffer.CurrentSnapshot.Length); 33 | TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(span)); 34 | return Task.CompletedTask; 35 | }, 36 | VsTaskRunContext.UIThreadIdlePriority); 37 | } 38 | 39 | private void DocumentValidated(object sender, EventArgs e) 40 | { 41 | var span = new SnapshotSpan(_view.TextBuffer.CurrentSnapshot, 0, _view.TextBuffer.CurrentSnapshot.Length); 42 | TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(span)); 43 | } 44 | 45 | public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) 46 | { 47 | var tags = new List>(); 48 | 49 | if (_document.IsParsing || _validator.IsValidating || !_hasLoaded || !spans.Any() || spans[0].IsEmpty) 50 | return tags; 51 | 52 | ITextSnapshotLine line = spans[0].Start.GetContainingLine(); 53 | IEnumerable items = _document.ItemsInSpan(line.Extent); 54 | 55 | foreach (ParseItem item in items) 56 | { 57 | tags.AddRange(CreateError(item)); 58 | } 59 | 60 | return tags; 61 | } 62 | 63 | private IEnumerable> CreateError(ParseItem item) 64 | { 65 | foreach (DisplayError error in item.Errors) 66 | { 67 | var span = new SnapshotSpan(_view.TextBuffer.CurrentSnapshot, item.Span); 68 | string errorType = GetErrorType(error.Category); 69 | 70 | yield return new TagSpan(span, new ErrorTag(errorType, error.Name)); 71 | } 72 | } 73 | 74 | public static string GetErrorType(ErrorCategory errorType) 75 | { 76 | switch (errorType) 77 | { 78 | case ErrorCategory.Error: 79 | return PredefinedErrorTypeNames.SyntaxError; 80 | case ErrorCategory.Warning: 81 | return PredefinedErrorTypeNames.Warning; 82 | } 83 | 84 | return ErrorFormatDefinition.Suggestion; 85 | } 86 | 87 | public void Dispose() 88 | { 89 | _validator.Validated -= DocumentValidated; 90 | } 91 | 92 | public event EventHandler TagsChanged; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Validation/Tagger/ErrorTaggerProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Text; 2 | using Microsoft.VisualStudio.Text.Editor; 3 | using Microsoft.VisualStudio.Text.Tagging; 4 | using Microsoft.VisualStudio.Utilities; 5 | using System.ComponentModel.Composition; 6 | 7 | namespace EditorConfig 8 | { 9 | [Export(typeof(ITaggerProvider))] 10 | [ContentType(Constants.LanguageName)] 11 | [TagType(typeof(ErrorTag))] 12 | class ErrorTaggerProvider : ITaggerProvider 13 | { 14 | public ITagger CreateTagger(ITextBuffer buffer) where T : ITag 15 | { 16 | if (buffer.Properties.TryGetProperty(typeof(IWpfTextView), out IWpfTextView view)) 17 | { 18 | return buffer.Properties.GetOrCreateSingletonProperty(() => new ErrorTagger(view)) as ITagger; 19 | } 20 | 21 | return null; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Validation/ValidationOptions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Shell; 2 | using System; 3 | using System.ComponentModel; 4 | 5 | namespace EditorConfig 6 | { 7 | public class ValidationOptions : DialogPage 8 | { 9 | // General 10 | private const string _general = "General"; 11 | 12 | [Category(_general)] 13 | [DisplayName("Enable validation")] 14 | [Description("This will enable the validator to run on the document.")] 15 | [DefaultValue(true)] 16 | public bool EnableValidation { get; set; } = true; 17 | 18 | [Category(_general)] 19 | [DisplayName("Display errors as warnings")] 20 | [Description("This will make errors found in the document show up as warnings in the Error List.")] 21 | [DefaultValue(true)] 22 | public bool ShowErrorsAsWarnings { get; set; } = true; 23 | 24 | // Rules 25 | private const string _rules = "Rules"; 26 | 27 | [Category(_rules)] 28 | [DisplayName("Validate unknown properties")] 29 | [Description("This will show errors for unknown properties. It is a good way to catch typos.")] 30 | [DefaultValue(true)] 31 | public bool EnableUnknownProperties { get; set; } = true; 32 | 33 | [Category(_rules)] 34 | [DisplayName("Validate unknown values")] 35 | [Description("This will show errors for unknown property values.")] 36 | [DefaultValue(true)] 37 | public bool EnableUnknownValues { get; set; } = true; 38 | 39 | [Category(_rules)] 40 | [DisplayName("Validate duplicate sections")] 41 | [Description("This will show errors when a section has already been defined earlier in the document.")] 42 | [DefaultValue(true)] 43 | public bool EnableDuplicateSections { get; set; } = true; 44 | 45 | [Category(_rules)] 46 | [DisplayName("Validate duplicate properties")] 47 | [Description("This will show errors when a property has already been defined earlier in the section.")] 48 | [DefaultValue(true)] 49 | public bool EnableDuplicateProperties { get; set; } = true; 50 | 51 | [Category(_rules)] 52 | [DisplayName("Validate parent overrides")] 53 | [Description("Show an error if a property was also defined in a parent document with the same value and severity.")] 54 | [DefaultValue(true)] 55 | public bool EnableDuplicateFoundInParent { get; set; } = true; 56 | 57 | // Sections 58 | private const string _sections = "Sections"; 59 | 60 | [Category(_sections)] 61 | [DisplayName("Validate globbing patterns")] 62 | [Description("Show an error if a globbing pattern isn't matching any files on disk.")] 63 | [DefaultValue(true)] 64 | public bool EnableGlobbingMatcher { get; set; } = true; 65 | 66 | [Category(_sections)] 67 | [DisplayName("Allow spaces in sections")] 68 | [Description("Spaces in globbing patterns are allowed, but are often the result of a typo.")] 69 | [DefaultValue(false)] 70 | public bool AllowSpacesInSections { get; set; } 71 | 72 | public override void SaveSettingsToStorage() 73 | { 74 | Telemetry.TrackOperation("ValidationOptionsSaved"); 75 | base.SaveSettingsToStorage(); 76 | Saved?.Invoke(this, EventArgs.Empty); 77 | } 78 | 79 | public static event EventHandler Saved; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/icons.pkgdef: -------------------------------------------------------------------------------- 1 |  2 | [$RootKey$\ShellFileAssociations\.editorconfig] 3 | "DefaultIconMoniker"="666770e6-562f-46d7-a555-3a0cdffe94d2:1" -------------------------------------------------------------------------------- /src/source.extension.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // This file was generated by Extensibility Tools v1.10.211 4 | // 5 | // ------------------------------------------------------------------------------ 6 | namespace EditorConfig 7 | { 8 | static class Vsix 9 | { 10 | public const string Id = "1209461d-57f8-46a4-814a-dbe5fecef941"; 11 | public const string Name = "EditorConfig Language Service"; 12 | public const string Description = @"Language service for .editorconfig files. 13 | 14 | EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs."; 15 | public const string Language = "en-US"; 16 | public const string Version = "1.17"; 17 | public const string Author = "Mads Kristensen"; 18 | public const string Tags = "editorconfig"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/source.extension.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfigLanguage/5848368ab1b727ea313a0aad29c7cdc529390a5f/src/source.extension.ico -------------------------------------------------------------------------------- /src/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | EditorConfig Language Service 6 | Language service for .editorconfig files. 7 | 8 | EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs. 9 | https://github.com/madskristensen/EditorConfigLanguage 10 | Resources\LICENSE 11 | https://github.com/madskristensen/EditorConfigLanguage/blob/master/CHANGELOG.md 12 | Resources\Icon.png 13 | Resources\Icon.png 14 | editorconfig 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | --------------------------------------------------------------------------------