├── art └── screenshot.png ├── src ├── EditorConfig │ ├── logo.png │ ├── License.txt │ ├── Classify │ │ ├── EditorClassifierClassifierProvider.cs │ │ └── EditorConfigClassifier.cs │ ├── ContentType │ │ └── EditorConfigContentTypeDefinition.cs │ ├── source.extension.vsixmanifest │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Completion │ │ ├── CompletionItem.cs │ │ ├── EditorConfigCompletionSource.cs │ │ └── EditorConfigCompletionController.cs │ ├── EditorConfigTextViewCreationListener.cs │ ├── Validation │ │ └── EditorConfigErrorTag.cs │ └── EditorConfig.csproj └── EditorConfig.sln ├── .gitattributes ├── README.md └── .gitignore /art/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfig/master/art/screenshot.png -------------------------------------------------------------------------------- /src/EditorConfig/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/EditorConfig/master/src/EditorConfig/logo.png -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/EditorConfig/License.txt: -------------------------------------------------------------------------------- 1 | Copyright 2014 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. -------------------------------------------------------------------------------- /src/EditorConfig/Classify/EditorClassifierClassifierProvider.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(EditorConfigContentTypeDefinition.EditorConfigContentType)] 10 | class EditorConfigClassifierProvider : IClassifierProvider 11 | { 12 | [Import] 13 | public IClassificationTypeRegistryService Registry { get; set; } 14 | 15 | public IClassifier GetClassifier(ITextBuffer textBuffer) 16 | { 17 | return textBuffer.Properties.GetOrCreateSingletonProperty(() => new EditorConfigClassifier(Registry)); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/EditorConfig/ContentType/EditorConfigContentTypeDefinition.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.Composition; 2 | using Microsoft.VisualStudio.Utilities; 3 | 4 | namespace EditorConfig 5 | { 6 | class EditorConfigContentTypeDefinition 7 | { 8 | public const string EditorConfigContentType = "EditorConfig"; 9 | 10 | [Export(typeof(ContentTypeDefinition))] 11 | [Name(EditorConfigContentType)] 12 | [BaseDefinition("code")] 13 | public ContentTypeDefinition IEditorConfigContentType { get; set; } 14 | 15 | [Export(typeof(FileExtensionToContentTypeDefinition))] 16 | [ContentType(EditorConfigContentType)] 17 | [FileExtension(".editorconfig")] 18 | public FileExtensionToContentTypeDefinition EditorConfigFileExtension { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | EditorConfig for Visual Studio 2 | ============ 3 | 4 | [![Build status](https://ci.appveyor.com/api/projects/status/27hvb1s209u0a7xp)](https://ci.appveyor.com/project/madskristensen/editorconfig) 5 | 6 | **Note: This extension is unpublished on the VS Gallery.** 7 | 8 | Gives syntax highlighting, validation and Intellisense for .editorconfig files 9 | 10 | This is meant as a pull request to https://github.com/editorconfig/editorconfig-visualstudio 11 | 12 | 13 | ## Screenshot: 14 | 15 | ![screenshot](https://raw.githubusercontent.com/madskristensen/EditorConfig/master/art/screenshot.png) 16 | 17 | I can't compile your project, since I don't have VS 2010 installed. 18 | 19 | This code should be Visual Studio 2010+ compatible though. All you have to do 20 | is to copy over the file `EditorConfigTextViewCreationListener.cs` and the folders `Classify`, `Completion`, `validation` and `ContentType` to 21 | the .editorconfig VS extension project and then add the missing references. 22 | 23 | Sorry for such a lame pull request 24 | -------------------------------------------------------------------------------- /src/EditorConfig/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | .editorconfig Colorizer 6 | Colorizer and Intellisense for .editorconfig files 7 | License.txt 8 | logo.png 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/EditorConfig/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("EditorConfigEditor")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("EditorConfigEditor")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // Version information for an assembly consists of the following four values: 23 | // 24 | // Major Version 25 | // Minor Version 26 | // Build Number 27 | // Revision 28 | // 29 | // You can specify all the values or you can default the Build and Revision Numbers 30 | // by using the '*' as shown below: 31 | // [assembly: AssemblyVersion("1.0.*")] 32 | [assembly: AssemblyVersion("1.0.0.0")] 33 | [assembly: AssemblyFileVersion("1.0.0.0")] 34 | -------------------------------------------------------------------------------- /src/EditorConfig.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30722.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EditorConfig", "EditorConfig\EditorConfig.csproj", "{0439E23F-FBE4-48FB-8A08-1BCFF2A8854F}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D0ED7743-20D1-45E1-9BEB-BC62CDE60D0F}" 9 | ProjectSection(SolutionItems) = preProject 10 | ..\.gitignore = ..\.gitignore 11 | ..\README.md = ..\README.md 12 | EndProjectSection 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | CI|Any CPU = CI|Any CPU 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {0439E23F-FBE4-48FB-8A08-1BCFF2A8854F}.CI|Any CPU.ActiveCfg = CI|Any CPU 22 | {0439E23F-FBE4-48FB-8A08-1BCFF2A8854F}.CI|Any CPU.Build.0 = CI|Any CPU 23 | {0439E23F-FBE4-48FB-8A08-1BCFF2A8854F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {0439E23F-FBE4-48FB-8A08-1BCFF2A8854F}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {0439E23F-FBE4-48FB-8A08-1BCFF2A8854F}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {0439E23F-FBE4-48FB-8A08-1BCFF2A8854F}.Release|Any CPU.Build.0 = Release|Any CPU 27 | EndGlobalSection 28 | GlobalSection(SolutionProperties) = preSolution 29 | HideSolutionNode = FALSE 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /src/EditorConfig/Completion/CompletionItem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace EditorConfig 5 | { 6 | class CompletionItem 7 | { 8 | private static List _dic = new List 9 | { 10 | {new CompletionItem("root", "Special property that should be specified at the top of the file outside of any sections. Set to “true” to stop .editorconfig files search on current file.", "true")}, 11 | {new CompletionItem("indent_style", "Indentation Style", "tab", "space")}, 12 | {new CompletionItem("indent_size", "Indentation Size (in single-spaced characters)", "tab") }, 13 | {new CompletionItem("tab_width", "Width of a single tabstop character") }, 14 | {new CompletionItem("end_of_line", "Line ending file format (Unix, DOS, Mac)", "lf", "crlf", "cr") }, 15 | {new CompletionItem("charset", "File character encoding", "latin1", "utf-8", "utf-1be", "utf-1le")}, 16 | {new CompletionItem("trim_trailing_whitespace", "Denotes whether whitespace is allowed at the end of lines", "true", "false")}, 17 | {new CompletionItem("insert_final_newline", "Denotes whether file should end with a newline", "true", "false")}, 18 | {new CompletionItem("max_line_length", "Forces hard line wrapping after the amount of characters specified")}, 19 | }; 20 | 21 | private CompletionItem(string name, string description, params string[] values) 22 | { 23 | this.Name = name; 24 | this.Description = description; 25 | this.Values = values; 26 | } 27 | 28 | public static IEnumerable Items 29 | { 30 | get { return _dic; } 31 | } 32 | 33 | public static CompletionItem GetCompletionItem(string name) 34 | { 35 | return _dic.SingleOrDefault(c => c.Name == name); 36 | } 37 | 38 | public string Name { get; set; } 39 | public string Description { get; set; } 40 | public IEnumerable Values { get; set; } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/EditorConfig/EditorConfigTextViewCreationListener.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.Composition; 3 | using Microsoft.VisualStudio.Editor; 4 | using Microsoft.VisualStudio.Language.Intellisense; 5 | using Microsoft.VisualStudio.OLE.Interop; 6 | using Microsoft.VisualStudio.Shell; 7 | using Microsoft.VisualStudio.Text.Editor; 8 | using Microsoft.VisualStudio.TextManager.Interop; 9 | using Microsoft.VisualStudio.Utilities; 10 | 11 | namespace EditorConfig 12 | { 13 | [Export(typeof(IVsTextViewCreationListener))] 14 | [ContentType(EditorConfigContentTypeDefinition.EditorConfigContentType)] 15 | [TextViewRole(PredefinedTextViewRoles.Interactive)] 16 | internal sealed class VsTextViewCreationListener : IVsTextViewCreationListener 17 | { 18 | [Import] 19 | IVsEditorAdaptersFactoryService AdaptersFactory = null; 20 | 21 | [Import] 22 | ICompletionBroker CompletionBroker = null; 23 | 24 | [Import] 25 | internal SVsServiceProvider ServiceProvider = null; 26 | 27 | private ErrorListProvider _errorList; 28 | 29 | public void VsTextViewCreated(IVsTextView textViewAdapter) 30 | { 31 | IWpfTextView view = AdaptersFactory.GetWpfTextView(textViewAdapter); 32 | 33 | view.TextBuffer.Properties.GetOrCreateSingletonProperty(() => view); 34 | _errorList = view.TextBuffer.Properties.GetOrCreateSingletonProperty(() => new ErrorListProvider(ServiceProvider)); 35 | 36 | if (_errorList == null) 37 | return; 38 | 39 | CommandFilter filter = new CommandFilter(view, CompletionBroker); 40 | 41 | IOleCommandTarget next; 42 | textViewAdapter.AddCommandFilter(filter, out next); 43 | filter.Next = next; 44 | 45 | view.Closed += OnViewClosed; 46 | } 47 | 48 | private void OnViewClosed(object sender, EventArgs e) 49 | { 50 | IWpfTextView view = (IWpfTextView)sender; 51 | view.Closed -= OnViewClosed; 52 | 53 | if (_errorList != null) 54 | { 55 | _errorList.Tasks.Clear(); 56 | _errorList.Dispose(); 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/EditorConfig/Classify/EditorConfigClassifier.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text.RegularExpressions; 5 | using Microsoft.VisualStudio.Language.StandardClassification; 6 | using Microsoft.VisualStudio.Text; 7 | using Microsoft.VisualStudio.Text.Classification; 8 | 9 | namespace EditorConfig 10 | { 11 | class EditorConfigClassifier : IClassifier 12 | { 13 | private static Regex _rxKeywords = new Regex(@"(?<=\=\s?)([a-zA-Z0-9-]+)\b", RegexOptions.Compiled); 14 | private static Regex _rxIdentifier = new Regex(@"^([^=]+)\b(?=\=?)", RegexOptions.Compiled); 15 | private static Regex _rxString = new Regex(@"\[([^\]]+)\]", RegexOptions.Compiled); 16 | private static Regex _rxComment = new Regex(@"#.*", RegexOptions.Compiled); 17 | private static List> _map; 18 | 19 | public EditorConfigClassifier(IClassificationTypeRegistryService registry) 20 | { 21 | if (_map == null) 22 | _map = new List> 23 | { 24 | {Tuple.Create(_rxComment, registry.GetClassificationType(PredefinedClassificationTypeNames.Comment))}, 25 | {Tuple.Create(_rxString, registry.GetClassificationType(PredefinedClassificationTypeNames.String))}, 26 | {Tuple.Create(_rxIdentifier, registry.GetClassificationType(PredefinedClassificationTypeNames.SymbolDefinition))}, 27 | {Tuple.Create(_rxKeywords, registry.GetClassificationType(PredefinedClassificationTypeNames.Literal))}, 28 | }; 29 | } 30 | 31 | public IList GetClassificationSpans(SnapshotSpan span) 32 | { 33 | IList list = new List(); 34 | ITextSnapshotLine line = span.Start.GetContainingLine(); 35 | string text = line.GetText(); 36 | 37 | foreach (var tuple in _map) 38 | foreach (Match match in tuple.Item1.Matches(text)) 39 | { 40 | var str = new SnapshotSpan(line.Snapshot, line.Start.Position + match.Index, match.Length); 41 | 42 | // Make sure we don't double classify 43 | if (list.Any(s => s.Span.IntersectsWith(str))) 44 | continue; 45 | 46 | list.Add(new ClassificationSpan(str, tuple.Item2)); 47 | } 48 | 49 | return list; 50 | } 51 | 52 | public event EventHandler ClassificationChanged 53 | { 54 | add { } 55 | remove { } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # MSTest test Results 20 | [Tt]est[Rr]esult*/ 21 | [Bb]uild[Ll]og.* 22 | 23 | #NUNIT 24 | *.VisualState.xml 25 | TestResult.xml 26 | 27 | # Build Results of an ATL Project 28 | [Dd]ebugPS/ 29 | [Rr]eleasePS/ 30 | dlldata.c 31 | 32 | *_i.c 33 | *_p.c 34 | *_i.h 35 | *.ilk 36 | *.meta 37 | *.obj 38 | *.pch 39 | *.pdb 40 | *.pgc 41 | *.pgd 42 | *.rsp 43 | *.sbr 44 | *.tlb 45 | *.tli 46 | *.tlh 47 | *.tmp 48 | *.tmp_proj 49 | *.log 50 | *.vspscc 51 | *.vssscc 52 | .builds 53 | *.pidb 54 | *.svclog 55 | *.scc 56 | 57 | # Chutzpah Test files 58 | _Chutzpah* 59 | 60 | # Visual C++ cache files 61 | ipch/ 62 | *.aps 63 | *.ncb 64 | *.opensdf 65 | *.sdf 66 | *.cachefile 67 | 68 | # Visual Studio profiler 69 | *.psess 70 | *.vsp 71 | *.vspx 72 | 73 | # TFS 2012 Local Workspace 74 | $tf/ 75 | 76 | # Guidance Automation Toolkit 77 | *.gpState 78 | 79 | # ReSharper is a .NET coding add-in 80 | _ReSharper*/ 81 | *.[Rr]e[Ss]harper 82 | *.DotSettings.user 83 | 84 | # JustCode is a .NET coding addin-in 85 | .JustCode 86 | 87 | # TeamCity is a build add-in 88 | _TeamCity* 89 | 90 | # DotCover is a Code Coverage Tool 91 | *.dotCover 92 | 93 | # NCrunch 94 | *.ncrunch* 95 | _NCrunch_* 96 | .*crunch*.local.xml 97 | 98 | # MightyMoose 99 | *.mm.* 100 | AutoTest.Net/ 101 | 102 | # Web workbench (sass) 103 | .sass-cache/ 104 | 105 | # Installshield output folder 106 | [Ee]xpress/ 107 | 108 | # DocProject is a documentation generator add-in 109 | DocProject/buildhelp/ 110 | DocProject/Help/*.HxT 111 | DocProject/Help/*.HxC 112 | DocProject/Help/*.hhc 113 | DocProject/Help/*.hhk 114 | DocProject/Help/*.hhp 115 | DocProject/Help/Html2 116 | DocProject/Help/html 117 | 118 | # Click-Once directory 119 | publish/ 120 | 121 | # Publish Web Output 122 | *.[Pp]ublish.xml 123 | *.azurePubxml 124 | 125 | # NuGet Packages Directory 126 | packages/ 127 | ## TODO: If the tool you use requires repositories.config uncomment the next line 128 | #!packages/repositories.config 129 | 130 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 131 | # This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) 132 | !packages/build/ 133 | 134 | # Windows Azure Build Output 135 | csx/ 136 | *.build.csdef 137 | 138 | # Windows Store app package directory 139 | AppPackages/ 140 | 141 | # Others 142 | sql/ 143 | *.Cache 144 | ClientBin/ 145 | [Ss]tyle[Cc]op.* 146 | ~$* 147 | *~ 148 | *.dbmdl 149 | *.dbproj.schemaview 150 | *.pfx 151 | *.publishsettings 152 | node_modules/ 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | *.mdf 166 | *.ldf 167 | 168 | # Business Intelligence projects 169 | *.rdl.data 170 | *.bim.layout 171 | *.bim_*.settings 172 | 173 | # Microsoft Fakes 174 | FakesAssemblies/ 175 | 176 | # ========================= 177 | # Operating System Files 178 | # ========================= 179 | 180 | # OSX 181 | # ========================= 182 | 183 | .DS_Store 184 | .AppleDouble 185 | .LSOverride 186 | 187 | # Icon must ends with two \r. 188 | Icon 189 | 190 | # Thumbnails 191 | ._* 192 | 193 | # Files that might appear on external disk 194 | .Spotlight-V100 195 | .Trashes 196 | 197 | # Windows 198 | # ========================= 199 | 200 | # Windows image file caches 201 | Thumbs.db 202 | ehthumbs.db 203 | 204 | # Folder config file 205 | Desktop.ini 206 | 207 | # Recycle Bin used on file shares 208 | $RECYCLE.BIN/ 209 | 210 | # Windows Installer files 211 | *.cab 212 | *.msi 213 | *.msm 214 | *.msp 215 | -------------------------------------------------------------------------------- /src/EditorConfig/Completion/EditorConfigCompletionSource.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.Composition; 3 | using System.Linq; 4 | using System.Windows.Media; 5 | using Microsoft.VisualStudio.Language.Intellisense; 6 | using Microsoft.VisualStudio.Language.StandardClassification; 7 | using Microsoft.VisualStudio.Text; 8 | using Microsoft.VisualStudio.Text.Classification; 9 | using Microsoft.VisualStudio.Text.Operations; 10 | using Microsoft.VisualStudio.Utilities; 11 | using Intel = Microsoft.VisualStudio.Language.Intellisense; 12 | 13 | namespace EditorConfig 14 | { 15 | [Export(typeof(ICompletionSourceProvider))] 16 | [ContentType(EditorConfigContentTypeDefinition.EditorConfigContentType)] 17 | [Name("Editor Config Completion")] 18 | class EditorConfigCompletionSourceProvider : ICompletionSourceProvider 19 | { 20 | [Import] 21 | IClassifierAggregatorService ClassifierAggregatorService = null; 22 | 23 | [Import] 24 | ITextStructureNavigatorSelectorService NavigatorService = null; 25 | 26 | [Import] 27 | IGlyphService GlyphService = null; 28 | 29 | private static ImageSource _glyph; 30 | 31 | public ICompletionSource TryCreateCompletionSource(ITextBuffer textBuffer) 32 | { 33 | if (_glyph == null) 34 | _glyph = GlyphService.GetGlyph(StandardGlyphGroup.GlyphGroupProperty, StandardGlyphItem.GlyphItemPublic); 35 | 36 | return new EditorConfigCompletionSource(textBuffer, ClassifierAggregatorService, NavigatorService, _glyph); 37 | } 38 | } 39 | 40 | class EditorConfigCompletionSource : ICompletionSource 41 | { 42 | private ITextBuffer _buffer; 43 | private bool _disposed = false; 44 | private IClassifier _classifier; 45 | private ITextStructureNavigatorSelectorService _navigator; 46 | private ImageSource _glyph; 47 | 48 | public EditorConfigCompletionSource(ITextBuffer buffer, IClassifierAggregatorService classifier, ITextStructureNavigatorSelectorService navigator, ImageSource glyph) 49 | { 50 | _buffer = buffer; 51 | _classifier = classifier.GetClassifier(buffer); 52 | _navigator = navigator; 53 | _glyph = glyph; 54 | } 55 | 56 | public void AugmentCompletionSession(ICompletionSession session, IList completionSets) 57 | { 58 | if (_disposed) 59 | return; 60 | 61 | ITextSnapshot snapshot = _buffer.CurrentSnapshot; 62 | var triggerPoint = session.GetTriggerPoint(snapshot); 63 | 64 | if (triggerPoint == null) 65 | return; 66 | 67 | SnapshotSpan extent = FindTokenSpanAtPosition(session).GetSpan(snapshot); 68 | var line = triggerPoint.Value.GetContainingLine().Extent; 69 | 70 | var spans = _classifier.GetClassificationSpans(line); 71 | 72 | List list = new List(); 73 | string current = string.Empty; 74 | 75 | foreach (var span in spans) 76 | { 77 | if (span.ClassificationType.IsOfType(PredefinedClassificationTypeNames.SymbolDefinition)) 78 | { 79 | current = span.Span.GetText(); 80 | 81 | if (!span.Span.Contains(extent)) 82 | continue; 83 | 84 | foreach (var key in CompletionItem.Items) 85 | list.Add(CreateCompletion(key.Name, key.Description)); 86 | } 87 | else if (span.ClassificationType.IsOfType(PredefinedClassificationTypeNames.Literal)) 88 | { 89 | if (!span.Span.Contains(extent)) 90 | continue; 91 | 92 | CompletionItem item = CompletionItem.GetCompletionItem(current); 93 | if (item != null){ 94 | foreach (var value in item.Values) 95 | list.Add(CreateCompletion(value)); 96 | }} 97 | } 98 | 99 | var applicableTo = snapshot.CreateTrackingSpan(extent, SpanTrackingMode.EdgeInclusive); 100 | 101 | completionSets.Add(new CompletionSet("All", "All", applicableTo, list, Enumerable.Empty())); 102 | } 103 | 104 | private Completion CreateCompletion(string name, string description = null) 105 | { 106 | return new Completion(name, name, description, _glyph, null); 107 | } 108 | 109 | private ITrackingSpan FindTokenSpanAtPosition(ICompletionSession session) 110 | { 111 | SnapshotPoint currentPoint = (session.TextView.Caret.Position.BufferPosition) - 1; 112 | ITextStructureNavigator navigator = _navigator.GetTextStructureNavigator(_buffer); 113 | TextExtent extent = navigator.GetExtentOfWord(currentPoint); 114 | return currentPoint.Snapshot.CreateTrackingSpan(extent.Span, SpanTrackingMode.EdgeInclusive); 115 | } 116 | 117 | public void Dispose() 118 | { 119 | _disposed = true; 120 | } 121 | } 122 | } -------------------------------------------------------------------------------- /src/EditorConfig/Completion/EditorConfigCompletionController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using Microsoft.VisualStudio; 4 | using Microsoft.VisualStudio.Language.Intellisense; 5 | using Microsoft.VisualStudio.OLE.Interop; 6 | using Microsoft.VisualStudio.Text; 7 | using Microsoft.VisualStudio.Text.Editor; 8 | 9 | namespace EditorConfig 10 | { 11 | internal sealed class CommandFilter : IOleCommandTarget 12 | { 13 | private ICompletionSession _currentSession; 14 | 15 | public CommandFilter(IWpfTextView textView, ICompletionBroker broker) 16 | { 17 | _currentSession = null; 18 | 19 | TextView = textView; 20 | Broker = broker; 21 | } 22 | 23 | public IWpfTextView TextView { get; private set; } 24 | public ICompletionBroker Broker { get; private set; } 25 | public IOleCommandTarget Next { get; set; } 26 | 27 | private static char GetTypeChar(IntPtr pvaIn) 28 | { 29 | return (char)(ushort)Marshal.GetObjectForNativeVariant(pvaIn); 30 | } 31 | 32 | public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) 33 | { 34 | bool handled = false; 35 | int hresult = VSConstants.S_OK; 36 | 37 | // 1. Pre-process 38 | if (pguidCmdGroup == VSConstants.VSStd2K) 39 | { 40 | switch ((VSConstants.VSStd2KCmdID)nCmdID) 41 | { 42 | case VSConstants.VSStd2KCmdID.AUTOCOMPLETE: 43 | case VSConstants.VSStd2KCmdID.COMPLETEWORD: 44 | case VSConstants.VSStd2KCmdID.SHOWMEMBERLIST: 45 | handled = StartSession(); 46 | break; 47 | case VSConstants.VSStd2KCmdID.RETURN: 48 | handled = Complete(false); 49 | break; 50 | case VSConstants.VSStd2KCmdID.TAB: 51 | handled = Complete(true); 52 | break; 53 | case VSConstants.VSStd2KCmdID.CANCEL: 54 | handled = Cancel(); 55 | break; 56 | } 57 | } 58 | 59 | if (!handled) 60 | hresult = Next.Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); 61 | 62 | if (ErrorHandler.Succeeded(hresult)) 63 | { 64 | if (pguidCmdGroup == VSConstants.VSStd2K) 65 | { 66 | switch ((VSConstants.VSStd2KCmdID)nCmdID) 67 | { 68 | case VSConstants.VSStd2KCmdID.TYPECHAR: 69 | char ch = GetTypeChar(pvaIn); 70 | if (ch == '=' || ch == ' ') 71 | Cancel(); 72 | else if (!char.IsPunctuation(ch) && !char.IsControl(ch)) 73 | StartSession(); 74 | else if (_currentSession != null) 75 | Filter(); 76 | break; 77 | case VSConstants.VSStd2KCmdID.BACKSPACE: 78 | if (_currentSession == null) 79 | StartSession(); 80 | 81 | Filter(); 82 | break; 83 | } 84 | } 85 | } 86 | 87 | return hresult; 88 | } 89 | 90 | private void Filter() 91 | { 92 | if (_currentSession == null) 93 | return; 94 | 95 | _currentSession.SelectedCompletionSet.SelectBestMatch(); 96 | _currentSession.SelectedCompletionSet.Recalculate(); 97 | } 98 | 99 | bool Cancel() 100 | { 101 | if (_currentSession == null) 102 | return false; 103 | 104 | _currentSession.Dismiss(); 105 | 106 | return true; 107 | } 108 | 109 | bool Complete(bool force) 110 | { 111 | if (_currentSession == null) 112 | return false; 113 | 114 | if (!_currentSession.SelectedCompletionSet.SelectionStatus.IsSelected && !force) 115 | { 116 | _currentSession.Dismiss(); 117 | return false; 118 | } 119 | else 120 | { 121 | _currentSession.Commit(); 122 | return true; 123 | } 124 | } 125 | 126 | bool StartSession() 127 | { 128 | if (_currentSession != null) 129 | return false; 130 | 131 | SnapshotPoint caret = TextView.Caret.Position.BufferPosition; 132 | ITextSnapshot snapshot = caret.Snapshot; 133 | 134 | if (!Broker.IsCompletionActive(TextView)) 135 | { 136 | _currentSession = Broker.CreateCompletionSession(TextView, snapshot.CreateTrackingPoint(caret, PointTrackingMode.Positive), true); 137 | } 138 | else 139 | { 140 | _currentSession = Broker.GetSessions(TextView)[0]; 141 | } 142 | _currentSession.Dismissed += (sender, args) => _currentSession = null; 143 | 144 | if (!_currentSession.IsStarted) 145 | _currentSession.Start(); 146 | 147 | return true; 148 | } 149 | 150 | public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) 151 | { 152 | if (pguidCmdGroup == VSConstants.VSStd2K) 153 | { 154 | switch ((VSConstants.VSStd2KCmdID)prgCmds[0].cmdID) 155 | { 156 | case VSConstants.VSStd2KCmdID.AUTOCOMPLETE: 157 | case VSConstants.VSStd2KCmdID.COMPLETEWORD: 158 | case VSConstants.VSStd2KCmdID.SHOWMEMBERLIST: 159 | prgCmds[0].cmdf = (uint)OLECMDF.OLECMDF_ENABLED | (uint)OLECMDF.OLECMDF_SUPPORTED; 160 | return VSConstants.S_OK; 161 | } 162 | } 163 | return Next.QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText); 164 | } 165 | } 166 | } -------------------------------------------------------------------------------- /src/EditorConfig/Validation/EditorConfigErrorTag.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.Composition; 4 | using System.Linq; 5 | using Microsoft.VisualStudio.Language.StandardClassification; 6 | using Microsoft.VisualStudio.Shell; 7 | using Microsoft.VisualStudio.Text; 8 | using Microsoft.VisualStudio.Text.Classification; 9 | using Microsoft.VisualStudio.Text.Editor; 10 | using Microsoft.VisualStudio.Text.Tagging; 11 | using Microsoft.VisualStudio.Utilities; 12 | 13 | namespace EditorConfig 14 | { 15 | [Export(typeof(ITaggerProvider))] 16 | [ContentType(EditorConfigContentTypeDefinition.EditorConfigContentType)] 17 | [TagType(typeof(ErrorTag))] 18 | class CheckTextErrorProvider : ITaggerProvider 19 | { 20 | [Import] 21 | IClassifierAggregatorService _classifierAggregatorService = null; 22 | 23 | [Import] 24 | public ITextDocumentFactoryService TextDocumentFactoryService { get; set; } 25 | 26 | public ITagger CreateTagger(ITextBuffer buffer) where T : ITag 27 | { 28 | if (buffer == null) 29 | throw new ArgumentException("Buffer is null"); 30 | 31 | var errorlist = buffer.Properties.GetProperty(typeof(ErrorListProvider)) as ErrorListProvider; 32 | var view = buffer.Properties.GetProperty(typeof(IWpfTextView)) as IWpfTextView; 33 | 34 | ITextDocument document; 35 | if (TextDocumentFactoryService.TryGetTextDocument(buffer, out document) && errorlist != null) 36 | { 37 | return new CheckTextErrorTagger(view, _classifierAggregatorService, errorlist, document) as ITagger; 38 | } 39 | 40 | return null; 41 | } 42 | } 43 | 44 | class CheckTextErrorTagger : ITagger 45 | { 46 | private IClassifier _classifier; 47 | private ErrorListProvider _errorlist; 48 | private ITextDocument _document; 49 | private IWpfTextView _view; 50 | 51 | public CheckTextErrorTagger(IWpfTextView view, IClassifierAggregatorService classifier, ErrorListProvider errorlist, ITextDocument document) 52 | { 53 | _view = view; 54 | _classifier = classifier.GetClassifier(view.TextBuffer); 55 | _errorlist = errorlist; 56 | _document = document; 57 | } 58 | 59 | public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) 60 | { 61 | var span = spans[0]; 62 | var line = span.Start.GetContainingLine(); 63 | var classificationSpans = _classifier.GetClassificationSpans(line.Extent); 64 | string property = null; 65 | 66 | ClearError(line); 67 | 68 | foreach (var cspan in classificationSpans) 69 | { 70 | if (cspan.ClassificationType.IsOfType(PredefinedClassificationTypeNames.SymbolDefinition)) 71 | { 72 | property = cspan.Span.GetText(); 73 | CompletionItem item = CompletionItem.GetCompletionItem(property); 74 | 75 | if (item == null) 76 | yield return CreateError(line, cspan, "\"" + property + "\" is not a valid .editorconfig property"); ; 77 | } 78 | else if (cspan.ClassificationType.IsOfType(PredefinedClassificationTypeNames.Literal)) 79 | { 80 | if (string.IsNullOrEmpty(property)) 81 | continue; 82 | 83 | CompletionItem item = CompletionItem.GetCompletionItem(property); 84 | if (item == null) 85 | continue; 86 | 87 | string value = cspan.Span.GetText(); 88 | int intValue; 89 | 90 | if (!item.Values.Contains(value) && !int.TryParse(value, out intValue)) 91 | yield return CreateError(line, cspan, "\"" + value + "\" is not a valid value for the '" + property + "' property"); 92 | } 93 | } 94 | } 95 | 96 | private TagSpan CreateError(ITextSnapshotLine line, ClassificationSpan cspan, string message) 97 | { 98 | ErrorTask task = CreateErrorTask(line, cspan, message); 99 | 100 | _errorlist.Tasks.Add(task); 101 | 102 | SnapshotSpan CheckTextSpan = new SnapshotSpan(cspan.Span.Snapshot, new Span(cspan.Span.Start, cspan.Span.Length)); 103 | return new TagSpan(CheckTextSpan, new ErrorTag(message, message)); 104 | } 105 | 106 | private ErrorTask CreateErrorTask(ITextSnapshotLine line, ClassificationSpan cspan, string text) 107 | { 108 | ErrorTask task = new ErrorTask 109 | { 110 | Text = text, 111 | Line = line.LineNumber, 112 | Column = cspan.Span.Start.Position - line.Start.Position, 113 | Category = TaskCategory.Misc, 114 | ErrorCategory = TaskErrorCategory.Warning, 115 | Priority = TaskPriority.Low, 116 | Document = _document.FilePath 117 | }; 118 | 119 | task.Navigate += task_Navigate; 120 | 121 | return task; 122 | } 123 | 124 | private void task_Navigate(object sender, EventArgs e) 125 | { 126 | ErrorTask task = (ErrorTask)sender; 127 | _errorlist.Navigate(task, new Guid("{00000000-0000-0000-0000-000000000000}")); 128 | 129 | var line = _view.TextBuffer.CurrentSnapshot.GetLineFromLineNumber(task.Line); 130 | var point = new SnapshotPoint(line.Snapshot, line.Start.Position + task.Column); 131 | _view.Caret.MoveTo(point); 132 | } 133 | 134 | private void ClearError(ITextSnapshotLine line) 135 | { 136 | foreach (ErrorTask existing in _errorlist.Tasks) 137 | { 138 | if (existing.Line == line.LineNumber) 139 | { 140 | _errorlist.Tasks.Remove(existing); 141 | break; 142 | } 143 | } 144 | } 145 | 146 | 147 | public event EventHandler TagsChanged 148 | { 149 | add { } 150 | remove { } 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/EditorConfig/EditorConfig.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12.0 5 | 11.0 6 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 7 | 8 | 9 | 12.0 10 | 11 | publish\ 12 | true 13 | Disk 14 | false 15 | Foreground 16 | 7 17 | Days 18 | false 19 | false 20 | true 21 | 0 22 | 1.0.0.%2a 23 | false 24 | false 25 | true 26 | Program 27 | $(DevEnvDir)\devenv.exe 28 | /rootsuffix Exp 29 | 30 | 31 | bin\CI\ 32 | TRACE 33 | true 34 | pdbonly 35 | AnyCPU 36 | prompt 37 | MinimumRecommendedRules.ruleset 38 | False 39 | 40 | 41 | 42 | Debug 43 | AnyCPU 44 | 2.0 45 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 46 | {0439E23F-FBE4-48FB-8A08-1BCFF2A8854F} 47 | Library 48 | Properties 49 | EditorConfigEditor 50 | EditorConfigEditor 51 | v4.5 52 | false 53 | true 54 | false 55 | false 56 | false 57 | false 58 | 59 | 60 | true 61 | full 62 | false 63 | bin\Debug\ 64 | DEBUG;TRACE 65 | prompt 66 | 4 67 | 68 | 69 | pdbonly 70 | true 71 | bin\Release\ 72 | TRACE 73 | prompt 74 | 4 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | Designer 90 | 91 | 92 | 93 | 94 | False 95 | Microsoft .NET Framework 4.5 %28x86 and x64%29 96 | true 97 | 98 | 99 | False 100 | .NET Framework 3.5 SP1 Client Profile 101 | false 102 | 103 | 104 | False 105 | .NET Framework 3.5 SP1 106 | false 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | Always 132 | true 133 | 134 | 135 | Always 136 | true 137 | 138 | 139 | 140 | 141 | 148 | --------------------------------------------------------------------------------