├── .gitattributes ├── .gitignore ├── AutoT4MVC.sln ├── AutoT4MVC ├── AutoT4MVC.csproj ├── AutoT4MVC.dll.config ├── AutoT4MVC.vsct ├── AutoT4MVCPackage.cs ├── Controller.cs ├── GlobalSuppressions.cs ├── Guids.cs ├── Key.snk ├── LICENCE.txt ├── Options.cs ├── PkgCmdID.cs ├── ProjectEventArgs.cs ├── ProjectItemExtensions.cs ├── Properties │ └── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── T4MVCSettings.cs ├── T4MVCSettingsBuilder.cs ├── T4MVCSettingsCache.cs ├── VSPackage.resx ├── noun_project_2223.png ├── packages.config └── source.extension.vsixmanifest ├── LICENCE.txt └── README.md /.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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | [Dd]ebug/ 46 | [Rr]elease/ 47 | *_i.c 48 | *_p.c 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.vspscc 63 | .builds 64 | *.dotCover 65 | 66 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 67 | packages/ 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | 76 | # Visual Studio profiler 77 | *.psess 78 | *.vsp 79 | 80 | # ReSharper is a .NET coding add-in 81 | _ReSharper* 82 | 83 | # Installshield output folder 84 | [Ee]xpress 85 | 86 | # DocProject is a documentation generator add-in 87 | DocProject/buildhelp/ 88 | DocProject/Help/*.HxT 89 | DocProject/Help/*.HxC 90 | DocProject/Help/*.hhc 91 | DocProject/Help/*.hhk 92 | DocProject/Help/*.hhp 93 | DocProject/Help/Html2 94 | DocProject/Help/html 95 | 96 | # Click-Once directory 97 | publish 98 | 99 | # Others 100 | [Bb]in 101 | [Oo]bj 102 | sql 103 | TestResults 104 | *.Cache 105 | ClientBin 106 | stylecop.* 107 | ~$* 108 | *.dbmdl 109 | Generated_Code #added for RIA/Silverlight projects 110 | 111 | # Backup & report files from converting an old project file to a newer 112 | # Visual Studio version. Backup files are not needed, because we have git ;-) 113 | _UpgradeReport_Files/ 114 | Backup*/ 115 | UpgradeLog*.XML 116 | 117 | # NCrunch 118 | *.ncrunchsolution 119 | 120 | ############ 121 | ## Windows 122 | ############ 123 | 124 | # Windows image file caches 125 | Thumbs.db 126 | 127 | # Folder config file 128 | Desktop.ini 129 | 130 | 131 | ############# 132 | ## Python 133 | ############# 134 | 135 | *.py[co] 136 | 137 | # Packages 138 | *.egg 139 | *.egg-info 140 | dist 141 | build 142 | eggs 143 | parts 144 | bin 145 | var 146 | sdist 147 | develop-eggs 148 | .installed.cfg 149 | 150 | # Installer logs 151 | pip-log.txt 152 | 153 | # Unit test / coverage reports 154 | .coverage 155 | .tox 156 | 157 | #Translations 158 | *.mo 159 | 160 | #Mr Developer 161 | .mr.developer.cfg 162 | 163 | # Mac crap 164 | .DS_Store 165 | -------------------------------------------------------------------------------- /AutoT4MVC.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26228.9 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoT4MVC", "AutoT4MVC\AutoT4MVC.csproj", "{E25F1D10-8F69-4FD8-8032-CAFDA99934CC}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {E25F1D10-8F69-4FD8-8032-CAFDA99934CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {E25F1D10-8F69-4FD8-8032-CAFDA99934CC}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {E25F1D10-8F69-4FD8-8032-CAFDA99934CC}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {E25F1D10-8F69-4FD8-8032-CAFDA99934CC}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /AutoT4MVC/AutoT4MVC.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 15.0 5 | 11.0 6 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 7 | 8 | 9 | 10 | 11 | 4.0 12 | false 13 | publish\ 14 | true 15 | Disk 16 | false 17 | Foreground 18 | 7 19 | Days 20 | false 21 | false 22 | true 23 | 0 24 | 1.0.0.%2a 25 | false 26 | true 27 | 28 | 29 | 30 | 31 | Debug 32 | AnyCPU 33 | 2.0 34 | {E25F1D10-8F69-4FD8-8032-CAFDA99934CC} 35 | {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 36 | Library 37 | Properties 38 | AutoT4MVC 39 | AutoT4MVC 40 | True 41 | Key.snk 42 | v4.6 43 | 44 | 45 | true 46 | full 47 | false 48 | bin\Debug\ 49 | DEBUG;TRACE 50 | prompt 51 | 4 52 | True 53 | 54 | 55 | pdbonly 56 | true 57 | bin\Release\ 58 | TRACE 59 | prompt 60 | 4 61 | true 62 | True 63 | 64 | 65 | 66 | False 67 | 68 | 69 | True 70 | 71 | 72 | True 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | True 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | ..\packages\Rx-Core.2.0.21114\lib\Net45\System.Reactive.Core.dll 95 | 96 | 97 | ..\packages\Rx-Interfaces.2.0.21114\lib\Net45\System.Reactive.Interfaces.dll 98 | 99 | 100 | ..\packages\Rx-Linq.2.0.21114\lib\Net45\System.Reactive.Linq.dll 101 | 102 | 103 | ..\packages\Rx-PlatformServices.2.0.21114\lib\Net45\System.Reactive.PlatformServices.dll 104 | 105 | 106 | 107 | 108 | 109 | True 110 | 111 | 112 | 113 | 114 | {1CBA492E-7263-47BB-87FE-639000619B15} 115 | 8 116 | 0 117 | 0 118 | primary 119 | False 120 | False 121 | 122 | 123 | {00020430-0000-0000-C000-000000000046} 124 | 2 125 | 0 126 | 0 127 | primary 128 | False 129 | False 130 | 131 | 132 | 133 | 134 | 135 | 136 | Component 137 | 138 | 139 | 140 | 141 | 142 | True 143 | True 144 | Resources.resx 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | ResXFileCodeGenerator 156 | Resources.Designer.cs 157 | Designer 158 | 159 | 160 | true 161 | VSPackage 162 | Designer 163 | 164 | 165 | 166 | 167 | true 168 | 169 | 170 | Always 171 | true 172 | 173 | 174 | Designer 175 | 176 | 177 | Designer 178 | 179 | 180 | 181 | 182 | Menus.ctmenu 183 | Designer 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | Always 192 | true 193 | 194 | 195 | 196 | 197 | False 198 | Microsoft .NET Framework 4.5 %28x86 and x64%29 199 | true 200 | 201 | 202 | False 203 | .NET Framework 3.5 SP1 Client Profile 204 | false 205 | 206 | 207 | False 208 | .NET Framework 3.5 SP1 209 | false 210 | 211 | 212 | 213 | true 214 | 215 | 216 | 217 | 224 | -------------------------------------------------------------------------------- /AutoT4MVC/AutoT4MVC.dll.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /AutoT4MVC/AutoT4MVC.vsct: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /AutoT4MVC/AutoT4MVCPackage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.Design; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using EnvDTE; 7 | using EnvDTE80; 8 | using Microsoft.VisualStudio; 9 | using Microsoft.VisualStudio.Shell; 10 | using Microsoft.VisualStudio.Shell.Interop; 11 | 12 | namespace AutoT4MVC 13 | { 14 | [PackageRegistration(UseManagedResourcesOnly = true)] 15 | [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] 16 | [Guid(GuidList.guidAutoT4MVCPkgString)] 17 | [ProvideAutoLoad(VSConstants.UICONTEXT.SolutionExists_string)] 18 | [ProvideOptionPage(typeof (Options), Options.CategoryName, Options.PageName, 1000, 1001, false)] 19 | [ProvideMenuResource("Menus.ctmenu", 1)] 20 | public sealed class AutoT4MVCPackage : Package 21 | { 22 | private BuildEvents _buildEvents; 23 | private Controller _controller; 24 | private DocumentEvents _documentEvents; 25 | private DTE _dte; 26 | private ProjectItemsEvents _projectItemsEvents; 27 | private SolutionEvents _solutionEvents; 28 | 29 | private Options Options 30 | { 31 | get { return (Options)GetDialogPage(typeof (Options)); } 32 | } 33 | 34 | protected override void Initialize() 35 | { 36 | base.Initialize(); 37 | 38 | _dte = GetService(typeof (SDTE)) as DTE; 39 | if (_dte == null) 40 | return; 41 | 42 | _controller = new Controller(); 43 | 44 | _buildEvents = _dte.Events.BuildEvents; 45 | _buildEvents.OnBuildBegin += OnBuildBegin; 46 | 47 | _documentEvents = _dte.Events.DocumentEvents; 48 | _documentEvents.DocumentSaved += DocumentSaved; 49 | 50 | var events2 = _dte.Events as Events2; 51 | if (events2 == null) 52 | return; 53 | 54 | _projectItemsEvents = events2.ProjectItemsEvents; 55 | _projectItemsEvents.ItemAdded += ItemAdded; 56 | _projectItemsEvents.ItemRemoved += ItemRemoved; 57 | _projectItemsEvents.ItemRenamed += ItemRenamed; 58 | 59 | _solutionEvents = _dte.Events.SolutionEvents; 60 | _solutionEvents.ProjectRemoved += ProjectRemoved; 61 | 62 | var menuCommandService = GetService(typeof(IMenuCommandService)) as OleMenuCommandService; 63 | if (null != menuCommandService) 64 | { 65 | var showOptionsCommandId = new CommandID(GuidList.guidAutoT4MVCCmdSet, 66 | (int) PkgCmdIDList.cmdidShowOptions); 67 | var showOptionsMenuCommand = new OleMenuCommand(ShowOptions, showOptionsCommandId); 68 | menuCommandService.AddCommand(showOptionsMenuCommand); 69 | showOptionsMenuCommand.BeforeQueryStatus += ShowOptionsMenuCommandOnBeforeQueryStatus; 70 | } 71 | } 72 | 73 | private void ProjectRemoved(Project project) 74 | { 75 | _controller.HandleProjectUnload(project); 76 | } 77 | 78 | private void DocumentSaved(Document document) 79 | { 80 | if (!Options.RunOnSave) 81 | return; 82 | 83 | _controller.HandleContentChange(document.ProjectItem); 84 | } 85 | 86 | private void ItemRenamed(ProjectItem projectItem, string oldName) 87 | { 88 | if (!Options.RunOnSave) 89 | return; 90 | 91 | _controller.HandleNameChange(projectItem); 92 | } 93 | 94 | private void ItemRemoved(ProjectItem projectItem) 95 | { 96 | if (!Options.RunOnSave) 97 | return; 98 | 99 | _controller.HandleNameChange(projectItem); 100 | } 101 | 102 | private void ItemAdded(ProjectItem projectItem) 103 | { 104 | if (!Options.RunOnSave) 105 | return; 106 | 107 | _controller.HandleNameChange(projectItem); 108 | } 109 | 110 | private void OnBuildBegin(vsBuildScope scope, vsBuildAction action) 111 | { 112 | if (!Options.RunOnBuild) 113 | return; 114 | 115 | IEnumerable projects; 116 | switch (scope) 117 | { 118 | case vsBuildScope.vsBuildScopeProject: 119 | case vsBuildScope.vsBuildScopeBatch: 120 | projects = ((object[]) _dte.ActiveSolutionProjects).OfType(); 121 | break; 122 | case vsBuildScope.vsBuildScopeSolution: 123 | default: 124 | // Sometimes when you hit F5 to run a project, VS gives the undefined value 0 as vsBuildScope, 125 | // so in this case we default to running templates for all projects 126 | projects = _dte.Solution.Projects.OfType(); 127 | break; 128 | } 129 | 130 | _controller.RunTemplates(projects); 131 | } 132 | 133 | private void ShowOptionsMenuCommandOnBeforeQueryStatus(object sender, EventArgs eventArgs) 134 | { 135 | var showOptionsMenuCommand = sender as OleMenuCommand; 136 | if (showOptionsMenuCommand == null) 137 | return; 138 | 139 | var monitorSelection = (IVsMonitorSelection)GetGlobalService(typeof(SVsShellMonitorSelection)); 140 | IntPtr hierarchyPtr; 141 | IntPtr selectionContainerPtr; 142 | uint projectItemId; 143 | IVsMultiItemSelect mis; 144 | monitorSelection.GetCurrentSelection(out hierarchyPtr, out projectItemId, out mis, out selectionContainerPtr); 145 | 146 | var hierarchy = Marshal.GetTypedObjectForIUnknown(hierarchyPtr, typeof(IVsHierarchy)) as IVsHierarchy; 147 | if (hierarchy == null) 148 | return; 149 | 150 | object value; 151 | hierarchy.GetProperty(projectItemId, (int)__VSHPROPID.VSHPROPID_Name, out value); 152 | 153 | showOptionsMenuCommand.Visible = string.Equals(value as string, "T4MVC.tt", StringComparison.OrdinalIgnoreCase); 154 | } 155 | 156 | private void ShowOptions(object sender, EventArgs e) 157 | { 158 | ShowOptionPage(typeof(Options)); 159 | } 160 | 161 | protected override int QueryClose(out bool canClose) 162 | { 163 | int result = base.QueryClose(out canClose); 164 | if (!canClose) 165 | return result; 166 | 167 | if (_solutionEvents != null) 168 | { 169 | _solutionEvents.ProjectRemoved -= ProjectRemoved; 170 | _solutionEvents = null; 171 | } 172 | if (_buildEvents != null) 173 | { 174 | _buildEvents.OnBuildBegin -= OnBuildBegin; 175 | _buildEvents = null; 176 | } 177 | if (_documentEvents != null) 178 | { 179 | _documentEvents.DocumentSaved -= DocumentSaved; 180 | _documentEvents = null; 181 | } 182 | if (_projectItemsEvents != null) 183 | { 184 | _projectItemsEvents.ItemAdded -= ItemAdded; 185 | _projectItemsEvents.ItemRemoved -= ItemRemoved; 186 | _projectItemsEvents.ItemRenamed -= ItemRenamed; 187 | } 188 | if (_controller != null) 189 | _controller.Dispose(); 190 | 191 | return result; 192 | } 193 | } 194 | } -------------------------------------------------------------------------------- /AutoT4MVC/Controller.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using EnvDTE; 9 | using System.Reactive.Linq; 10 | using VSLangProj; 11 | 12 | namespace AutoT4MVC 13 | { 14 | public sealed class Controller : IDisposable 15 | { 16 | private event EventHandler Update; 17 | 18 | private IDisposable _projectSubscription; 19 | private readonly T4MVCSettingsCache _settingsCache; 20 | 21 | public Controller() 22 | { 23 | _settingsCache = new T4MVCSettingsCache(); 24 | 25 | _projectSubscription = Observable.FromEventPattern(e => Update += e, e => Update -= e) 26 | .Select(e => e.EventArgs.Project) 27 | .GroupBy(p => p) 28 | .SelectMany(g => g.Throttle(TimeSpan.FromSeconds(1))) 29 | .Subscribe(RunTemplate); 30 | } 31 | 32 | public void HandleNameChange(ProjectItem item) 33 | { 34 | var reloadSettings = T4MVCSettings.RequiresCacheInvalidation(item); 35 | 36 | var settings = _settingsCache.GetSettings(item, reloadSettings); 37 | 38 | if (settings == null) 39 | return; 40 | 41 | if (settings.TriggerOnNameChange(item)) 42 | Update(this, new ProjectEventArgs(item.ContainingProject)); 43 | } 44 | 45 | public void HandleContentChange(ProjectItem item) 46 | { 47 | var reloadSettings = T4MVCSettings.RequiresCacheInvalidation(item); 48 | 49 | var settings = _settingsCache.GetSettings(item, reloadSettings); 50 | 51 | if (settings == null) 52 | return; 53 | 54 | if (settings.TriggerOnContentChange(item)) 55 | Update(this, new ProjectEventArgs(item.ContainingProject)); 56 | } 57 | 58 | public void HandleProjectUnload(Project project) 59 | { 60 | _settingsCache.InvalidateSettings(project); 61 | } 62 | 63 | public void RunTemplates(IEnumerable projects) 64 | { 65 | if (projects == null) 66 | return; 67 | 68 | var templates = projects.Where(p => p != null).FindProjectItems("T4MVC.tt"); 69 | foreach (var template in templates) 70 | { 71 | var templateVsProjectItem = template.Object as VSProjectItem; 72 | if (templateVsProjectItem != null) 73 | { 74 | templateVsProjectItem.RunCustomTool(); 75 | } 76 | else 77 | { 78 | if (!template.IsOpen) 79 | template.Open(); 80 | template.Save(); 81 | } 82 | } 83 | } 84 | public void RunTemplate(Project project) 85 | { 86 | if (project == null) 87 | return; 88 | 89 | RunTemplates(new[] { project }); 90 | } 91 | 92 | public void Dispose() 93 | { 94 | if (_projectSubscription != null) 95 | { 96 | _projectSubscription.Dispose(); 97 | _projectSubscription = null; 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /AutoT4MVC/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. Project-level 3 | // suppressions either have no target or are given a specific target 4 | // and scoped to a namespace, type, member, etc. 5 | // 6 | // To add a suppression to this file, right-click the message in the 7 | // Error List, point to "Suppress Message(s)", and click "In Project 8 | // Suppression File". You do not need to add suppressions to this 9 | // file manually. 10 | 11 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")] 12 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", Scope = "type", Target = "AutoT4MVC.AutoT4MVCPackage")] 13 | -------------------------------------------------------------------------------- /AutoT4MVC/Guids.cs: -------------------------------------------------------------------------------- 1 | // Guids.cs 2 | // MUST match guids.h 3 | using System; 4 | 5 | namespace AutoT4MVC 6 | { 7 | static class GuidList 8 | { 9 | public const string guidAutoT4MVCPkgString = "c676817c-46cc-47d3-b03c-8a05f499d4a5"; 10 | public const string guidAutoT4MVCCmdSetString = "3e7abe3a-4955-4c2f-aef7-4672394b69fd"; 11 | 12 | public static readonly Guid guidAutoT4MVCCmdSet = new Guid(guidAutoT4MVCCmdSetString); 13 | }; 14 | } -------------------------------------------------------------------------------- /AutoT4MVC/Key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bennor/AutoT4MVC/c375e47736372a7409666f1b3ce68d52ce06d584/AutoT4MVC/Key.snk -------------------------------------------------------------------------------- /AutoT4MVC/LICENCE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Bennor McCarthy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /AutoT4MVC/Options.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using Microsoft.VisualStudio.Shell; 3 | 4 | namespace AutoT4MVC 5 | { 6 | public class Options : DialogPage 7 | { 8 | private bool _runOnSave = true; 9 | private bool _runOnBuild = true; 10 | 11 | public const string CategoryName = "AutoT4MVC"; 12 | public const string PageName = "General"; 13 | 14 | [Category("General")] 15 | [DisplayName("Run on save")] 16 | [Description("Run T4MVC templates when files in the Controllers, Views, Scripts and Content folders are saved, created or deleted.")] 17 | [DefaultValue(true)] 18 | public bool RunOnSave 19 | { 20 | get { return _runOnSave; } 21 | set { _runOnSave = value; } 22 | } 23 | 24 | [Category("General")] 25 | [DisplayName("Run on build")] 26 | [Description("Run T4MVC templates when building.")] 27 | [DefaultValue(true)] 28 | public bool RunOnBuild 29 | { 30 | get { return _runOnBuild; } 31 | set { _runOnBuild = value; } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /AutoT4MVC/PkgCmdID.cs: -------------------------------------------------------------------------------- 1 | namespace AutoT4MVC 2 | { 3 | static class PkgCmdIDList 4 | { 5 | public const uint cmdidShowOptions = 0x100; 6 | }; 7 | } -------------------------------------------------------------------------------- /AutoT4MVC/ProjectEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using EnvDTE; 4 | 5 | namespace AutoT4MVC 6 | { 7 | public class ProjectEventArgs : EventArgs 8 | { 9 | public Project Project { get; private set; } 10 | 11 | public ProjectEventArgs(Project project) 12 | { 13 | if (project == null) 14 | throw new ArgumentNullException("project"); 15 | 16 | Project = project; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /AutoT4MVC/ProjectItemExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using EnvDTE; 7 | 8 | namespace AutoT4MVC 9 | { 10 | public static class ProjectItemExtensions 11 | { 12 | public static IEnumerable FindProjectItems(this Project project, string name) 13 | { 14 | return project.ProjectItems.FindProjectItems(name); 15 | } 16 | 17 | public static IEnumerable FindProjectItems(this IEnumerable projects, string name) 18 | { 19 | return projects.SelectMany(project => project.ProjectItems.FindProjectItems(name)); 20 | } 21 | 22 | private static IEnumerable FindProjectItems(this ProjectItems projectItems, string name) 23 | { 24 | foreach (ProjectItem projectItem in projectItems) 25 | { 26 | if (StringComparer.OrdinalIgnoreCase.Equals(projectItem.Name, name)) 27 | yield return projectItem; 28 | 29 | if (projectItem.ProjectItems != null) 30 | { 31 | foreach (var subItem in projectItem.ProjectItems.FindProjectItems(name)) 32 | yield return subItem; 33 | } 34 | if (projectItem.SubProject != null) 35 | { 36 | foreach (var subItem in projectItem.SubProject.ProjectItems.FindProjectItems(name)) 37 | yield return subItem; 38 | } 39 | } 40 | } 41 | 42 | public static bool HasProject(this ProjectItem projectItem) 43 | { 44 | if (projectItem == null) 45 | throw new ArgumentNullException("projectItem"); 46 | 47 | return projectItem.ContainingProject != null 48 | && !string.Equals(projectItem.ContainingProject.Name, "Miscellaneous Files", 49 | StringComparison.OrdinalIgnoreCase); 50 | } 51 | 52 | public static bool MatchesAnyPathFragment(this ProjectItem projectItem, IList pathFragments) 53 | { 54 | if (projectItem == null) 55 | throw new ArgumentNullException("projectItem"); 56 | 57 | if (pathFragments == null) 58 | return false; 59 | 60 | return projectItem.GetFileNames() 61 | .Any(fileName => 62 | pathFragments.Any(p => 63 | fileName.IndexOf(p, StringComparison.OrdinalIgnoreCase) > -1)); 64 | } 65 | 66 | public static IEnumerable GetFileNames(this ProjectItem item) 67 | { 68 | var projectFolderPath = item.HasProject() 69 | ? Path.GetDirectoryName(item.ContainingProject.FullName) 70 | : null; 71 | 72 | return Enumerable.Range(0, item.FileCount).Select(i => 73 | { 74 | try 75 | { 76 | string fileName = item.FileNames[(short)i]; 77 | 78 | if (projectFolderPath != null) 79 | fileName = fileName.Replace(projectFolderPath, ""); 80 | 81 | return fileName; 82 | } 83 | catch (COMException) { return null; /* Ignore invalid exceptions */ } 84 | }).Where(f => !string.IsNullOrWhiteSpace(f)); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /AutoT4MVC/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Resources; 4 | using System.Runtime.CompilerServices; 5 | using System.Runtime.InteropServices; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("AutoT4MVC")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("Bennor McCarthy")] 14 | [assembly: AssemblyProduct("AutoT4MVC")] 15 | [assembly: AssemblyCopyright("")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | [assembly: ComVisible(false)] 19 | [assembly: CLSCompliant(false)] 20 | [assembly: NeutralResourcesLanguage("en-US")] 21 | 22 | // Version information for an assembly consists of the following four values: 23 | // 24 | // Major Version 25 | // Minor Version 26 | // Build Number 27 | // Revision 28 | // 29 | // You can specify all the values or you can default the Revision and Build Numbers 30 | // by using the '*' as shown below: 31 | 32 | [assembly: AssemblyVersion("1.5.3.0")] 33 | [assembly: AssemblyFileVersion("1.5.3.0")] 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /AutoT4MVC/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace AutoT4MVC { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AutoT4MVC.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /AutoT4MVC/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 11 | 12 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | text/microsoft-resx 119 | 120 | 121 | 2.0 122 | 123 | 124 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 125 | 126 | 127 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 128 | 129 | -------------------------------------------------------------------------------- /AutoT4MVC/T4MVCSettings.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace AutoT4MVC 7 | { 8 | public class T4MVCSettings 9 | { 10 | private static readonly string[] SettingsFileNames = 11 | { 12 | @"\T4MVC.tt.settings.xml", 13 | @"\T4MVC.tt.settings.t4" 14 | }; 15 | 16 | public string ControllersFolder { get; set; } 17 | public string ViewsRootFolder { get; set; } 18 | 19 | public List NonQualifiedViewFolders { get; set; } 20 | public List StaticFilesFolders { get; set; } 21 | public List ExcludedStaticFileExtensions { get; set; } 22 | public List ExcludedViewExtensions { get; set; } 23 | 24 | private bool TriggerAlways(ProjectItem item) 25 | { 26 | return IsSettingsFile(item); 27 | } 28 | 29 | public bool TriggerOnNameChange(ProjectItem item) 30 | { 31 | if (TriggerAlways(item)) 32 | return true; 33 | 34 | var contentType = GetContentType(item); 35 | 36 | switch (contentType) 37 | { 38 | case T4ContentType.Controller: 39 | case T4ContentType.View: 40 | case T4ContentType.StaticContent: 41 | return true; 42 | default: 43 | return false; 44 | } 45 | } 46 | 47 | public bool TriggerOnContentChange(ProjectItem item) 48 | { 49 | if (TriggerAlways(item)) 50 | return true; 51 | 52 | var contentType = GetContentType(item); 53 | 54 | switch (contentType) 55 | { 56 | case T4ContentType.Controller: 57 | return true; 58 | default: 59 | return false; 60 | } 61 | } 62 | 63 | private static bool IsSettingsFile(ProjectItem item) 64 | { 65 | return item.GetFileNames() 66 | .Any(fileName => SettingsFileNames 67 | .Any(settingFilename => fileName.EndsWith(settingFilename, StringComparison.InvariantCultureIgnoreCase))); 68 | } 69 | 70 | public static bool RequiresCacheInvalidation(ProjectItem item) 71 | { 72 | return IsSettingsFile(item); 73 | } 74 | 75 | private enum T4ContentType 76 | { 77 | Controller, 78 | View, 79 | StaticContent, 80 | Unknown 81 | } 82 | 83 | private T4ContentType GetContentType(ProjectItem item) 84 | { 85 | var fileNames = item.GetFileNames(); 86 | 87 | foreach (var fileName in fileNames) 88 | { 89 | if (fileName.IndexOf(this.ControllersFolder, StringComparison.InvariantCultureIgnoreCase) >= 0 90 | && fileName.EndsWith(".cs", StringComparison.InvariantCultureIgnoreCase)) 91 | return T4ContentType.Controller; 92 | 93 | if (fileName.IndexOf(this.ViewsRootFolder, StringComparison.InvariantCultureIgnoreCase) >= 0 94 | && ExcludedViewExtensions.All(ee => !fileName.EndsWith(ee, StringComparison.InvariantCultureIgnoreCase)) 95 | && NonQualifiedViewFolders.All(nq => fileName.IndexOf(nq, StringComparison.InvariantCultureIgnoreCase) < 0)) 96 | return T4ContentType.View; 97 | 98 | if (StaticFilesFolders.Any(sff => fileName.StartsWith(sff, StringComparison.InvariantCultureIgnoreCase)) 99 | && ExcludedStaticFileExtensions.All(ee => !fileName.EndsWith(ee, StringComparison.InvariantCultureIgnoreCase))) 100 | return T4ContentType.StaticContent; 101 | } 102 | return T4ContentType.Unknown; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /AutoT4MVC/T4MVCSettingsBuilder.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Xml; 7 | using System.Xml.Linq; 8 | 9 | namespace AutoT4MVC 10 | { 11 | public static class T4MVCSettingsBuilder 12 | { 13 | public static T4MVCSettings BuildDefault() 14 | { 15 | return new T4MVCSettings() 16 | { 17 | ControllersFolder = @"\Controllers\", 18 | ViewsRootFolder = @"\Views\", 19 | NonQualifiedViewFolders = new List(){ 20 | @"\DisplayTemplates\", 21 | @"\EditorTemplates\" 22 | }, 23 | StaticFilesFolders = new List(){ 24 | @"\Scripts\", 25 | @"\Content\" 26 | }, 27 | ExcludedStaticFileExtensions = new List(){ 28 | ".cs", 29 | ".cshtml", 30 | ".aspx", 31 | ".ascx" 32 | }, 33 | ExcludedViewExtensions = new List() 34 | { 35 | ".master", 36 | ".js", 37 | ".css" 38 | } 39 | }; 40 | } 41 | 42 | public static T4MVCSettings Build(Project settingsProject) 43 | { 44 | var t4MVCTemplate = settingsProject.FindProjectItems("T4MVC.tt").FirstOrDefault(); 45 | 46 | // No T4MVC Template 47 | if (t4MVCTemplate == null) 48 | return null; 49 | 50 | // Find Settings XML 51 | var settingsProjectItem = settingsProject.FindProjectItems("T4MVC.tt.settings.xml").FirstOrDefault(); 52 | 53 | // Return default settings if no XML settings file found 54 | if (settingsProjectItem == null) 55 | return BuildDefault(); 56 | else 57 | return Build(settingsProjectItem); 58 | } 59 | 60 | public static T4MVCSettings Build(ProjectItem settingsProjectItem) 61 | { 62 | if (!settingsProjectItem.Name.Equals("T4MVC.tt.settings.xml", StringComparison.InvariantCultureIgnoreCase)) 63 | throw new ArgumentException("Not a valid T4MVC Settings File", "SettingsProjectItem"); 64 | 65 | var settingsFileName = settingsProjectItem.FileNames[0]; 66 | 67 | if (settingsFileName == null 68 | || !File.Exists(settingsFileName)) 69 | return null; 70 | 71 | XDocument xDocument; 72 | try 73 | { 74 | xDocument = XDocument.Load(settingsFileName); 75 | } 76 | catch (XmlException) 77 | { 78 | // Unable to load T4MVC XML Settings File 79 | return null; 80 | } 81 | 82 | var settings = T4MVCSettingsBuilder.BuildDefault(); 83 | 84 | // Controllers Folder 85 | var controllersFolderValue = xDocument.Descendants("ControllersFolder").Select(e => string.Format(@"\{0}\", e.Value)).FirstOrDefault(); 86 | if (controllersFolderValue != null) 87 | settings.ControllersFolder = controllersFolderValue; 88 | 89 | // Views Root Folder 90 | var viewsRootFolderValue = xDocument.Descendants("ViewsRootFolder").Select(e => string.Format(@"\{0}\", e.Value)).FirstOrDefault(); 91 | if (viewsRootFolderValue != null) 92 | settings.ViewsRootFolder = viewsRootFolderValue; 93 | 94 | // Non Qualified View Folders 95 | var nonQualifiedViewFoldersNode = xDocument.Descendants("NonQualifiedViewFolders").FirstOrDefault(); 96 | if (nonQualifiedViewFoldersNode != null) 97 | settings.NonQualifiedViewFolders = nonQualifiedViewFoldersNode.Elements("ViewFolder").Select(e => string.Format(@"\{0}\", e.Value)).ToList(); 98 | 99 | // Static Files Folders 100 | var staticFilesFoldersNode = xDocument.Descendants("StaticFilesFolders").FirstOrDefault(); 101 | if (staticFilesFoldersNode != null) 102 | settings.StaticFilesFolders = staticFilesFoldersNode.Elements("FileFolder").Select(e => string.Format(@"\{0}\", e.Value)).ToList(); 103 | 104 | // Excluded Static File Extensions 105 | var excludedStaticFileExtensionsNode = xDocument.Descendants("ExcludedStaticFileExtensions").FirstOrDefault(); 106 | if (excludedStaticFileExtensionsNode != null) 107 | settings.ExcludedStaticFileExtensions = excludedStaticFileExtensionsNode.Elements("Extension").Select(e => e.Value).ToList(); 108 | 109 | // Excluded View Extensions 110 | var excludedViewExtensionsNode = xDocument.Descendants("ExcludedViewExtensions").FirstOrDefault(); 111 | if (excludedViewExtensionsNode != null) 112 | settings.ExcludedViewExtensions = excludedViewExtensionsNode.Elements("Extension").Select(e => e.Value).ToList(); 113 | 114 | return settings; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /AutoT4MVC/T4MVCSettingsCache.cs: -------------------------------------------------------------------------------- 1 | using EnvDTE; 2 | using System.Collections.Concurrent; 3 | 4 | namespace AutoT4MVC 5 | { 6 | public class T4MVCSettingsCache 7 | { 8 | private readonly ConcurrentDictionary _projectT4MVCSettings; 9 | 10 | public T4MVCSettingsCache() 11 | { 12 | _projectT4MVCSettings = new ConcurrentDictionary(); 13 | } 14 | 15 | public T4MVCSettings GetSettings(Project project) 16 | { 17 | T4MVCSettings settings; 18 | 19 | // Try from Cache 20 | if (_projectT4MVCSettings.TryGetValue(project, out settings)) 21 | return settings; 22 | 23 | // Building Settings 24 | settings = T4MVCSettingsBuilder.Build(project); 25 | 26 | // Cache 27 | _projectT4MVCSettings.TryAdd(project, settings); 28 | 29 | return settings; 30 | } 31 | public T4MVCSettings GetSettings(Project project, bool forceReload) 32 | { 33 | if (forceReload) 34 | InvalidateSettings(project); 35 | 36 | return GetSettings(project); 37 | } 38 | 39 | public T4MVCSettings GetSettings(ProjectItem projectItem) 40 | { 41 | if (projectItem.HasProject()) 42 | return GetSettings(projectItem.ContainingProject); 43 | else 44 | return null; 45 | } 46 | public T4MVCSettings GetSettings(ProjectItem projectItem, bool forceReload) 47 | { 48 | if (forceReload) 49 | InvalidateSettings(projectItem.ContainingProject); 50 | 51 | return GetSettings(projectItem); 52 | } 53 | 54 | public bool InvalidateSettings(Project project) 55 | { 56 | T4MVCSettings settings; 57 | 58 | return _projectT4MVCSettings.TryRemove(project, out settings); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /AutoT4MVC/VSPackage.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | AutoT4MVC 122 | 123 | 124 | An extension for Visual Studio 2012/2013 which will automatically run your T4MVC templates at build time and when you create/remove/rename/save a file that T4MVC cares about. 125 | 126 | -------------------------------------------------------------------------------- /AutoT4MVC/noun_project_2223.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bennor/AutoT4MVC/c375e47736372a7409666f1b3ce68d52ce06d584/AutoT4MVC/noun_project_2223.png -------------------------------------------------------------------------------- /AutoT4MVC/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AutoT4MVC/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | AutoT4MVC 6 | An extension for Visual Studio which automatically runs your T4MVC templates at build time and when you create/remove/rename/save a file that T4MVC cares about. 7 | http://bennor.github.io/AutoT4MVC/ 8 | LICENCE.txt 9 | https://github.com/bennor/AutoT4MVC/releases 10 | noun_project_2223.png 11 | T4MVC 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LICENCE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Bennor McCarthy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # What's this for? 2 | 3 | There used to be [a really sweet macro](http://stackoverflow.com/questions/2341717/can-you-do-a-runcustomtool-with-envdte-as-a-pre-build-event) for Visual Studio that would automatically run [T4MVC](http://t4mvc.codeplex.com) templates on build. Unfortunately, macro support has been removed from Visual Studio 2012+, so this is an extension that will do the same thing (and more). 4 | 5 | T4MVC templates are run under the following conditions (all string comparisons are case-insensitive): 6 | 7 | * a project or solution containing the template is built 8 | * a file in a "Controllers" folder is saved (in the same project) 9 | * the settings file "T4MVC.tt.settings.xml" (or "T4MVC.tt.settings.t4") is saved (in the same project) 10 | * a file is added/removed/renamed in a folder named "Assets", "Content", "Controllers", "CSS", "Images", "JS", "Scripts", "Styles" or "Views" (in the same project) 11 | 12 | Note: Drag/drop in the Solution Explorer will not trigger the templates to re-run, as the added/removed events are not fired. 13 | 14 | [Chirpy](http://chirpy.codeplex.com/) and [AutoTT](https://github.com/MartinF/Dynamo.AutoTT) do similar things, but Chirpy is overkill if all you want is your T4MVC templates built and I think AutoTT requires configuration. 15 | 16 | Just build and install the template using the VSIX file, [grab it from the Visual Studio gallery](http://visualstudiogallery.msdn.microsoft.com/8d820b76-9fc4-429f-a95f-e68ed7d3111a) or **do it the easy way** and use the 'Extension & Updates' manager in Visual Studio 2012, 2013, 2015 or 2017. --------------------------------------------------------------------------------