Skip to content

Commit b578b46

Browse files
committed
feat(samples): add SampleExtensionWithTemplates sample project
- Add sample extension demonstrating VS template support - Include project template (SampleProjectTemplate) - Include item template (SampleItemTemplate) - Fix VSSDK1079 error by removing invalid InstallRoot metadata Closes #23
1 parent 98ae93f commit b578b46

9 files changed

Lines changed: 185 additions & 35 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace $rootnamespace$;
2+
3+
/// <summary>
4+
/// Sample class created from item template.
5+
/// </summary>
6+
public class $fileinputname$
7+
{
8+
public $fileinputname$()
9+
{
10+
}
11+
12+
public void DoSomething()
13+
{
14+
// TODO: Implement your logic here
15+
}
16+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<VSTemplate Version="3.0.0" Type="Item" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
3+
<TemplateData>
4+
<Name>Sample Class</Name>
5+
<Description>A sample class item template</Description>
6+
<ProjectType>CSharp</ProjectType>
7+
<SortOrder>10</SortOrder>
8+
<DefaultName>SampleClass.cs</DefaultName>
9+
</TemplateData>
10+
<TemplateContent>
11+
<ProjectItem ReplaceParameters="true" TargetFileName="$fileinputname$.cs">SampleClass.cs</ProjectItem>
12+
</TemplateContent>
13+
</VSTemplate>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace $safeprojectname$;
2+
3+
class Program
4+
{
5+
static void Main(string[] args)
6+
{
7+
Console.WriteLine("Hello from $safeprojectname$!");
8+
}
9+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<RootNamespace>$safeprojectname$</RootNamespace>
7+
<AssemblyName>$safeprojectname$</AssemblyName>
8+
<ImplicitUsings>enable</ImplicitUsings>
9+
<Nullable>enable</Nullable>
10+
</PropertyGroup>
11+
12+
</Project>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<VSTemplate Version="3.0.0" Type="Project" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
3+
<TemplateData>
4+
<Name>Sample Console App</Name>
5+
<Description>A sample console application project template</Description>
6+
<ProjectType>CSharp</ProjectType>
7+
<SortOrder>1000</SortOrder>
8+
<DefaultName>SampleConsoleApp</DefaultName>
9+
<ProvideDefaultName>true</ProvideDefaultName>
10+
<CreateNewFolder>true</CreateNewFolder>
11+
<LocationField>Enabled</LocationField>
12+
<EnableLocationBrowseButton>true</EnableLocationBrowseButton>
13+
</TemplateData>
14+
<TemplateContent>
15+
<Project File="SampleProject.csproj" ReplaceParameters="true">
16+
<ProjectItem ReplaceParameters="true" TargetFileName="Program.cs">Class1.cs</ProjectItem>
17+
</Project>
18+
</TemplateContent>
19+
</VSTemplate>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<!--
2+
For LOCAL DEVELOPMENT, this project uses Microsoft.NET.Sdk with
3+
Directory.Build.props/targets to add VSIX SDK behavior.
4+
5+
When published, users would use:
6+
<Project Sdk="CodingWithCalvin.VsixSdk/1.0.0">
7+
-->
8+
<Project Sdk="Microsoft.NET.Sdk">
9+
10+
<PropertyGroup>
11+
<TargetFramework>net472</TargetFramework>
12+
<Version>1.0.0</Version>
13+
<RootNamespace>SampleExtensionWithTemplates</RootNamespace>
14+
<AssemblyName>SampleExtensionWithTemplates</AssemblyName>
15+
</PropertyGroup>
16+
17+
<ItemGroup>
18+
<PackageReference Include="Microsoft.VisualStudio.SDK" Version="17.*" />
19+
</ItemGroup>
20+
21+
</Project>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using System.Threading;
4+
using Microsoft.VisualStudio.Shell;
5+
using Task = System.Threading.Tasks.Task;
6+
7+
namespace SampleExtensionWithTemplates
8+
{
9+
/// <summary>
10+
/// This is the class that implements the package exposed by this assembly.
11+
/// </summary>
12+
[PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
13+
[Guid(PackageGuidString)]
14+
public sealed class SampleExtensionWithTemplatesPackage : AsyncPackage
15+
{
16+
/// <summary>
17+
/// SampleExtensionWithTemplatesPackage GUID string.
18+
/// </summary>
19+
public const string PackageGuidString = "b2c3d4e5-f6a7-8901-bcde-f23456789012";
20+
21+
/// <summary>
22+
/// Initialization of the package; this method is called right after the package is sited.
23+
/// </summary>
24+
protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)
25+
{
26+
await base.InitializeAsync(cancellationToken, progress);
27+
28+
// When initialized asynchronously, switch to the main thread before accessing VS services
29+
await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
30+
31+
// This extension provides project and item templates
32+
// Templates are automatically discovered from ProjectTemplates/ and ItemTemplates/ folders
33+
}
34+
}
35+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
3+
<Metadata>
4+
<Identity Id="SampleExtensionWithTemplates.b2c3d4e5-f6a7-8901-bcde-f23456789012" Version="1.0.0" Language="en-US" Publisher="Coding With Calvin" />
5+
<DisplayName>Sample Extension With Templates</DisplayName>
6+
<Description xml:space="preserve">A sample Visual Studio extension demonstrating template support with CodingWithCalvin.VsixSdk</Description>
7+
<MoreInfo>https://github.com/CodingWithCalvin/VsixSdk</MoreInfo>
8+
<Tags>sample, templates, vsix</Tags>
9+
</Metadata>
10+
<Installation>
11+
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.0, 19.0)">
12+
<ProductArchitecture>amd64</ProductArchitecture>
13+
</InstallationTarget>
14+
<InstallationTarget Id="Microsoft.VisualStudio.Professional" Version="[17.0, 19.0)">
15+
<ProductArchitecture>amd64</ProductArchitecture>
16+
</InstallationTarget>
17+
<InstallationTarget Id="Microsoft.VisualStudio.Enterprise" Version="[17.0, 19.0)">
18+
<ProductArchitecture>amd64</ProductArchitecture>
19+
</InstallationTarget>
20+
</Installation>
21+
<Dependencies>
22+
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="[4.7.2,)" />
23+
</Dependencies>
24+
<Prerequisites>
25+
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[17.0,19.0)" DisplayName="Visual Studio core editor" />
26+
</Prerequisites>
27+
<Assets>
28+
<Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgDefProjectOutputGroup|" />
29+
</Assets>
30+
<Content>
31+
<ProjectTemplate Path="ProjectTemplates" />
32+
<ItemTemplate Path="ItemTemplates" />
33+
</Content>
34+
</PackageManifest>

src/CodingWithCalvin.VsixSdk/Sdk/Sdk.Vsix.Templates.targets

Lines changed: 26 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,32 @@
1515
</PropertyGroup>
1616

1717
<!--
18-
Auto-discover project templates in the ProjectTemplates folder.
19-
Each subfolder containing a .vstemplate file becomes a VsixProjectTemplate item.
18+
Auto-discover project and item templates.
19+
Discovery must happen in a target because we need to compute additional metadata.
2020
-->
21-
<ItemGroup Condition="'$(EnableDefaultVsixTemplateItems)' == 'true' and '$(EnableDefaultItems)' != 'false'">
21+
<Target Name="DiscoverVsixTemplates" BeforeTargets="PrepareVsixTemplates">
2222
<!-- Find all .vstemplate files in ProjectTemplates subfolders -->
23-
<_DiscoveredProjectTemplateFiles Include="$(VsixProjectTemplatesFolder)\**\*.vstemplate"
24-
Condition="Exists('$(MSBuildProjectDirectory)\$(VsixProjectTemplatesFolder)')"
25-
Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
26-
27-
<!-- Convert to folder paths (parent of each .vstemplate) -->
28-
<VsixProjectTemplate Include="@(_DiscoveredProjectTemplateFiles->'%(RootDir)%(Directory)'->TrimEnd('\')->Distinct())"
29-
Condition="'@(_DiscoveredProjectTemplateFiles)' != ''" />
30-
</ItemGroup>
23+
<ItemGroup Condition="'$(EnableDefaultVsixTemplateItems)' == 'true' and '$(EnableDefaultItems)' != 'false'">
24+
<_DiscoveredProjectTemplateFiles Include="$(MSBuildProjectDirectory)\$(VsixProjectTemplatesFolder)\**\*.vstemplate"
25+
Condition="Exists('$(MSBuildProjectDirectory)\$(VsixProjectTemplatesFolder)')" />
26+
<_DiscoveredItemTemplateFiles Include="$(MSBuildProjectDirectory)\$(VsixItemTemplatesFolder)\**\*.vstemplate"
27+
Condition="Exists('$(MSBuildProjectDirectory)\$(VsixItemTemplatesFolder)')" />
28+
</ItemGroup>
3129

32-
<!--
33-
Auto-discover item templates in the ItemTemplates folder.
34-
Each subfolder containing a .vstemplate file becomes a VsixItemTemplate item.
35-
-->
36-
<ItemGroup Condition="'$(EnableDefaultVsixTemplateItems)' == 'true' and '$(EnableDefaultItems)' != 'false'">
37-
<!-- Find all .vstemplate files in ItemTemplates subfolders -->
38-
<_DiscoveredItemTemplateFiles Include="$(VsixItemTemplatesFolder)\**\*.vstemplate"
39-
Condition="Exists('$(MSBuildProjectDirectory)\$(VsixItemTemplatesFolder)')"
40-
Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
30+
<!-- Create VsixProjectTemplate items - use the parent directory of the .vstemplate file -->
31+
<ItemGroup Condition="'@(_DiscoveredProjectTemplateFiles)' != ''">
32+
<VsixProjectTemplate Include="@(_DiscoveredProjectTemplateFiles->'%(RootDir)%(Directory)')">
33+
<!-- Compute folder name from .vstemplate filename by getting its parent folder -->
34+
<_TemplateFolderName>%(_DiscoveredProjectTemplateFiles.Filename)</_TemplateFolderName>
35+
</VsixProjectTemplate>
36+
</ItemGroup>
4137

42-
<!-- Convert to folder paths (parent of each .vstemplate) -->
43-
<VsixItemTemplate Include="@(_DiscoveredItemTemplateFiles->'%(RootDir)%(Directory)'->TrimEnd('\')->Distinct())"
44-
Condition="'@(_DiscoveredItemTemplateFiles)' != ''" />
45-
</ItemGroup>
38+
<ItemGroup Condition="'@(_DiscoveredItemTemplateFiles)' != ''">
39+
<VsixItemTemplate Include="@(_DiscoveredItemTemplateFiles->'%(RootDir)%(Directory)')">
40+
<_TemplateFolderName>%(_DiscoveredItemTemplateFiles.Filename)</_TemplateFolderName>
41+
</VsixItemTemplate>
42+
</ItemGroup>
43+
</Target>
4644

4745
<!--
4846
Exclude template source files from being included as Content in the VSIX.
@@ -57,18 +55,17 @@
5755
Target: PrepareVsixTemplates
5856
Prepares template items for zipping by computing output paths.
5957
-->
60-
<Target Name="PrepareVsixTemplates" BeforeTargets="ZipVsixTemplates">
58+
<Target Name="PrepareVsixTemplates" BeforeTargets="ZipVsixTemplates" DependsOnTargets="DiscoverVsixTemplates">
6159
<ItemGroup>
62-
<!-- Compute zip file name from folder name for project templates -->
60+
<!-- Compute zip file name and output path for project templates -->
61+
<!-- _TemplateFolderName was set during discovery from the .vstemplate filename -->
6362
<VsixProjectTemplate>
64-
<_TemplateFolderName>$([System.IO.Path]::GetFileName('%(Identity)'))</_TemplateFolderName>
6563
<_ZipFileName>%(VsixProjectTemplate._TemplateFolderName).zip</_ZipFileName>
6664
<_ZipOutputPath>$(_VsixTemplateIntermediateOutputPath)ProjectTemplates\%(VsixProjectTemplate.TargetSubPath)</_ZipOutputPath>
6765
</VsixProjectTemplate>
6866

69-
<!-- Compute zip file name from folder name for item templates -->
67+
<!-- Compute zip file name and output path for item templates -->
7068
<VsixItemTemplate>
71-
<_TemplateFolderName>$([System.IO.Path]::GetFileName('%(Identity)'))</_TemplateFolderName>
7269
<_ZipFileName>%(VsixItemTemplate._TemplateFolderName).zip</_ZipFileName>
7370
<_ZipOutputPath>$(_VsixTemplateIntermediateOutputPath)ItemTemplates\%(VsixItemTemplate.TargetSubPath)</_ZipOutputPath>
7471
</VsixItemTemplate>
@@ -146,47 +143,41 @@
146143
Condition="'@(VsixProjectTemplate)' != ''">
147144
<VSIXSubPath>ProjectTemplates\%(VsixProjectTemplate.TargetSubPath)</VSIXSubPath>
148145
<Ngen>false</Ngen>
149-
<InstallRoot>ProjectTemplates</InstallRoot>
150146
</VSIXSourceItem>
151147

152148
<!-- Add zipped item templates -->
153149
<VSIXSourceItem Include="%(VsixItemTemplate._ZipOutputPath)%(VsixItemTemplate._ZipFileName)"
154150
Condition="'@(VsixItemTemplate)' != ''">
155151
<VSIXSubPath>ItemTemplates\%(VsixItemTemplate.TargetSubPath)</VSIXSubPath>
156152
<Ngen>false</Ngen>
157-
<InstallRoot>ItemTemplates</InstallRoot>
158153
</VSIXSourceItem>
159154

160155
<!-- Add pre-built template zips (project templates) -->
161156
<VSIXSourceItem Include="%(VsixTemplateZip.Identity)"
162157
Condition="'@(VsixTemplateZip)' != '' and '%(VsixTemplateZip.TemplateType)' == 'Project'">
163158
<VSIXSubPath>ProjectTemplates\%(VsixTemplateZip.TargetSubPath)</VSIXSubPath>
164159
<Ngen>false</Ngen>
165-
<InstallRoot>ProjectTemplates</InstallRoot>
166160
</VSIXSourceItem>
167161

168162
<!-- Add pre-built template zips (item templates) -->
169163
<VSIXSourceItem Include="%(VsixTemplateZip.Identity)"
170164
Condition="'@(VsixTemplateZip)' != '' and '%(VsixTemplateZip.TemplateType)' == 'Item'">
171165
<VSIXSubPath>ItemTemplates\%(VsixTemplateZip.TargetSubPath)</VSIXSubPath>
172166
<Ngen>false</Ngen>
173-
<InstallRoot>ItemTemplates</InstallRoot>
174167
</VSIXSourceItem>
175168

176169
<!-- Add template references (project templates) -->
177170
<VSIXSourceItem Include="%(VsixTemplateReference._ZipOutputPath)%(VsixTemplateReference._ZipFileName)"
178171
Condition="'@(VsixTemplateReference)' != '' and '%(VsixTemplateReference.TemplateType)' == 'Project'">
179172
<VSIXSubPath>ProjectTemplates\%(VsixTemplateReference.TargetSubPath)</VSIXSubPath>
180173
<Ngen>false</Ngen>
181-
<InstallRoot>ProjectTemplates</InstallRoot>
182174
</VSIXSourceItem>
183175

184176
<!-- Add template references (item templates) -->
185177
<VSIXSourceItem Include="%(VsixTemplateReference._ZipOutputPath)%(VsixTemplateReference._ZipFileName)"
186178
Condition="'@(VsixTemplateReference)' != '' and '%(VsixTemplateReference.TemplateType)' == 'Item'">
187179
<VSIXSubPath>ItemTemplates\%(VsixTemplateReference.TargetSubPath)</VSIXSubPath>
188180
<Ngen>false</Ngen>
189-
<InstallRoot>ItemTemplates</InstallRoot>
190181
</VSIXSourceItem>
191182
</ItemGroup>
192183
</Target>

0 commit comments

Comments
 (0)