├── README.md ├── art └── context-menu.png ├── src ├── Resources │ └── Icon.png ├── Commands │ ├── BaseCommand.cs │ ├── CommandRegistration.cs │ └── AutoPrefixCommand.cs ├── CssAutoPrefixPackage.cs ├── Properties │ └── AssemblyInfo.cs ├── source.extension.cs ├── Helpers │ └── Logger.cs ├── source.extension.vsixmanifest ├── VSCommandTable.cs ├── packages.config ├── VSCommandTable.vsct ├── NodeProcess.cs └── CssAutoPrefixer.csproj ├── .gitignore ├── .github ├── ISSUE_TEMPLATE.md └── CONTRIBUTING.md ├── .gitattributes ├── LICENSE ├── CHANGELOG.md ├── appveyor.yml ├── CssAutoPrefixer.sln └── .editorconfig /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/CssAutoPrefixer/master/README.md -------------------------------------------------------------------------------- /art/context-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/CssAutoPrefixer/master/art/context-menu.png -------------------------------------------------------------------------------- /src/Resources/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/madskristensen/CssAutoPrefixer/master/src/Resources/Icon.png -------------------------------------------------------------------------------- /.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 -------------------------------------------------------------------------------- /.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. -------------------------------------------------------------------------------- /src/Commands/BaseCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.OLE.Interop; 2 | using System; 3 | 4 | namespace CssAutoPrefixer 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/CssAutoPrefixPackage.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Shell; 2 | using System; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace CssAutoPrefixer 6 | { 7 | [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] 8 | [InstalledProductRegistration(Vsix.Name, Vsix.Description, Vsix.Version)] 9 | [Guid(PackageGuids.guidPackageString)] 10 | [ProvideMenuResource("Menus.ctmenu", 1)] 11 | public sealed class CssAutoPrefixPackage : AsyncPackage 12 | { 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /src/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using CssAutoPrefixer; 2 | using System.Reflection; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle(Vsix.Name)] 6 | [assembly: AssemblyDescription(Vsix.Description)] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany(Vsix.Author)] 9 | [assembly: AssemblyProduct(Vsix.Name)] 10 | [assembly: AssemblyCopyright(Vsix.Author)] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | 14 | [assembly: ComVisible(false)] 15 | 16 | [assembly: AssemblyVersion(Vsix.Version)] 17 | [assembly: AssemblyFileVersion(Vsix.Version)] 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Road map 2 | 3 | - [x] Added UTF-8 encoding support 4 | 5 | Features that have a checkmark are complete and available for 6 | download in the 7 | [CI build](http://vsixgallery.com/extension/7df8a985-0e26-4aab-95fc-f48ee61b086a/). 8 | 9 | # Change log 10 | 11 | These are the changes to each version that has been released 12 | on the official Visual Studio extension gallery. 13 | 14 | ## 0.6 15 | 16 | - [x] Support for LESS and Scss 17 | - [x] Scoped keyboard shortcut to JS editor 18 | 19 | ## 0.5 20 | 21 | - [x] Initial release 22 | - [x] Install npm modules 23 | - [x] Command on CSS context menu 24 | -------------------------------------------------------------------------------- /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 | after_test: 15 | - ps: Vsix-PushArtifacts | Vsix-PublishToGallery 16 | -------------------------------------------------------------------------------- /src/source.extension.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // This file was generated by VSIX Synchronizer 4 | // 5 | // ------------------------------------------------------------------------------ 6 | namespace CssAutoPrefixer 7 | { 8 | internal sealed partial class Vsix 9 | { 10 | public const string Id = "7df8a985-0e26-4aab-95fc-f48ee61b086a"; 11 | public const string Name = "CSS AutoPrefixer"; 12 | public const string Description = @"Write your CSS rules without vendor prefixes (in fact, forget about them entirely). Autoprefixer will use the data based on current browser popularity and property support to apply prefixes for you."; 13 | public const string Language = "en-US"; 14 | public const string Version = "0.7"; 15 | public const string Author = "Mads Kristensen"; 16 | public const string Tags = "CSS, LESS, Sass, Scss, autoprefixer"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Helpers/Logger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.Shell; 3 | using Microsoft.VisualStudio.Shell.Interop; 4 | 5 | internal static class Logger 6 | { 7 | private static IVsOutputWindowPane _pane; 8 | private static IVsOutputWindow _output = (IVsOutputWindow)ServiceProvider.GlobalProvider.GetService(typeof(SVsOutputWindow)); 9 | 10 | public static void Log(object message) 11 | { 12 | try 13 | { 14 | if (EnsurePane()) 15 | { 16 | _pane.OutputString(DateTime.Now.ToString() + ": " + message + Environment.NewLine); 17 | } 18 | } 19 | catch (Exception ex) 20 | { 21 | System.Diagnostics.Debug.Write(ex); 22 | } 23 | } 24 | 25 | private static bool EnsurePane() 26 | { 27 | if (_pane == null) 28 | { 29 | var guid = Guid.NewGuid(); 30 | _output.CreatePane(ref guid, CssAutoPrefixer.Vsix.Name, 1, 1); 31 | _output.GetPane(ref guid, out _pane); 32 | } 33 | 34 | return _pane != null; 35 | } 36 | } -------------------------------------------------------------------------------- /CssAutoPrefixer.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26212.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JavaScriptPrettier", "src\CssAutoPrefixer.csproj", "{D1F752E5-6CAB-4513-980A-51B44E104CDF}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{50552A90-8343-4135-A563-AE454C22F3D6}" 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 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {D1F752E5-6CAB-4513-980A-51B44E104CDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {D1F752E5-6CAB-4513-980A-51B44E104CDF}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {D1F752E5-6CAB-4513-980A-51B44E104CDF}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {D1F752E5-6CAB-4513-980A-51B44E104CDF}.Release|Any CPU.Build.0 = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(SolutionProperties) = preSolution 28 | HideSolutionNode = FALSE 29 | EndGlobalSection 30 | EndGlobal 31 | -------------------------------------------------------------------------------- /src/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CSS AutoPrefixer 6 | Write your CSS rules without vendor prefixes (in fact, forget about them entirely). Autoprefixer will use the data based on current browser popularity and property support to apply prefixes for you. 7 | https://github.com/madskristensen/CssAutoPrefixer 8 | Resources\LICENSE 9 | https://github.com/madskristensen/CssAutoPrefixer/blob/master/CHANGELOG.md 10 | Resources\Icon.png 11 | Resources\Icon.png 12 | CSS, LESS, Sass, Scss, autoprefixer 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/VSCommandTable.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // This file was generated by Extensibility Tools v1.10.188 4 | // 5 | // ------------------------------------------------------------------------------ 6 | namespace CssAutoPrefixer 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 guidPackageString = "1fb559a7-7c51-4b78-b941-697bd7764ade"; 16 | public const string guidPackageCmdSetString = "df207aa8-51d1-44f8-b6c1-31af17cce355"; 17 | public const string CssEditorString = "a5401142-f49d-43db-90b1-f57ba349e55c"; 18 | public const string CssEditorWithEncodingString = "226f7e34-0ae8-4157-9cd8-b66b4eaf2c7b"; 19 | public const string LessEditorString = "28c69eda-edf9-4ca8-9ebe-443348b6d916"; 20 | public const string LessEditorWithEncodingString = "eb284e36-4c91-422b-8df6-4dfc2ec3d350"; 21 | public const string ScssEditorString = "181fe41b-5a5d-479f-9f8f-bf665f4ebc2a"; 22 | public const string ScssEditorWithEncodingString = "52334ead-0711-4a03-804e-7169f077a621"; 23 | public const string CssCmdSetString = "64da400e-b4ad-4d67-aa92-4b7acb01ecd5"; 24 | public static Guid guidPackage = new Guid(guidPackageString); 25 | public static Guid guidPackageCmdSet = new Guid(guidPackageCmdSetString); 26 | public static Guid CssEditor = new Guid(CssEditorString); 27 | public static Guid CssEditorWithEncoding = new Guid(CssEditorWithEncodingString); 28 | public static Guid LessEditor = new Guid(LessEditorString); 29 | public static Guid LessEditorWithEncoding = new Guid(LessEditorWithEncodingString); 30 | public static Guid ScssEditor = new Guid(ScssEditorString); 31 | public static Guid ScssEditorWithEncoding = new Guid(ScssEditorWithEncodingString); 32 | public static Guid CssCmdSet = new Guid(CssCmdSetString); 33 | } 34 | /// 35 | /// Helper class that encapsulates all CommandIDs uses across VS Package. 36 | /// 37 | internal sealed partial class PackageIds 38 | { 39 | public const int MyMenuGroup = 0x1020; 40 | public const int AutoPrefixCommandId = 0x0100; 41 | public const int cssContextMenu = 0x0002; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.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 -------------------------------------------------------------------------------- /src/Commands/CommandRegistration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.Editor; 2 | using Microsoft.VisualStudio.Shell; 3 | using Microsoft.VisualStudio.Shell.Interop; 4 | using Microsoft.VisualStudio.Text; 5 | using Microsoft.VisualStudio.Text.Editor; 6 | using Microsoft.VisualStudio.Text.Operations; 7 | using Microsoft.VisualStudio.TextManager.Interop; 8 | using Microsoft.VisualStudio.Utilities; 9 | using System; 10 | using System.ComponentModel.Composition; 11 | using System.IO; 12 | using System.Linq; 13 | 14 | namespace CssAutoPrefixer 15 | { 16 | [Export(typeof(IVsTextViewCreationListener))] 17 | [ContentType("CSS")] 18 | [ContentType("LESS")] 19 | [ContentType("SCSS")] 20 | [TextViewRole(PredefinedTextViewRoles.PrimaryDocument)] 21 | internal sealed class CommandRegistration : IVsTextViewCreationListener 22 | { 23 | public static string[] FileExtensions { get; } = { ".css", ".less", ".sass", ".scss" }; 24 | 25 | [Import] 26 | private IVsEditorAdaptersFactoryService AdaptersFactory { get; set; } 27 | 28 | [Import] 29 | private ITextDocumentFactoryService DocumentService { get; set; } 30 | 31 | [Import] 32 | private ITextBufferUndoManagerProvider UndoProvider { get; set; } 33 | 34 | public async void VsTextViewCreated(IVsTextView textViewAdapter) 35 | { 36 | IWpfTextView view = AdaptersFactory.GetWpfTextView(textViewAdapter); 37 | 38 | if (!DocumentService.TryGetTextDocument(view.TextBuffer, out ITextDocument doc)) 39 | return; 40 | 41 | string ext = Path.GetExtension(doc.FilePath); 42 | 43 | if (!FileExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase)) 44 | return; 45 | 46 | ITextBufferUndoManager undoManager = UndoProvider.GetTextBufferUndoManager(view.TextBuffer); 47 | NodeProcess node = view.Properties.GetOrCreateSingletonProperty(() => new NodeProcess()); 48 | 49 | AddCommandFilter(textViewAdapter, new AutoPrefixCommand(view, undoManager, node)); 50 | 51 | if (!node.IsReadyToExecute()) 52 | { 53 | await Install(node); 54 | } 55 | } 56 | 57 | private static async System.Threading.Tasks.Task Install(NodeProcess node) 58 | { 59 | var statusbar = (IVsStatusbar)ServiceProvider.GlobalProvider.GetService(typeof(SVsStatusbar)); 60 | 61 | statusbar.FreezeOutput(0); 62 | statusbar.SetText($"Installing {NodeProcess.Packages} npm modules..."); 63 | statusbar.FreezeOutput(1); 64 | 65 | bool success = await node.EnsurePackageInstalled(); 66 | string status = success ? "Done" : "Failed"; 67 | 68 | statusbar.FreezeOutput(0); 69 | statusbar.SetText($"Installing {NodeProcess.Packages} npm modules... {status}"); 70 | statusbar.FreezeOutput(1); 71 | } 72 | 73 | private void AddCommandFilter(IVsTextView textViewAdapter, BaseCommand command) 74 | { 75 | textViewAdapter.AddCommandFilter(command, out var next); 76 | command.Next = next; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/VSCommandTable.vsct: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/Commands/AutoPrefixCommand.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using Microsoft.VisualStudio; 3 | using Microsoft.VisualStudio.OLE.Interop; 4 | using Microsoft.VisualStudio.Shell; 5 | using Microsoft.VisualStudio.Text; 6 | using Microsoft.VisualStudio.Text.Editor; 7 | using Microsoft.VisualStudio.Text.Operations; 8 | using System; 9 | using System.Threading.Tasks; 10 | 11 | namespace CssAutoPrefixer 12 | { 13 | internal sealed class AutoPrefixCommand : BaseCommand 14 | { 15 | private Guid _commandGroup = PackageGuids.guidPackageCmdSet; 16 | private const uint _commandId = PackageIds.AutoPrefixCommandId; 17 | 18 | private IWpfTextView _view; 19 | private ITextBufferUndoManager _undoManager; 20 | private NodeProcess _node; 21 | 22 | public AutoPrefixCommand(IWpfTextView view, ITextBufferUndoManager undoManager, NodeProcess node) 23 | { 24 | _view = view; 25 | _undoManager = undoManager; 26 | _node = node; 27 | } 28 | 29 | public override int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) 30 | { 31 | if (pguidCmdGroup == _commandGroup && nCmdID == _commandId) 32 | { 33 | if (_node != null && _node.IsReadyToExecute()) 34 | { 35 | ThreadHelper.JoinableTaskFactory.RunAsync(ExecuteAsync); 36 | } 37 | 38 | return VSConstants.S_OK; 39 | } 40 | 41 | return Next.Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut); 42 | } 43 | 44 | private async Task ExecuteAsync() 45 | { 46 | string input = _view.TextBuffer.CurrentSnapshot.GetText(); 47 | string output = await _node.ExecuteProcess(input); 48 | 49 | if (string.IsNullOrEmpty(output) || input == output) 50 | return false; 51 | 52 | using (ITextEdit edit = _view.TextBuffer.CreateEdit()) 53 | using (ITextUndoTransaction undo = _undoManager.TextBufferUndoHistory.CreateTransaction(Vsix.Name)) 54 | { 55 | edit.Replace(0, _view.TextBuffer.CurrentSnapshot.Length, output); 56 | edit.Apply(); 57 | 58 | var dte = (DTE)ServiceProvider.GlobalProvider.GetService(typeof(DTE)); 59 | dte.ExecuteCommand("Edit.FormatDocument"); 60 | 61 | undo.Complete(); 62 | } 63 | 64 | return true; 65 | } 66 | 67 | public override int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) 68 | { 69 | if (pguidCmdGroup == _commandGroup && prgCmds[0].cmdID == _commandId) 70 | { 71 | if (_node != null) 72 | { 73 | if (_node.IsReadyToExecute()) 74 | { 75 | prgCmds[0].cmdf = (uint)OLECMDF.OLECMDF_ENABLED | (uint)OLECMDF.OLECMDF_SUPPORTED; 76 | } 77 | else 78 | { 79 | prgCmds[0].cmdf = (uint)OLECMDF.OLECMDF_SUPPORTED; 80 | } 81 | } 82 | 83 | return VSConstants.S_OK; 84 | } 85 | 86 | return Next.QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText); 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /src/NodeProcess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace CssAutoPrefixer 8 | { 9 | internal class NodeProcess 10 | { 11 | public const string Packages = "postcss-cli autoprefixer"; 12 | 13 | private static string _installDir = Path.Combine(Path.GetTempPath(), Vsix.Name, Packages.GetHashCode().ToString()); 14 | private static readonly string _executable = Path.Combine(_installDir, "node_modules\\.bin\\postcss.cmd"); 15 | 16 | public bool IsInstalling 17 | { 18 | get; 19 | private set; 20 | } 21 | 22 | public bool IsReadyToExecute() 23 | { 24 | return File.Exists(_executable); 25 | } 26 | 27 | public async Task EnsurePackageInstalled() 28 | { 29 | if (IsInstalling) 30 | return false; 31 | 32 | if (IsReadyToExecute()) 33 | return true; 34 | 35 | IsInstalling = true; 36 | 37 | try 38 | { 39 | if (!Directory.Exists(_installDir)) 40 | Directory.CreateDirectory(_installDir); 41 | 42 | var start = new ProcessStartInfo("cmd", $"/c npm install {Packages}") 43 | { 44 | WorkingDirectory = _installDir, 45 | UseShellExecute = false, 46 | CreateNoWindow = true, 47 | RedirectStandardOutput = true, 48 | RedirectStandardError = true, 49 | StandardOutputEncoding = Encoding.UTF8, 50 | StandardErrorEncoding = Encoding.UTF8, 51 | }; 52 | 53 | ModifyPathVariable(start); 54 | 55 | using (var proc = Process.Start(start)) 56 | { 57 | string output = await proc.StandardOutput.ReadToEndAsync(); 58 | string error = await proc.StandardError.ReadToEndAsync(); 59 | 60 | if (!string.IsNullOrEmpty(output)) 61 | Logger.Log(output); 62 | 63 | if (!string.IsNullOrEmpty(error)) 64 | Logger.Log(error); 65 | 66 | proc.WaitForExit(); 67 | return proc.ExitCode == 0; 68 | } 69 | } 70 | catch (Exception ex) 71 | { 72 | Logger.Log(ex); 73 | return false; 74 | } 75 | finally 76 | { 77 | IsInstalling = false; 78 | } 79 | } 80 | 81 | public async Task ExecuteProcess(string input) 82 | { 83 | if (!await EnsurePackageInstalled()) 84 | return null; 85 | 86 | var start = new ProcessStartInfo("cmd", $"/c \"{_executable}\" --use autoprefixer --no-map") 87 | { 88 | UseShellExecute = false, 89 | CreateNoWindow = true, 90 | RedirectStandardOutput = true, 91 | RedirectStandardError = true, 92 | RedirectStandardInput = true, 93 | StandardOutputEncoding = Encoding.UTF8, 94 | StandardErrorEncoding = Encoding.UTF8, 95 | }; 96 | 97 | ModifyPathVariable(start); 98 | 99 | try 100 | { 101 | using (var proc = Process.Start(start)) 102 | { 103 | using (var stream = new StreamWriter(proc.StandardInput.BaseStream, Encoding.UTF8)) 104 | { 105 | await stream.WriteAsync(input); 106 | } 107 | 108 | string output = await proc.StandardOutput.ReadToEndAsync(); 109 | string error = await proc.StandardError.ReadToEndAsync(); 110 | 111 | if (!string.IsNullOrEmpty(error)) 112 | { 113 | Logger.Log(error); 114 | } 115 | 116 | proc.WaitForExit(); 117 | return output; 118 | } 119 | } 120 | catch (Exception ex) 121 | { 122 | Logger.Log(ex); 123 | return null; 124 | } 125 | } 126 | 127 | private static void ModifyPathVariable(ProcessStartInfo start) 128 | { 129 | string path = start.EnvironmentVariables["PATH"]; 130 | 131 | var process = Process.GetCurrentProcess(); 132 | string ideDir = Path.GetDirectoryName(process.MainModule.FileName); 133 | 134 | if (Directory.Exists(ideDir)) 135 | { 136 | string parent = Directory.GetParent(ideDir).Parent.FullName; 137 | 138 | string rc2Preview1Path = new DirectoryInfo(Path.Combine(parent, @"Web\External")).FullName; 139 | 140 | if (Directory.Exists(rc2Preview1Path)) 141 | { 142 | path += ";" + rc2Preview1Path; 143 | path += ";" + rc2Preview1Path + "\\git"; 144 | } 145 | else 146 | { 147 | path += ";" + Path.Combine(ideDir, @"Extensions\Microsoft\Web Tools\External"); 148 | path += ";" + Path.Combine(ideDir, @"Extensions\Microsoft\Web Tools\External\git"); 149 | } 150 | } 151 | 152 | start.EnvironmentVariables["PATH"] = path; 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Looking to contribute something? **Here's how you can help.** 4 | 5 | Please take a moment to review this document in order to make the contribution 6 | process easy and effective for everyone involved. 7 | 8 | Following these guidelines helps to communicate that you respect the time of 9 | the developers managing and developing this open source project. In return, 10 | they should reciprocate that respect in addressing your issue or assessing 11 | patches and features. 12 | 13 | 14 | ## Using the issue tracker 15 | 16 | The issue tracker is the preferred channel for [bug reports](#bug-reports), 17 | [features requests](#feature-requests) and 18 | [submitting pull requests](#pull-requests), but please respect the 19 | following restrictions: 20 | 21 | * Please **do not** use the issue tracker for personal support requests. Stack 22 | Overflow is a better place to get help. 23 | 24 | * Please **do not** derail or troll issues. Keep the discussion on topic and 25 | respect the opinions of others. 26 | 27 | * Please **do not** open issues or pull requests which *belongs to* third party 28 | components. 29 | 30 | 31 | ## Bug reports 32 | 33 | A bug is a _demonstrable problem_ that is caused by the code in the repository. 34 | Good bug reports are extremely helpful, so thanks! 35 | 36 | Guidelines for bug reports: 37 | 38 | 1. **Use the GitHub issue search** — check if the issue has already been 39 | reported. 40 | 41 | 2. **Check if the issue has been fixed** — try to reproduce it using the 42 | latest `master` or development branch in the repository. 43 | 44 | 3. **Isolate the problem** — ideally create an 45 | [SSCCE](http://www.sscce.org/) and a live example. 46 | Uploading the project on cloud storage (OneDrive, DropBox, et el.) 47 | or creating a sample GitHub repository is also helpful. 48 | 49 | 50 | A good bug report shouldn't leave others needing to chase you up for more 51 | information. Please try to be as detailed as possible in your report. What is 52 | your environment? What steps will reproduce the issue? What browser(s) and OS 53 | experience the problem? Do other browsers show the bug differently? What 54 | would you expect to be the outcome? All these details will help people to fix 55 | any potential bugs. 56 | 57 | Example: 58 | 59 | > Short and descriptive example bug report title 60 | > 61 | > A summary of the issue and the Visual Studio, browser, OS environments 62 | > in which it occurs. If suitable, include the steps required to reproduce the bug. 63 | > 64 | > 1. This is the first step 65 | > 2. This is the second step 66 | > 3. Further steps, etc. 67 | > 68 | > `` - a link to the project/file uploaded on cloud storage or other publicly accessible medium. 69 | > 70 | > Any other information you want to share that is relevant to the issue being 71 | > reported. This might include the lines of code that you have identified as 72 | > causing the bug, and potential solutions (and your opinions on their 73 | > merits). 74 | 75 | 76 | ## Feature requests 77 | 78 | Feature requests are welcome. But take a moment to find out whether your idea 79 | fits with the scope and aims of the project. It's up to *you* to make a strong 80 | case to convince the project's developers of the merits of this feature. Please 81 | provide as much detail and context as possible. 82 | 83 | 84 | ## Pull requests 85 | 86 | Good pull requests, patches, improvements and new features are a fantastic 87 | help. They should remain focused in scope and avoid containing unrelated 88 | commits. 89 | 90 | **Please ask first** before embarking on any significant pull request (e.g. 91 | implementing features, refactoring code, porting to a different language), 92 | otherwise you risk spending a lot of time working on something that the 93 | project's developers might not want to merge into the project. 94 | 95 | Please adhere to the [coding guidelines](#code-guidelines) used throughout the 96 | project (indentation, accurate comments, etc.) and any other requirements 97 | (such as test coverage). 98 | 99 | Adhering to the following process is the best way to get your work 100 | included in the project: 101 | 102 | 1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork, 103 | and configure the remotes: 104 | 105 | ```bash 106 | # Clone your fork of the repo into the current directory 107 | git clone https://github.com//.git 108 | # Navigate to the newly cloned directory 109 | cd 110 | # Assign the original repo to a remote called "upstream" 111 | git remote add upstream https://github.com/madskristensen/.git 112 | ``` 113 | 114 | 2. If you cloned a while ago, get the latest changes from upstream: 115 | 116 | ```bash 117 | git checkout master 118 | git pull upstream master 119 | ``` 120 | 121 | 3. Create a new topic branch (off the main project development branch) to 122 | contain your feature, change, or fix: 123 | 124 | ```bash 125 | git checkout -b 126 | ``` 127 | 128 | 4. Commit your changes in logical chunks. Please adhere to these [git commit 129 | message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 130 | or your code is unlikely be merged into the main project. Use Git's 131 | [interactive rebase](https://help.github.com/articles/interactive-rebase) 132 | feature to tidy up your commits before making them public. Also, prepend name of the feature 133 | to the commit message. For instance: "SCSS: Fixes compiler results for IFileListener.\nFixes `#123`" 134 | 135 | 5. Locally merge (or rebase) the upstream development branch into your topic branch: 136 | 137 | ```bash 138 | git pull [--rebase] upstream master 139 | ``` 140 | 141 | 6. Push your topic branch up to your fork: 142 | 143 | ```bash 144 | git push origin 145 | ``` 146 | 147 | 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) 148 | with a clear title and description against the `master` branch. 149 | 150 | 151 | ## Code guidelines 152 | 153 | - Always use proper indentation. 154 | - In Visual Studio under `Tools > Options > Text Editor > C# > Advanced`, make sure 155 | `Place 'System' directives first when sorting usings` option is enabled (checked). 156 | - Before committing, organize usings for each updated C# source file. Either you can 157 | right-click editor and select `Organize Usings > Remove and sort` OR use extension 158 | like [BatchFormat](http://visualstudiogallery.msdn.microsoft.com/a7f75c34-82b4-4357-9c66-c18e32b9393e). 159 | - Before committing, run Code Analysis in `Debug` configuration and follow the guidelines 160 | to fix CA issues. Code Analysis commits can be made separately. 161 | -------------------------------------------------------------------------------- /src/CssAutoPrefixer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $(VisualStudioVersion) 6 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 7 | true 8 | v3 9 | Program 10 | $(DevEnvDir)\devenv.exe 11 | /rootsuffix Exp 12 | 13 | 14 | 15 | 16 | 17 | Debug 18 | AnyCPU 19 | 2.0 20 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 21 | {D1F752E5-6CAB-4513-980A-51B44E104CDF} 22 | Library 23 | Properties 24 | CssAutoPrefixer 25 | CssAutoPrefixer 26 | v4.5.2 27 | true 28 | true 29 | true 30 | true 31 | true 32 | false 33 | 34 | 35 | true 36 | full 37 | false 38 | bin\Debug\ 39 | DEBUG;TRACE 40 | prompt 41 | 4 42 | 43 | 44 | pdbonly 45 | true 46 | bin\Release\ 47 | TRACE 48 | prompt 49 | 4 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | True 61 | True 62 | source.extension.vsixmanifest 63 | 64 | 65 | True 66 | True 67 | VSCommandTable.vsct 68 | 69 | 70 | 71 | 72 | Resources\LICENSE 73 | true 74 | 75 | 76 | 77 | Designer 78 | VsixManifestGenerator 79 | source.extension.cs 80 | 81 | 82 | 83 | 84 | False 85 | False 86 | 87 | 88 | False 89 | False 90 | 91 | 92 | False 93 | False 94 | 95 | 96 | False 97 | False 98 | 99 | 100 | 101 | 102 | False 103 | False 104 | 105 | 106 | ..\packages\Microsoft.VisualStudio.CoreUtility.14.3.25407\lib\net45\Microsoft.VisualStudio.CoreUtility.dll 107 | False 108 | 109 | 110 | ..\packages\Microsoft.VisualStudio.Editor.14.3.25407\lib\net45\Microsoft.VisualStudio.Editor.dll 111 | False 112 | 113 | 114 | ..\packages\Microsoft.VisualStudio.Imaging.14.3.25407\lib\net45\Microsoft.VisualStudio.Imaging.dll 115 | False 116 | 117 | 118 | ..\packages\Microsoft.VisualStudio.OLE.Interop.7.10.6070\lib\Microsoft.VisualStudio.OLE.Interop.dll 119 | False 120 | 121 | 122 | ..\packages\Microsoft.VisualStudio.Shell.14.0.14.3.25407\lib\Microsoft.VisualStudio.Shell.14.0.dll 123 | False 124 | 125 | 126 | ..\packages\Microsoft.VisualStudio.Shell.Immutable.10.0.10.0.30319\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll 127 | False 128 | 129 | 130 | ..\packages\Microsoft.VisualStudio.Shell.Immutable.11.0.11.0.50727\lib\net45\Microsoft.VisualStudio.Shell.Immutable.11.0.dll 131 | False 132 | 133 | 134 | ..\packages\Microsoft.VisualStudio.Shell.Immutable.12.0.12.0.21003\lib\net45\Microsoft.VisualStudio.Shell.Immutable.12.0.dll 135 | False 136 | 137 | 138 | ..\packages\Microsoft.VisualStudio.Shell.Immutable.14.0.14.3.25407\lib\net45\Microsoft.VisualStudio.Shell.Immutable.14.0.dll 139 | False 140 | 141 | 142 | ..\packages\Microsoft.VisualStudio.Shell.Interop.7.10.6071\lib\Microsoft.VisualStudio.Shell.Interop.dll 143 | False 144 | 145 | 146 | True 147 | ..\packages\Microsoft.VisualStudio.Shell.Interop.10.0.10.0.30319\lib\Microsoft.VisualStudio.Shell.Interop.10.0.dll 148 | True 149 | 150 | 151 | True 152 | ..\packages\Microsoft.VisualStudio.Shell.Interop.11.0.11.0.61030\lib\Microsoft.VisualStudio.Shell.Interop.11.0.dll 153 | True 154 | 155 | 156 | True 157 | ..\packages\Microsoft.VisualStudio.Shell.Interop.12.0.12.0.30110\lib\Microsoft.VisualStudio.Shell.Interop.12.0.dll 158 | True 159 | 160 | 161 | ..\packages\Microsoft.VisualStudio.Shell.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.Shell.Interop.8.0.dll 162 | False 163 | 164 | 165 | ..\packages\Microsoft.VisualStudio.Shell.Interop.9.0.9.0.30729\lib\Microsoft.VisualStudio.Shell.Interop.9.0.dll 166 | False 167 | 168 | 169 | ..\packages\Microsoft.VisualStudio.Text.Data.14.3.25407\lib\net45\Microsoft.VisualStudio.Text.Data.dll 170 | False 171 | 172 | 173 | ..\packages\Microsoft.VisualStudio.Text.Logic.14.3.25407\lib\net45\Microsoft.VisualStudio.Text.Logic.dll 174 | False 175 | 176 | 177 | ..\packages\Microsoft.VisualStudio.Text.UI.14.3.25407\lib\net45\Microsoft.VisualStudio.Text.UI.dll 178 | False 179 | 180 | 181 | ..\packages\Microsoft.VisualStudio.Text.UI.Wpf.14.3.25407\lib\net45\Microsoft.VisualStudio.Text.UI.Wpf.dll 182 | False 183 | 184 | 185 | ..\packages\Microsoft.VisualStudio.TextManager.Interop.7.10.6070\lib\Microsoft.VisualStudio.TextManager.Interop.dll 186 | False 187 | 188 | 189 | ..\packages\Microsoft.VisualStudio.TextManager.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.TextManager.Interop.8.0.dll 190 | False 191 | 192 | 193 | ..\packages\Microsoft.VisualStudio.Threading.14.1.111\lib\net45\Microsoft.VisualStudio.Threading.dll 194 | False 195 | 196 | 197 | ..\packages\Microsoft.VisualStudio.Utilities.14.3.25407\lib\net45\Microsoft.VisualStudio.Utilities.dll 198 | False 199 | 200 | 201 | ..\packages\Microsoft.VisualStudio.Validation.14.1.111\lib\net45\Microsoft.VisualStudio.Validation.dll 202 | False 203 | 204 | 205 | False 206 | False 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | Menus.ctmenu 218 | VsctGenerator 219 | VSCommandTable.cs 220 | 221 | 222 | 223 | 224 | true 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 233 | 234 | 235 | 236 | 237 | 238 | 239 | 246 | --------------------------------------------------------------------------------