├── .gitattributes ├── .github └── workflows │ ├── activation.yml │ └── main.yml ├── .gitignore ├── .releaserc.json ├── .unitypackageignore ├── CHANGELOG.md ├── CHANGELOG.md.meta ├── Documentation~ ├── favicon.ico ├── header.png ├── index.md ├── logo.svg ├── manual │ ├── contributing.md │ ├── data-binding.md │ ├── getting-started.md │ └── toc.yml ├── scripts │ ├── file-utils.patch │ ├── generate-docs.ps1 │ ├── generate-docs.sh │ ├── lib-visibility.patch │ └── update-engine.ps1 └── toc.yml ├── Editor.meta ├── Editor ├── EditorExtensions.cs ├── EditorExtensions.cs.meta ├── EditorUtils.cs ├── EditorUtils.cs.meta ├── FasterGames.T4.Editor.asmdef ├── FasterGames.T4.Editor.asmdef.meta ├── ImporterVersion.cs ├── ImporterVersion.cs.meta ├── ReflectionUtils.cs ├── ReflectionUtils.cs.meta ├── TextTemplateImporter.cs ├── TextTemplateImporter.cs.meta ├── TextTemplateImporterEditor.cs ├── TextTemplateImporterEditor.cs.meta ├── TextTemplateIncludeImporter.cs ├── TextTemplateIncludeImporter.cs.meta ├── TextTemplating.meta ├── TextTemplating │ ├── Microsoft.VisualStudio.TextTemplating.meta │ ├── Microsoft.VisualStudio.TextTemplating │ │ ├── DirectiveProcessor.cs │ │ ├── DirectiveProcessor.cs.meta │ │ ├── DirectiveProcessorException.cs │ │ ├── DirectiveProcessorException.cs.meta │ │ ├── EncodingHelper.cs │ │ ├── EncodingHelper.cs.meta │ │ ├── Engine.cs │ │ ├── Engine.cs.meta │ │ ├── Interfaces.cs │ │ ├── Interfaces.cs.meta │ │ ├── ParameterDirectiveProcessor.cs │ │ ├── ParameterDirectiveProcessor.cs.meta │ │ ├── RequiresProvidesDirectiveProcessor.cs │ │ ├── RequiresProvidesDirectiveProcessor.cs.meta │ │ ├── TextTemplatingSession.cs │ │ ├── TextTemplatingSession.cs.meta │ │ ├── TextTransformation.cs │ │ ├── TextTransformation.cs.meta │ │ ├── ToStringHelper.cs │ │ └── ToStringHelper.cs.meta │ ├── Mono.TextTemplating.CodeCompilation.meta │ ├── Mono.TextTemplating.CodeCompilation │ │ ├── CodeCompiler.cs │ │ ├── CodeCompiler.cs.meta │ │ ├── CodeCompilerArguments.cs │ │ ├── CodeCompilerArguments.cs.meta │ │ ├── CodeCompilerResult.cs │ │ ├── CodeCompilerResult.cs.meta │ │ ├── CscCodeCompiler.cs │ │ ├── CscCodeCompiler.cs.meta │ │ ├── MSBuildErrorParser.cs │ │ ├── MSBuildErrorParser.cs.meta │ │ ├── ProcessUtils.cs │ │ ├── ProcessUtils.cs.meta │ │ ├── RuntimeInfo.cs │ │ └── RuntimeInfo.cs.meta │ ├── Mono.TextTemplating.meta │ └── Mono.TextTemplating │ │ ├── CompiledTemplate.cs │ │ ├── CompiledTemplate.cs.meta │ │ ├── CrossAppDomainAssemblyResolver.cs │ │ ├── CrossAppDomainAssemblyResolver.cs.meta │ │ ├── FileUtil.cs │ │ ├── FileUtil.cs.meta │ │ ├── ParsedTemplate.cs │ │ ├── ParsedTemplate.cs.meta │ │ ├── RecyclableAppDomain.cs │ │ ├── RecyclableAppDomain.cs.meta │ │ ├── StringUtil.cs │ │ ├── StringUtil.cs.meta │ │ ├── TemplateGenerator.cs │ │ ├── TemplateGenerator.cs.meta │ │ ├── TemplateSettings.cs │ │ ├── TemplateSettings.cs.meta │ │ ├── TemplatingEngine.cs │ │ ├── TemplatingEngine.cs.meta │ │ ├── Tokeniser.cs │ │ ├── Tokeniser.cs.meta │ │ ├── Utf8.cs │ │ └── Utf8.cs.meta ├── UnityDataHost.cs └── UnityDataHost.cs.meta ├── LICENSE.md ├── LICENSE.md.meta ├── README.md ├── README.md.meta ├── Runtime.meta ├── Runtime ├── FasterGames.T4.Runtime.asmdef ├── FasterGames.T4.Runtime.asmdef.meta ├── IDataHost.cs └── IDataHost.cs.meta ├── Samples~ └── .gitkeep ├── Tests.meta ├── Tests ├── Editor.meta └── Editor │ ├── EditorTestRuntime.meta │ ├── EditorTestRuntime │ ├── Data.cs │ ├── Data.cs.meta │ ├── FasterGames.T4.Editor.Tests.EditorTestRuntime.asmdef │ └── FasterGames.T4.Editor.Tests.EditorTestRuntime.asmdef.meta │ ├── Example.cs │ ├── Example.cs.meta │ ├── Example.tt │ ├── Example.tt.meta │ ├── FasterGames.T4.Editor.Tests.asmdef │ ├── FasterGames.T4.Editor.Tests.asmdef.meta │ ├── TextTemplating.meta │ ├── TextTemplating │ ├── DummyHost.cs │ ├── DummyHost.cs.meta │ ├── EngineTests.cs │ ├── EngineTests.cs.meta │ ├── GenerateIndentedClassCodeTests.cs │ ├── GenerateIndentedClassCodeTests.cs.meta │ ├── GenerationTests.cs │ ├── GenerationTests.cs.meta │ ├── ParsingTests.cs │ ├── ParsingTests.cs.meta │ ├── TemplateEnginePreprocessTemplateTests.cs │ ├── TemplateEnginePreprocessTemplateTests.cs.meta │ ├── TemplatingEngineHelper.cs │ ├── TemplatingEngineHelper.cs.meta │ ├── TextTemplatingSessionTests.cs │ └── TextTemplatingSessionTests.cs.meta │ ├── exampleData.asset │ └── exampleData.asset.meta ├── Third Party Notices.md ├── Third Party Notices.md.meta ├── docfx.json ├── docfx.json.meta ├── package.json └── package.json.meta /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | *.anim merge=unityyamlmerge eol=lf 3 | *.asset merge=unityyamlmerge eol=lf 4 | *.controller merge=unityyamlmerge eol=lf 5 | *.mat merge=unityyamlmerge eol=lf 6 | *.meta merge=unityyamlmerge eol=lf 7 | *.physicsMaterial merge=unityyamlmerge eol=lf 8 | *.physicsMaterial2D merge=unityyamlmerge eol=lf 9 | *.prefab merge=unityyamlmerge eol=lf 10 | *.unity merge=unityyamlmerge eol=lf 11 | -------------------------------------------------------------------------------- /.github/workflows/activation.yml: -------------------------------------------------------------------------------- 1 | name: Acquire activation file 2 | on: 3 | workflow_dispatch: {} 4 | jobs: 5 | activation: 6 | name: Request manual activation file 🔑 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | 11 | - name: get unityVersion 12 | id: unityVersion 13 | uses: notiz-dev/github-action-json-property@release 14 | with: 15 | path: 'package.json' 16 | prop_path: 'unity' 17 | 18 | - name: get unityReleaseVersion 19 | id: unityReleaseVersion 20 | uses: notiz-dev/github-action-json-property@release 21 | with: 22 | path: 'package.json' 23 | prop_path: 'unityRelease' 24 | 25 | - name: Request manual activation file 26 | id: getManualLicenseFile 27 | uses: game-ci/unity-request-activation-file@v2 28 | with: 29 | unityVersion: ${{steps.unityVersion.outputs.prop}}.${{steps.unityReleaseVersion.outputs.prop}} 30 | 31 | # Upload artifact (Unity_v20XX.X.XXXX.alf) 32 | - name: Expose as artifact 33 | uses: actions/upload-artifact@v2 34 | with: 35 | name: ${{ steps.getManualLicenseFile.outputs.filePath }} 36 | path: ${{ steps.getManualLicenseFile.outputs.filePath }} 37 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | # Triggers the workflow on push or pull request events but only for the main branch 5 | push: 6 | branches: [ main ] 7 | pull_request: 8 | branches: [ main ] 9 | 10 | # Allows you to run this workflow manually from the Actions tab 11 | workflow_dispatch: 12 | 13 | jobs: 14 | # Tests 15 | testAllModes: 16 | name: Test in ${{ matrix.testMode }} 17 | runs-on: ubuntu-latest 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | testMode: 22 | - playmode 23 | - editmode 24 | steps: 25 | - uses: actions/checkout@v2 26 | with: 27 | repository: faster-games/package-testbed 28 | - uses: actions/checkout@v2 29 | with: 30 | path: Packages/com.faster-games.t4 31 | - uses: actions/cache@v2 32 | with: 33 | path: Library 34 | key: Library-TestPlatform 35 | restore-keys: | 36 | Library- 37 | - uses: game-ci/unity-test-runner@v2 38 | id: tests 39 | env: 40 | UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} 41 | with: 42 | projectPath: ./ 43 | testMode: ${{ matrix.testMode }} 44 | artifactsPath: ${{ matrix.testMode }}-artifacts 45 | githubToken: ${{ secrets.GITHUB_TOKEN }} 46 | checkName: ${{ matrix.testMode }} Test Results 47 | release: 48 | name: Release 49 | needs: [testAllModes] 50 | if: ${{ github.ref == 'refs/heads/main' }} 51 | runs-on: ubuntu-latest 52 | steps: 53 | - uses: actions/checkout@v2 54 | - name: Create dist directory 55 | run: mkdir dist/ 56 | - uses: actions/checkout@v2 57 | with: 58 | repository: faster-games/UnityFX 59 | path: dist/.unityfx 60 | - name: Install semantic-release plugins 61 | run: npm i --no-save @semantic-release/git @semantic-release/changelog 62 | - name: Export .unitypackage 63 | uses: bengreenier-actions/Unity-Package-Exporter@v1.0.0 64 | with: 65 | packagePath: ./ 66 | outputPackagePath: dist/com.faster-games.t4.unitypackage 67 | - uses: bengreenier-actions/docfx-action@v1.0.0 68 | name: Build docs 69 | with: 70 | args: ./docfx.json 71 | - name: Deploy to GitHub Pages 72 | uses: Cecilapp/GitHub-Pages-deploy@v3 73 | env: 74 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 75 | with: 76 | email: ben@bengreenier.com 77 | build_dir: dist/docs 78 | cname: t4.faster-games.com 79 | jekyll: no 80 | - name: Publish Release 81 | uses: codfish/semantic-release-action@v1 82 | env: 83 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 84 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | 13 | # Asset meta data should only be ignored when the corresponding asset is also ignored 14 | !/[Aa]ssets/**/*.meta 15 | 16 | # Uncomment this line if you wish to ignore the asset store tools plugin 17 | # /[Aa]ssets/AssetStoreTools* 18 | 19 | # Autogenerated Jetbrains Rider plugin 20 | [Aa]ssets/Plugins/Editor/JetBrains* 21 | 22 | # Visual Studio cache directory 23 | .vs/ 24 | 25 | # Gradle cache directory 26 | .gradle/ 27 | 28 | # Autogenerated VS/MD/Consulo solution and project files 29 | ExportedObj/ 30 | .consulo/ 31 | *.csproj 32 | *.unityproj 33 | *.sln 34 | *.suo 35 | *.tmp 36 | *.user 37 | *.userprefs 38 | *.pidb 39 | *.booproj 40 | *.svd 41 | *.pdb 42 | *.mdb 43 | *.opendb 44 | *.VC.db 45 | 46 | # Unity3D generated meta files 47 | *.pidb.meta 48 | *.pdb.meta 49 | *.mdb.meta 50 | 51 | # Unity3D generated file on crash reports 52 | sysinfo.txt 53 | 54 | # Builds 55 | *.apk 56 | *.unitypackage 57 | 58 | # Crashlytics generated file 59 | crashlytics-build.properties 60 | 61 | # docfx 62 | /**/DROP/ 63 | /**/TEMP/ 64 | /**/packages/ 65 | /**/bin/ 66 | /**/obj/ 67 | _site 68 | 69 | # general dist 70 | dist/ 71 | dist.meta 72 | -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "branches": ["main"], 3 | "plugins": [ 4 | ["@semantic-release/commit-analyzer"], 5 | ["@semantic-release/release-notes-generator"], 6 | ["@semantic-release/changelog"], 7 | [ 8 | "@semantic-release/npm", 9 | { 10 | "npmPublish": false 11 | } 12 | ], 13 | [ 14 | "@semantic-release/git", 15 | { 16 | "assets": ["package.json", "CHANGELOG.md", "!**/*.unitypackage"], 17 | "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 18 | } 19 | ], 20 | [ 21 | "@semantic-release/github", 22 | { 23 | "assets": [ 24 | { 25 | "path": "dist/com.faster-games.t4.unitypackage", 26 | "name": "com.faster-games.t4-${nextRelease.gitTag}.unitypackage", 27 | "label": "FasterGames.T4 ${nextRelease.gitTag}" 28 | } 29 | ] 30 | } 31 | ] 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /.unitypackageignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .github/ 3 | dist/ 4 | Documentation~/ 5 | node_modules/ 6 | .gitignore 7 | .gitattributes 8 | .releaserc.json 9 | docfx.json 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.4.1](https://github.com/faster-games/t4/compare/v1.4.0...v1.4.1) (2021-07-22) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * **misc:** Embedded data namespaces, tests 🐛 ([#8](https://github.com/faster-games/t4/issues/8)) ([742d625](https://github.com/faster-games/t4/commit/742d6256dfe0f45eee67a433c6b860639e1f1873)), closes [#6](https://github.com/faster-games/t4/issues/6) [#7](https://github.com/faster-games/t4/issues/7) 7 | 8 | # [1.4.0](https://github.com/faster-games/t4/compare/v1.3.2...v1.4.0) (2021-07-22) 9 | 10 | 11 | ### Features 12 | 13 | * **data-binding:** Add data binding support 🧬 ([#5](https://github.com/faster-games/t4/issues/5)) ([e94bd96](https://github.com/faster-games/t4/commit/e94bd9623f8ed521ffcc92ee8acc453efc1669c4)) 14 | 15 | ## [1.3.2](https://github.com/faster-games/t4/compare/v1.3.1...v1.3.2) (2021-07-20) 16 | 17 | 18 | ### Bug Fixes 19 | 20 | * **docs:** Update index page 📖 ([ff5613e](https://github.com/faster-games/t4/commit/ff5613eebb0da3fb79ad8beb093774d5a94a1816)) 21 | 22 | ## [1.3.1](https://github.com/faster-games/t4/compare/v1.3.0...v1.3.1) (2021-07-19) 23 | 24 | 25 | ### Bug Fixes 26 | 27 | * **typo:** Replace readme typo 😅 ([dd1bb44](https://github.com/faster-games/t4/commit/dd1bb441b2bfb049b82094b6164431fa96815842)) 28 | 29 | # [1.3.0](https://github.com/faster-games/t4/compare/v1.2.1...v1.3.0) (2021-07-19) 30 | 31 | 32 | ### Features 33 | 34 | * **docs:** Improve readme 📝 ([a5248fb](https://github.com/faster-games/t4/commit/a5248fba4f454a7fc20f5f2f3c9921e68cc44301)) 35 | 36 | ## [1.2.1](https://github.com/faster-games/t4/compare/v1.2.0...v1.2.1) (2021-07-19) 37 | 38 | 39 | ### Bug Fixes 40 | 41 | * **docs:** Redirecting link to editor docs 📝 ([833e3bc](https://github.com/faster-games/t4/commit/833e3bc8d723381dbf8fe012603878d6ab4c08b4)) 42 | 43 | # [1.2.0](https://github.com/faster-games/t4/compare/v1.1.0...v1.2.0) (2021-07-19) 44 | 45 | 46 | ### Bug Fixes 47 | 48 | * **docs:** fix example typo 🐛 ([#4](https://github.com/faster-games/t4/issues/4)) ([0051ae6](https://github.com/faster-games/t4/commit/0051ae6d7bb2e300a40d85336c3e62adad8a2433)) 49 | 50 | 51 | ### Features 52 | 53 | * **mono-t4:** Add generation support 🚀 ([#3](https://github.com/faster-games/t4/issues/3)) ([612fbb0](https://github.com/faster-games/t4/commit/612fbb0dfe7e9828a62ee53e819e67a0fac4ea10)) 54 | 55 | # [1.1.0](https://github.com/faster-games/t4/compare/v1.0.1...v1.1.0) (2021-07-19) 56 | 57 | 58 | ### Features 59 | 60 | * **dev-docs:** Update dev docs 📝 ([#2](https://github.com/faster-games/t4/issues/2)) ([9f1c588](https://github.com/faster-games/t4/commit/9f1c5887110e9c8e4efab655473f2a442e53a458)) 61 | 62 | ## [1.0.1](https://github.com/faster-games/t4/compare/v1.0.0...v1.0.1) (2021-07-19) 63 | 64 | 65 | ### Bug Fixes 66 | 67 | * **header:** Update header images 🎨 ([1a23378](https://github.com/faster-games/t4/commit/1a23378e6243e9ad5c81595228b4c301108b4e99)) 68 | 69 | # 1.0.0 (2021-07-19) 70 | 71 | 72 | ### Bug Fixes 73 | 74 | * **activation:** Add temp push trigger 🐛 ([9359e67](https://github.com/faster-games/t4/commit/9359e67083794c36c09f0fbd6830165551a39efe)) 75 | * **activation:** Re-add activation workflow 🎛 ([#1](https://github.com/faster-games/t4/issues/1)) ([66331ab](https://github.com/faster-games/t4/commit/66331abd742a63850ccb0280c3a8ab43d81468d4)) 76 | * **activation:** Remove push trigger ⚡ ([5b65f80](https://github.com/faster-games/t4/commit/5b65f80f43220fc7b035582998ee5c0d83f958fd)) 77 | * **meta:** Add initial meta files 🎟 ([43555ad](https://github.com/faster-games/t4/commit/43555ad10d548f8ee212aa2c2148bf995ba032cc)) 78 | 79 | 80 | ### Features 81 | 82 | * **init:** Create from package-template 🧩 ([c423d5d](https://github.com/faster-games/t4/commit/c423d5de6c219aac39263bc50fc59062e474df5e)) 83 | -------------------------------------------------------------------------------- /CHANGELOG.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 08e8a0aba2c5035419359f6a40e5361c 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Documentation~/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faster-games/t4/954234411b76686e106e8da305fbd85d69a31cc9/Documentation~/favicon.ico -------------------------------------------------------------------------------- /Documentation~/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faster-games/t4/954234411b76686e106e8da305fbd85d69a31cc9/Documentation~/header.png -------------------------------------------------------------------------------- /Documentation~/index.md: -------------------------------------------------------------------------------- 1 | # t4 2 | 3 | T4 text template generative importer for Unity3D. [View On GitHub](https://github.com/faster-games/t4) 📝🏗 4 | 5 | Project logo; A pink package on a grey background, next to the text "T4 Templating" in purple 6 | 7 | ![GitHub package.json version](https://img.shields.io/github/package-json/v/faster-games/t4) 8 | [![openupm](https://img.shields.io/npm/v/com.faster-games.t4?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/com.faster-games.t4/) 9 | [![CI](https://github.com/faster-games/t4/actions/workflows/main.yml/badge.svg)](https://github.com/faster-games/t4/actions/workflows/main.yml) 10 | [![Discord](https://img.shields.io/discord/862006447919726604)](https://discord.gg/QfQE6rWQqq) 11 | 12 | [T4 Text Templates](https://docs.microsoft.com/en-us/visualstudio/modeling/code-generation-and-t4-text-templates) provide a way to generate csharp code from templates, which are a mixture of text blocks and control logic. If you've ever used [Mushtache](http://mustache.github.io/mustache.5.html) or [Go's html/template](https://gowebexamples.com/templates/), T4 templates are pretty similar. This package allows [Unity](http://unity3d.com/) developers to author T4 templates (`.tt` files), and rely on the [Editor](https://docs.unity3d.com/Manual/UsingTheEditor.html) to process them and generate code. 13 | 14 | ## Installing 15 | 16 | This package supports [openupm](https://openupm.com/packages/com.faster-games.t4/) - you can install it using the following command: 17 | 18 | ``` 19 | openupm add com.faster-games.t4 20 | ``` 21 | 22 | Or by adding directly to your `manifest.json`: 23 | 24 | > Note: You may also use specific versions by appending `#{version}` where version is a [Release tag](https://github.com/faster-games/t4/releases) - e.g. `#v1.2.0`. 25 | 26 | ``` 27 | dependencies: { 28 | ... 29 | "com.faster-games.t4": "git+https://github.com/faster-games/t4.git" 30 | } 31 | ``` 32 | 33 | Or by using [Package Manager](https://docs.unity3d.com/Manual/upm-ui-giturl.html) to "Add a package from Git URL", using the following url: 34 | 35 | ``` 36 | https://github.com/faster-games/t4.git 37 | ``` 38 | 39 | ## Documentation 40 | 41 | - [Manual 📖](https://t4.faster-games.com/manual/getting-started.html) 42 | - [Scripting API 🔎](https://t4.faster-games.com/ref/FasterGames.T4.Editor.html) 43 | 44 | Please also see these resources from Microsoft, as they are the authors and maintainers of the `T4` templating featureset and format: 45 | 46 | - [MS Docs: Code Generation and T4 Text Templates](https://docs.microsoft.com/en-us/visualstudio/modeling/code-generation-and-t4-text-templates) 47 | - [MS Docs: Design Time Templates](https://docs.microsoft.com/en-us/visualstudio/modeling/design-time-code-generation-by-using-t4-text-templates) 48 | 49 | ### Quickstart 50 | 51 | - Add a `.tt` file under `Assets` 52 | - Select it in the [Project window](https://docs.unity3d.com/Manual/ProjectView.html) 53 | - Note that the importer used is `TextTemplateImporter` - that's us! 54 | - Any processing errors will be shown in the [Console](https://docs.unity3d.com/Manual/Console.html) 55 | 56 | ## Supporting the project 57 | 58 | If this project saved you some time, and you'd like to see it continue to be invested in, consider [buying me a coffee. ☕](https://www.buymeacoffee.com/bengreenier) I do this full-time, and every little bit helps! 💙 59 | -------------------------------------------------------------------------------- /Documentation~/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Documentation~/manual/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | To contribute to `faster-games/t4` here are some things you'll want to know: 4 | 5 | + `Documentation~\scripts\update-engine.ps1` can be used to pull `mono/t4` updates 6 | + `Documentation~\scripts\generate-docs.ps1` can be used to re-generate `docfx` docs 7 | + Min-supported Unity version is documented in `package.json` 8 | + `.gitattributes` should force `LF` endings 9 | 10 | Other than that, we use a normal fork and PR process to contribute! Feel free to send a PR, or open an Issue to discuss approaches. 11 | -------------------------------------------------------------------------------- /Documentation~/manual/data-binding.md: -------------------------------------------------------------------------------- 1 | # Data Binding 2 | 3 | > Note: This is a `Beta` feature, and is being actively developed. To use this feature, you need [`importerVersion`](xref:FasterGames.T4.Editor.TextTemplateImporter.importerVersion) to be set to [`Beta`](xref:FasterGames.T4.Editor.ImporterVersion.Beta). 4 | 5 | Data binding allows sharing data from Unity with a template. This allows the template to access and use that data during generation. 6 | 7 | ## Getting started 8 | 9 | 10 | - Create a class to represent the data you wish to embed: 11 | ``` 12 | [CreateAssetMenu(menuName = "EmbedData")] 13 | public class EmbedData : ScriptableObject 14 | { 15 | public List Animals; 16 | } 17 | ``` 18 | - Create an instance of this data in the Editor [Project window](https://docs.unity3d.com/Manual/ProjectView.html) (Right click -> Create -> EmbedData) 19 | - Create a TT file to use this data: 20 | ``` 21 | <#@ template debug="false" hostspecific="true" language="C#" #> 22 | <#@ output extension=".cs" #> 23 | <#@ import namespace="System.IO" #> 24 | using System; 25 | 26 | <# 27 | foreach (var animal in Host.Data.Animals) 28 | { 29 | #> 30 | 31 | [Serializable] 32 | public class <#= animal#>Test {} 33 | 34 | <# 35 | } 36 | #> 37 | ``` 38 | - Select the TT file in the [Project window](https://docs.unity3d.com/Manual/ProjectView.html) 39 | - In the [Inspector](https://docs.unity3d.com/Manual/UsingTheInspector.html) ensure [`importerVersion`](xref:FasterGames.T4.Editor.TextTemplateImporter.importerVersion) is set to [`Beta`](xref:FasterGames.T4.Editor.ImporterVersion.Beta) 40 | - Drag the data instance you created in the [Project window](https://docs.unity3d.com/Manual/ProjectView.html) to the [`embeddedData`](xref:FasterGames.T4.Editor.TextTemplateImporter.embeddedData) section in the [Inspector](https://docs.unity3d.com/Manual/UsingTheInspector.html) 41 | - Select "Apply" 42 | 43 | This will cause the template to be run such that `Host.Data` is the instance of your data. 44 | 45 | ## Troubleshooting 46 | 47 | ### Does the template need to be host specific? 48 | 49 | Yes - to inform the template engine to use the host with our data, [`hostspecific`](https://docs.microsoft.com/en-us/visualstudio/modeling/t4-template-directive?view=vs-2019#hostspecific-attribute) must be set to `true`. 50 | 51 | For instance: 52 | ``` 53 | <#@ template debug="false" hostspecific="true" language="C#" #> 54 | ``` 55 | 56 | ### Why does my template break when embeddedData is enabled? 57 | 58 | If your template fails to generate content after embedding data, this may be because the data class you're using is complex, and references other types that the template environment is not aware of. Usually if this is the case, the error will inform you of what type is missing. You may specify this type in [`additionalTypes`](xref:FasterGames.T4.Editor.TextTemplateImporter.additionalTypes) list, or simplify your data class. 59 | 60 | If you're not able to get it working, please [open an Issue](https://github.com/faster-games/t4/issues/new). 61 | 62 | ### Why does my template break on first import? 63 | 64 | If your data class and your codegen classes are in the same assembly (asmdef folder), on first import you may experience an error indicating the `UnityEngine.Object` does not have required properties. This is because Unity wasn't able to generate the assembly with your data class before attempting the import - as such, your embedded data structure is missing. 65 | 66 | The quickest solution is to move your data class to it's own assembly: 67 | - Create a new folder 68 | - Create an Assembly Definition in that folder 69 | - Move the data class to this new folder 70 | - Add a reference to this new assembly in the codegen assembly 71 | -------------------------------------------------------------------------------- /Documentation~/manual/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | Some tips and tricks on how to begin using T4 Templating. 4 | 5 | ## Official Docs 6 | 7 | - [MS Docs: Code Generation and T4 Text Templates](https://docs.microsoft.com/en-us/visualstudio/modeling/code-generation-and-t4-text-templates) 8 | - [MS Docs: Design Time Templates](https://docs.microsoft.com/en-us/visualstudio/modeling/design-time-code-generation-by-using-t4-text-templates) 9 | 10 | ## Quick Examples 11 | 12 | ### Generate UnityEvent classes 13 | 14 | Sometimes you may want to have many [UnityEvents](https://docs.unity3d.com/Manual/UnityEvents.html) with various typed parameters. Using a Text Template, you can quickly generate these classes: 15 | 16 | ```cs 17 | <#@ template language="C#" #> 18 | <#@ import namespace="System.Text" #> 19 | <#@ import namespace="System.Collections.Generic" #> 20 | 21 | using System; 22 | using UnityEngine; 23 | using UnityEngine.Events; 24 | 25 | namespace Events 26 | { 27 | 28 | <# 29 | foreach (var type in new string[] {"Vector2", "Vector3"}) 30 | { 31 | #> 32 | [Serializable] 33 | public class <#= type #>Event : UnityEvent<<#= type #>> {} 34 | 35 | <# 36 | } 37 | #> 38 | 39 | } 40 | ``` 41 | 42 | We embed a `foreach` loop that walks a list of type names (as strings). For each type, we create a class named `{Type}Event`, that inherits from `UnityEvent<{Type}>`. Here's the output: 43 | 44 | ```cs 45 | 46 | using System; 47 | using UnityEngine; 48 | using UnityEngine.Events; 49 | 50 | namespace Events 51 | { 52 | [Serializable] 53 | public class Vector2Event : UnityEvent {} 54 | 55 | [Serializable] 56 | public class Vector3Event : UnityEvent {} 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /Documentation~/manual/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Getting Started 2 | href: getting-started.md 3 | - name: Data Binding 4 | href: data-binding.md 5 | - name: Contributing 6 | href: contributing.md 7 | -------------------------------------------------------------------------------- /Documentation~/scripts/file-utils.patch: -------------------------------------------------------------------------------- 1 | From fc256ed9990469023e1859653077f804ce007a1e Mon Sep 17 00:00:00 2001 2 | From: Ben Greenier 3 | Date: Mon, 19 Jul 2021 12:20:21 -0700 4 | Subject: [PATCH] patch file 5 | 6 | --- 7 | .../Mono.TextTemplating/FileUtil.cs | 77 +------------------ 8 | 1 file changed, 4 insertions(+), 73 deletions(-) 9 | 10 | diff --git a/Editor/TextTemplating/Mono.TextTemplating/FileUtil.cs b/Editor/TextTemplating/Mono.TextTemplating/FileUtil.cs 11 | index 866b903..1222681 100644 12 | --- a/Editor/TextTemplating/Mono.TextTemplating/FileUtil.cs 13 | +++ b/Editor/TextTemplating/Mono.TextTemplating/FileUtil.cs 14 | @@ -31,80 +31,11 @@ namespace Mono.TextTemplating 15 | static class FileUtil 16 | { 17 | //from MonoDevelop.Core.FileService, copied here so Mono.TextTemplating can be used w/o MD dependency 18 | - public unsafe static string AbsoluteToRelativePath (string baseDirectoryPath, string absPath) 19 | + public static string AbsoluteToRelativePath (string baseDirectoryPath, string absPath) 20 | { 21 | - if (!Path.IsPathRooted (absPath) || string.IsNullOrEmpty (baseDirectoryPath)) 22 | - return absPath; 23 | - 24 | - absPath = GetFullPath (absPath); 25 | - baseDirectoryPath = GetFullPath (baseDirectoryPath).TrimEnd (Path.DirectorySeparatorChar); 26 | - 27 | - fixed (char* bPtr = baseDirectoryPath, aPtr = absPath) { 28 | - var bEnd = bPtr + baseDirectoryPath.Length; 29 | - var aEnd = aPtr + absPath.Length; 30 | - char* lastStartA = aEnd; 31 | - char* lastStartB = bEnd; 32 | - 33 | - int indx = 0; 34 | - // search common base path 35 | - var a = aPtr; 36 | - var b = bPtr; 37 | - while (a < aEnd) { 38 | - if (*a != *b) 39 | - break; 40 | - if (IsSeparator (*a)) { 41 | - indx++; 42 | - lastStartA = a + 1; 43 | - lastStartB = b; 44 | - } 45 | - a++; 46 | - b++; 47 | - if (b >= bEnd) { 48 | - if (a >= aEnd || IsSeparator (*a)) { 49 | - indx++; 50 | - lastStartA = a + 1; 51 | - lastStartB = b; 52 | - } 53 | - break; 54 | - } 55 | - } 56 | - if (indx == 0) 57 | - return absPath; 58 | - 59 | - if (lastStartA >= aEnd) 60 | - return "."; 61 | - 62 | - // handle case a: some/path b: some/path/deeper... 63 | - if (a >= aEnd) { 64 | - if (IsSeparator (*b)) { 65 | - lastStartA = a + 1; 66 | - lastStartB = b; 67 | - } 68 | - } 69 | - 70 | - // look how many levels to go up into the base path 71 | - int goUpCount = 0; 72 | - while (lastStartB < bEnd) { 73 | - if (IsSeparator (*lastStartB)) 74 | - goUpCount++; 75 | - lastStartB++; 76 | - } 77 | - var size = goUpCount * 2 + goUpCount + aEnd - lastStartA; 78 | - var result = new char [size]; 79 | - fixed (char* rPtr = result) { 80 | - // go paths up 81 | - var r = rPtr; 82 | - for (int i = 0; i < goUpCount; i++) { 83 | - *(r++) = '.'; 84 | - *(r++) = '.'; 85 | - *(r++) = Path.DirectorySeparatorChar; 86 | - } 87 | - // copy the remaining absulute path 88 | - while (lastStartA < aEnd) 89 | - *(r++) = *(lastStartA++); 90 | - } 91 | - return new string (result); 92 | - } 93 | + var fileUri = new Uri(absPath); 94 | + var referenceUri = new Uri(baseDirectoryPath); 95 | + return Uri.UnescapeDataString(referenceUri.MakeRelativeUri(fileUri).ToString()).Replace('/', Path.DirectorySeparatorChar); 96 | } 97 | 98 | static bool IsSeparator (char ch) 99 | -- 100 | 2.30.1.windows.1 101 | 102 | -------------------------------------------------------------------------------- /Documentation~/scripts/generate-docs.ps1: -------------------------------------------------------------------------------- 1 | Remove-Item -Recurse -Force dist/ 2 | Remove-Item -Recurse -Force obj/ 3 | 4 | git clone https://github.com/faster-games/UnityFX.git dist/.unityfx 5 | docfx 6 | -------------------------------------------------------------------------------- /Documentation~/scripts/generate-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -rf dist/ 4 | rm -rf obj/ 5 | 6 | git clone https://github.com/faster-games/UnityFX.git dist/.unityfx 7 | docfx 8 | -------------------------------------------------------------------------------- /Documentation~/scripts/lib-visibility.patch: -------------------------------------------------------------------------------- 1 | From acd71f305824e38b35621bb7f2aeee5a0aedf734 Mon Sep 17 00:00:00 2001 2 | From: Ben Greenier 3 | Date: Mon, 19 Jul 2021 12:48:24 -0700 4 | Subject: [PATCH] =?UTF-8?q?fix(patch-lib):=20Patch=20visibility=20for=20te?= 5 | =?UTF-8?q?sting=20=F0=9F=91=80?= 6 | MIME-Version: 1.0 7 | Content-Type: text/plain; charset=UTF-8 8 | Content-Transfer-Encoding: 8bit 9 | 10 | --- 11 | Editor/TextTemplating/Mono.TextTemplating/StringUtil.cs | 2 +- 12 | Editor/TextTemplating/Mono.TextTemplating/TemplateGenerator.cs | 2 +- 13 | 2 files changed, 2 insertions(+), 2 deletions(-) 14 | 15 | diff --git a/Editor/TextTemplating/Mono.TextTemplating/StringUtil.cs b/Editor/TextTemplating/Mono.TextTemplating/StringUtil.cs 16 | index bfcadb5..386fd53 100644 17 | --- a/Editor/TextTemplating/Mono.TextTemplating/StringUtil.cs 18 | +++ b/Editor/TextTemplating/Mono.TextTemplating/StringUtil.cs 19 | @@ -2,7 +2,7 @@ using System; 20 | 21 | namespace Mono.TextTemplating 22 | { 23 | - internal static class StringUtil 24 | + public static class StringUtil 25 | { 26 | public static Boolean IsNullOrWhiteSpace (String value) 27 | { 28 | diff --git a/Editor/TextTemplating/Mono.TextTemplating/TemplateGenerator.cs b/Editor/TextTemplating/Mono.TextTemplating/TemplateGenerator.cs 29 | index 24e7c3f..8986240 100644 30 | --- a/Editor/TextTemplating/Mono.TextTemplating/TemplateGenerator.cs 31 | +++ b/Editor/TextTemplating/Mono.TextTemplating/TemplateGenerator.cs 32 | @@ -307,7 +307,7 @@ namespace Mono.TextTemplating 33 | return false; 34 | } 35 | 36 | - internal static bool TryParseParameter (string parameter, out string processor, out string directive, out string name, out string value) 37 | + public static bool TryParseParameter (string parameter, out string processor, out string directive, out string name, out string value) 38 | { 39 | processor = directive = name = value = ""; 40 | 41 | -- 42 | 2.30.1.windows.1 43 | 44 | -------------------------------------------------------------------------------- /Documentation~/scripts/update-engine.ps1: -------------------------------------------------------------------------------- 1 | param ( 2 | [string] 3 | $Version = "2.0.5", 4 | 5 | [bool] 6 | $UpdateLib = $true, 7 | 8 | [bool] 9 | $UpdateTests = $true 10 | ) 11 | 12 | $WorkingDirectory="dist/.t4" 13 | $LibDirectory="Editor/TextTemplating" 14 | $TestDirectory="Tests/Editor/TextTemplating" 15 | 16 | try { 17 | Remove-Item -Recurse -Force "$WorkingDirectory" 18 | } catch {} 19 | 20 | if (!(Test-Path $WorkingDirectory)) 21 | { 22 | [System.IO.Directory]::CreateDirectory($WorkingDirectory) 23 | } 24 | 25 | 26 | Invoke-WebRequest -Uri "https://github.com/mono/t4/archive/refs/tags/v$Version.zip" -OutFile "$WorkingDirectory/lib.zip" 27 | Expand-Archive -Path "$WorkingDirectory/lib.zip" -DestinationPath "$WorkingDirectory/lib/" 28 | Copy-Item -Recurse -Path "$WorkingDirectory/lib/t4-$Version/Mono.TextTemplating/" -Destination "$WorkingDirectory/TextTemplating/" 29 | Copy-Item -Recurse -Path "$WorkingDirectory/lib/t4-$Version/Mono.TextTemplating.Tests/" -Destination "$WorkingDirectory/TextTemplating.Tests/" 30 | Remove-Item -Recurse -Force "$WorkingDirectory/lib" 31 | Remove-Item -Force "$WorkingDirectory/TextTemplating/Mono.TextTemplating.csproj" 32 | Remove-Item -Force "$WorkingDirectory/TextTemplating.Tests/Mono.TextTemplating.Tests.csproj" 33 | Remove-Item -Force "$WorkingDirectory/TextTemplating.Tests/MSBuildErrorParserTests.cs" 34 | Remove-Item -Force "$WorkingDirectory/TextTemplating/AssemblyInfo.cs" 35 | Remove-Item -Force "$WorkingDirectory/lib.zip" 36 | 37 | if ($UpdateLib) 38 | { 39 | try { 40 | Remove-Item -Recurse -Force "$LibDirectory/" 41 | } catch {} 42 | Copy-Item -Recurse -Path "$WorkingDirectory/TextTemplating/" -Destination "$LibDirectory/" 43 | 44 | git am Documentation~/scripts/file-utils.patch 45 | } 46 | 47 | if ($UpdateTests) 48 | { 49 | try { 50 | Remove-Item -Recurse -Force "$TestDirectory/" 51 | } catch {} 52 | Copy-Item -Recurse -Path "$WorkingDirectory/TextTemplating.Tests/" -Destination "$TestDirectory/" 53 | 54 | git am Documentation~/scripts/lib-visibility.patch 55 | } 56 | -------------------------------------------------------------------------------- /Documentation~/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Home 2 | href: index.md 3 | - name: Manual 4 | href: manual/ 5 | homepage: manual/getting-started.md 6 | - name: Scripting API 7 | href: xref:FasterGames.T4.Editor 8 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e7f56891fc83f8a42aef87667478f85a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/EditorExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using UnityEditor; 3 | using UnityEngine; 4 | 5 | namespace FasterGames.T4.Editor 6 | { 7 | /// 8 | /// Editor extensions to add TT creation to right click menus 9 | /// 10 | public static class EditorExtensions 11 | { 12 | /// 13 | /// Asset menu to create TT (.tt) files 14 | /// 15 | [MenuItem("Assets/Create/T4 Template", priority = 100)] 16 | public static void CreateTTFile() 17 | { 18 | var assetName = CreateSafeName(Path.Combine(EditorUtils.GetCurrentAssetDirectory(), "textTemplate.tt")); 19 | File.Create(assetName).Dispose(); 20 | 21 | AssetDatabase.ImportAsset(assetName); 22 | } 23 | 24 | /// 25 | /// Asset menu to create TTInclude (.ttinclude) files 26 | /// 27 | [MenuItem("Assets/Create/T4 Template Include", priority = 101)] 28 | public static void CreateTTIncludeFile() 29 | { 30 | var assetName = CreateSafeName(Path.Combine(EditorUtils.GetCurrentAssetDirectory(), "textTemplateInclude.ttinclude")); 31 | File.Create(assetName).Dispose(); 32 | AssetDatabase.ImportAsset(assetName); 33 | } 34 | 35 | /// 36 | /// Creates a filename that isn't currently in use 37 | /// 38 | /// the name you desire 39 | /// the name that's available 40 | private static string CreateSafeName(string desiredName) 41 | { 42 | var name = desiredName; 43 | var i = 1; 44 | while (File.Exists(name)) 45 | { 46 | name = Path.Combine(Path.GetDirectoryName(desiredName), $"{Path.GetFileNameWithoutExtension(desiredName)}{i}{Path.GetExtension(desiredName)}"); 47 | i++; 48 | } 49 | 50 | return name; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /Editor/EditorExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 56b1fb9c95624706b2c83a9269ab0fb0 3 | timeCreated: 1626820143 -------------------------------------------------------------------------------- /Editor/EditorUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEditor; 4 | using Object = UnityEngine.Object; 5 | 6 | namespace FasterGames.T4.Editor 7 | { 8 | /// 9 | /// Internal editor utilities 10 | /// 11 | internal static class EditorUtils 12 | { 13 | /// 14 | /// task runner 15 | /// 16 | /// 17 | /// This allows us to schedule work to be run once on Editor update 18 | /// 19 | /// task to run 20 | public static void Once(Action cb) 21 | { 22 | OnceTasks.Enqueue(cb); 23 | EditorApplication.update += OnceRunner; 24 | } 25 | 26 | /// 27 | /// Storage for tasks. See 28 | /// 29 | private static readonly Queue OnceTasks = new Queue(); 30 | 31 | /// 32 | /// Worker job that runs on Editor update 33 | /// 34 | /// 35 | /// This checks if any jobs need to be run, and if so, runs them. 36 | /// 37 | private static void OnceRunner() 38 | { 39 | while (OnceTasks.Count > 0) 40 | { 41 | OnceTasks.Dequeue()(); 42 | } 43 | 44 | EditorApplication.update -= OnceRunner; 45 | } 46 | 47 | /// 48 | /// Get the current asset directory 49 | /// 50 | /// 51 | /// From https://gist.github.com/allanolivei/9260107 52 | /// 53 | /// directory 54 | public static string GetCurrentAssetDirectory() 55 | { 56 | foreach (var obj in Selection.GetFiltered(SelectionMode.Assets)) 57 | { 58 | var path = AssetDatabase.GetAssetPath(obj); 59 | if (string.IsNullOrEmpty(path)) 60 | continue; 61 | 62 | if (System.IO.Directory.Exists(path)) 63 | return path; 64 | else if (System.IO.File.Exists(path)) 65 | return System.IO.Path.GetDirectoryName(path); 66 | } 67 | 68 | return "Assets"; 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /Editor/EditorUtils.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 964020e5576647e0922785de347a17f0 3 | timeCreated: 1626978599 -------------------------------------------------------------------------------- /Editor/FasterGames.T4.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "FasterGames.T4.Editor", 3 | "rootNamespace": "FasterGames.T4.Editor", 4 | "references": [ 5 | "GUID:70eadbddef1576040aa024086713826d" 6 | ], 7 | "includePlatforms": [ 8 | "Editor" 9 | ], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": false, 12 | "overrideReferences": false, 13 | "precompiledReferences": [], 14 | "autoReferenced": true, 15 | "defineConstraints": [], 16 | "versionDefines": [], 17 | "noEngineReferences": false 18 | } -------------------------------------------------------------------------------- /Editor/FasterGames.T4.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7e6bc557f44a650499c7bad48ec27044 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/ImporterVersion.cs: -------------------------------------------------------------------------------- 1 | namespace FasterGames.T4.Editor 2 | { 3 | /// 4 | /// The importer version to use 5 | /// 6 | public enum ImporterVersion 7 | { 8 | /// 9 | /// The stable option, but with fewer features 10 | /// 11 | Stable = 0, 12 | 13 | /// 14 | /// The beta option, for less-stable new features 15 | /// 16 | Beta 17 | } 18 | } -------------------------------------------------------------------------------- /Editor/ImporterVersion.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7bd700577abd4f35a1c887b16ab89245 3 | timeCreated: 1626818872 -------------------------------------------------------------------------------- /Editor/ReflectionUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.CodeDom; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace FasterGames.T4.Editor 7 | { 8 | /// 9 | /// Internal reflection utils 10 | /// 11 | internal static class ReflectionUtils 12 | { 13 | /// 14 | /// Get the child types from a src type 15 | /// 16 | /// src type 17 | /// child types 18 | public static IReadOnlyCollection ChildTypes(Type src) 19 | { 20 | List types = new List(); 21 | 22 | AddMissingChildTypes(src, ref types); 23 | 24 | return types; 25 | } 26 | 27 | /// 28 | /// Internal helper to add missing child types to a list 29 | /// 30 | /// src type 31 | /// existing types 32 | private static void AddMissingChildTypes(Type src, ref List types) 33 | { 34 | var fieldTypes = src.GetFields().Select(f => f.FieldType); 35 | var propTypes = src.GetProperties().Select(p => p.PropertyType); 36 | 37 | var baseTypes = new List(); 38 | if (src.BaseType != null) 39 | { 40 | baseTypes.Add(src.BaseType); 41 | } 42 | 43 | var coreTypes = fieldTypes.Union(propTypes)/*.Union(attrTypes)*/.Union(baseTypes); 44 | 45 | foreach (var type in coreTypes) 46 | { 47 | if (!types.Contains(type) && type != null) 48 | { 49 | types.Add(type); 50 | AddMissingChildTypes(type, ref types); 51 | } 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /Editor/ReflectionUtils.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e00163f37b964c1eb19480fe8ac01567 3 | timeCreated: 1626901155 -------------------------------------------------------------------------------- /Editor/TextTemplateImporter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System; 3 | using System.IO; 4 | using Mono.TextTemplating; 5 | using UnityEditor; 6 | using UnityEditor.AssetImporters; 7 | using UnityEngine; 8 | using Object = UnityEngine.Object; 9 | 10 | namespace FasterGames.T4.Editor 11 | { 12 | /// 13 | /// The TextTemplate (.tt) file importer for Unity3D 14 | /// 15 | /// 16 | /// This importer relies on mono/t4 to parse templates and generate csharp files 17 | /// 18 | [ScriptedImporter(2, "tt")] 19 | public class TextTemplateImporter : ScriptedImporter 20 | { 21 | /// 22 | /// Flag; determines which importer feature-set is supported 23 | /// 24 | [Tooltip("The importer version to use")] 25 | public ImporterVersion importerVersion; 26 | 27 | /// 28 | /// Flag; If set, any empty files that are generated will be ignored. 29 | /// 30 | [Tooltip("If set, any empty files that are generated will be ignored.")] 31 | public bool removeIfEmptyGeneration = true; 32 | 33 | /// 34 | /// Data to be embedded in the template host, so it can be accessed by the template 35 | /// 36 | [Tooltip("Allows data to be embedded and accessed by the template.")] 37 | public Object embeddedData; 38 | 39 | /// 40 | /// Additional types to import into the template context. 41 | /// 42 | /// 43 | /// Use this if your includes data types that are outside 44 | /// the default referenced types 45 | /// 46 | /// 47 | /// If contained `MyCustomNameSpace.MyCustomType dataElement` 48 | /// then you'd add `MyCustomNameSpace.MyCustomType` here. 49 | /// 50 | [Tooltip("Additional types to import into the template context.")] 51 | public List additionalTypes; 52 | 53 | /// 54 | public override void OnImportAsset(AssetImportContext ctx) 55 | { 56 | if (ctx == null) 57 | { 58 | return; 59 | } 60 | 61 | var outputFilePath = Path.Combine(Path.GetDirectoryName(ctx.assetPath), Path.GetFileNameWithoutExtension(ctx.assetPath) + ".cs"); 62 | var src = File.ReadAllText(ctx.assetPath); 63 | 64 | TemplateGenerator generator; 65 | 66 | switch (importerVersion) 67 | { 68 | case ImporterVersion.Stable: 69 | generator = new TemplateGenerator(); 70 | break; 71 | case ImporterVersion.Beta: 72 | { 73 | generator = UnityDataHost.CreateInstance(embeddedData, additionalTypes); 74 | break; 75 | } 76 | default: 77 | throw new InvalidOperationException(); 78 | } 79 | 80 | if (generator.ProcessTemplate(ctx.assetPath, src, ref outputFilePath, out string dst)) 81 | { 82 | if (!removeIfEmptyGeneration || dst.Length > 0) 83 | { 84 | File.WriteAllText(outputFilePath, dst); 85 | } 86 | 87 | EditorUtils.Once(() => 88 | { 89 | // TODO(bengreenier): is there a less expensive way to force it to reload scripts/appdomain? 90 | AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate); 91 | }); 92 | } 93 | else 94 | { 95 | for (var i = 0; i < generator.Errors.Count; i++) 96 | { 97 | var err = generator.Errors[i]; 98 | 99 | Debug.LogError(err.ToString()); 100 | } 101 | } 102 | 103 | // core asset import 104 | var asset = new TextAsset(src); 105 | ctx.AddObjectToAsset("text", asset); 106 | ctx.SetMainObject(asset); 107 | 108 | // setup data dependency 109 | if (embeddedData != null && importerVersion == ImporterVersion.Beta) 110 | { 111 | var dataPath = AssetDatabase.GetAssetPath(embeddedData); 112 | var dataGuid = AssetDatabase.GUIDFromAssetPath(dataPath); 113 | 114 | ctx.DependsOnArtifact(dataGuid); 115 | 116 | // needed to enforce the dependency 117 | AssetDatabase.LoadAssetAtPath(dataPath); 118 | } 119 | } 120 | } 121 | } -------------------------------------------------------------------------------- /Editor/TextTemplateImporter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0d7b524045e7470296c8e842826841f7 3 | timeCreated: 1626722796 -------------------------------------------------------------------------------- /Editor/TextTemplateImporterEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEditor.AssetImporters; 3 | using UnityEngine; 4 | 5 | namespace FasterGames.T4.Editor 6 | { 7 | /// 8 | /// Custom editor for 9 | /// 10 | [CustomEditor(typeof(TextTemplateImporter))] 11 | [CanEditMultipleObjects] 12 | public class TextTemplateImporterEditor : ScriptedImporterEditor 13 | { 14 | /// 15 | public override void OnInspectorGUI() 16 | { 17 | serializedObject.Update(); 18 | 19 | var tgt = ((TextTemplateImporter) target); 20 | 21 | EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(TextTemplateImporter.importerVersion))); 22 | 23 | EditorGUILayout.PropertyField( 24 | serializedObject.FindProperty(nameof(TextTemplateImporter.removeIfEmptyGeneration))); 25 | 26 | // only the beta gets embeddedData support 27 | if (tgt.importerVersion == ImporterVersion.Beta) 28 | { 29 | EditorGUILayout.Space(); 30 | EditorGUILayout.LabelField("Embedded Data", EditorStyles.largeLabel); 31 | EditorGUILayout.HelpBox($"Allows you to access data from Unity within your template. The data will be exposed at `Host.{nameof(UnityDataHost.Data)}` inside your template. This is a {nameof(ImporterVersion.Beta)} feature.", MessageType.None); 32 | 33 | EditorGUILayout.BeginHorizontal(); 34 | { 35 | EditorGUILayout.PropertyField( 36 | serializedObject.FindProperty(nameof(TextTemplateImporter.additionalTypes))); 37 | EditorGUILayout.HelpBox( 38 | "If your template fails to compile after enabling embedded data, you may need to include additional types in the Template Engine context.", 39 | MessageType.Warning); 40 | } 41 | EditorGUILayout.EndHorizontal(); 42 | 43 | EditorGUILayout.PropertyField(serializedObject.FindProperty(nameof(TextTemplateImporter.embeddedData))); 44 | 45 | var embeddedData = tgt.embeddedData; 46 | 47 | var initEnabled = GUI.enabled; 48 | GUI.enabled = false; 49 | if (embeddedData != null) 50 | { 51 | DrawPropertiesExcluding(new SerializedObject(embeddedData)); 52 | } 53 | GUI.enabled = initEnabled; 54 | } 55 | 56 | serializedObject.ApplyModifiedProperties(); 57 | ApplyRevertGUI(); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /Editor/TextTemplateImporterEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fb7fb0d71c2848128858b77c3c9dc5b6 3 | timeCreated: 1626813414 -------------------------------------------------------------------------------- /Editor/TextTemplateIncludeImporter.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using UnityEditor.AssetImporters; 3 | using UnityEngine; 4 | 5 | namespace FasterGames.T4.Editor 6 | { 7 | /// 8 | /// The TextTemplate include (.ttinclude) file importer for Unity3D 9 | /// 10 | [ScriptedImporter(1, "ttinclude")] 11 | public class TextTemplateIncludeImporter : ScriptedImporter 12 | { 13 | /// 14 | public override void OnImportAsset(AssetImportContext ctx) 15 | { 16 | // since this is just a supporting file, no generation is needed 17 | // however, we pull this in as text so it can show nicely in the editor 18 | var asset = new TextAsset(File.ReadAllText(ctx.assetPath)); 19 | ctx.AddObjectToAsset("text", asset); 20 | ctx.SetMainObject(asset); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /Editor/TextTemplateIncludeImporter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6d49c1479ae04d9e99683c124196b492 3 | timeCreated: 1626723188 -------------------------------------------------------------------------------- /Editor/TextTemplating.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 52078dc76a56048458a5abb3abc7987c 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9f55e6c691ae9d14492d4bd005ffa0b7 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/DirectiveProcessor.cs: -------------------------------------------------------------------------------- 1 | // 2 | // DirectiveProcessor.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2009 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.CodeDom.Compiler; 30 | using System.CodeDom; 31 | 32 | namespace Microsoft.VisualStudio.TextTemplating 33 | { 34 | public abstract class DirectiveProcessor : IDirectiveProcessor 35 | { 36 | CompilerErrorCollection errors; 37 | 38 | protected DirectiveProcessor () 39 | { 40 | } 41 | 42 | public virtual void Initialize (ITextTemplatingEngineHost host) 43 | { 44 | if (host == null) 45 | throw new ArgumentNullException ("host"); 46 | } 47 | 48 | public virtual void StartProcessingRun (CodeDomProvider languageProvider, string templateContents, CompilerErrorCollection errors) 49 | { 50 | if (languageProvider == null) 51 | throw new ArgumentNullException ("languageProvider"); 52 | this.errors = errors; 53 | } 54 | 55 | public abstract void FinishProcessingRun (); 56 | public abstract string GetClassCodeForProcessingRun (); 57 | public abstract string[] GetImportsForProcessingRun (); 58 | public abstract string GetPostInitializationCodeForProcessingRun (); 59 | public abstract string GetPreInitializationCodeForProcessingRun (); 60 | public abstract string[] GetReferencesForProcessingRun (); 61 | public abstract bool IsDirectiveSupported (string directiveName); 62 | public abstract void ProcessDirective (string directiveName, IDictionary arguments); 63 | 64 | public virtual CodeAttributeDeclarationCollection GetTemplateClassCustomAttributes () 65 | { 66 | return null; 67 | } 68 | 69 | CompilerErrorCollection IDirectiveProcessor.Errors { get { return errors; } } 70 | 71 | void IDirectiveProcessor.SetProcessingRunIsHostSpecific (bool hostSpecific) 72 | { 73 | } 74 | 75 | bool IDirectiveProcessor.RequiresProcessingRunIsHostSpecific { 76 | get { return false; } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/DirectiveProcessor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4170cfce4e5b8a14f8b20ebe5cf50489 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/DirectiveProcessorException.cs: -------------------------------------------------------------------------------- 1 | // 2 | // DirectiveProcessorException.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2009 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Runtime.Serialization; 29 | 30 | namespace Microsoft.VisualStudio.TextTemplating 31 | { 32 | 33 | [Serializable] 34 | public class DirectiveProcessorException : Exception 35 | { 36 | 37 | public DirectiveProcessorException () 38 | { 39 | } 40 | 41 | public DirectiveProcessorException (string message) 42 | : base (message) 43 | { 44 | } 45 | 46 | public DirectiveProcessorException (SerializationInfo info, StreamingContext context) 47 | : base (info, context) 48 | { 49 | } 50 | 51 | public DirectiveProcessorException (string message, Exception inner) 52 | : base (message, inner) 53 | { 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/DirectiveProcessorException.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 88495be4269a08140b1a43dab9fe1a69 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/EncodingHelper.cs: -------------------------------------------------------------------------------- 1 | // 2 | // EncodingHelper.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2010 Novell, Inc. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Text; 29 | 30 | namespace Microsoft.VisualStudio.TextTemplating 31 | { 32 | [Obsolete("Not implemented")] 33 | public static class EncodingHelper 34 | { 35 | public static Encoding GetEncoding (string filePath) 36 | { 37 | throw new NotImplementedException (); 38 | } 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/EncodingHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c95478daeea2b8d409e96bfdfc25fed5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/Engine.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Engine.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2009 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using Mono.TextTemplating; 29 | 30 | namespace Microsoft.VisualStudio.TextTemplating 31 | { 32 | [Obsolete ("Use Mono.TextTemplating.TemplatingEngine directly")] 33 | public class Engine : ITextTemplatingEngine 34 | { 35 | TemplatingEngine engine = new TemplatingEngine (); 36 | 37 | public string ProcessTemplate (string content, ITextTemplatingEngineHost host) 38 | { 39 | return engine.ProcessTemplate (content, host); 40 | } 41 | 42 | public string PreprocessTemplate (string content, ITextTemplatingEngineHost host, string className, 43 | string classNamespace, out string language, out string[] references) 44 | { 45 | return engine.PreprocessTemplate (content, host, className, classNamespace, out language, out references); 46 | } 47 | 48 | public const string CacheAssembliesOptionString = "CacheAssemblies"; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/Engine.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e8ec428572a96884b968c9515617e8d2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/Interfaces.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ITextTemplatingEngineHost.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2009-2010 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.CodeDom; 29 | using System.CodeDom.Compiler; 30 | using System.Collections; 31 | using System.Collections.Generic; 32 | using System.Runtime.Serialization; 33 | using System.Text; 34 | 35 | namespace Microsoft.VisualStudio.TextTemplating 36 | { 37 | public interface IRecognizeHostSpecific 38 | { 39 | void SetProcessingRunIsHostSpecific (bool hostSpecific); 40 | bool RequiresProcessingRunIsHostSpecific { get; } 41 | } 42 | 43 | [Obsolete("Use Mono.TextTemplating.TemplatingEngine directly")] 44 | public interface ITextTemplatingEngine 45 | { 46 | string ProcessTemplate (string content, ITextTemplatingEngineHost host); 47 | string PreprocessTemplate (string content, ITextTemplatingEngineHost host, string className, 48 | string classNamespace, out string language, out string [] references); 49 | } 50 | 51 | public interface ITextTemplatingEngineHost 52 | { 53 | object GetHostOption (string optionName); 54 | bool LoadIncludeText (string requestFileName, out string content, out string location); 55 | void LogErrors (CompilerErrorCollection errors); 56 | //FIXME: this break binary compat 57 | #if FEATURE_APPDOMAINS 58 | AppDomain ProvideTemplatingAppDomain (string content); 59 | #endif 60 | string ResolveAssemblyReference (string assemblyReference); 61 | Type ResolveDirectiveProcessor (string processorName); 62 | string ResolveParameterValue (string directiveId, string processorName, string parameterName); 63 | string ResolvePath (string path); 64 | void SetFileExtension (string extension); 65 | void SetOutputEncoding (Encoding encoding, bool fromOutputDirective); 66 | IList StandardAssemblyReferences { get; } 67 | IList StandardImports { get; } 68 | string TemplateFile { get; } 69 | } 70 | 71 | public interface ITextTemplatingSession : 72 | IEquatable, IEquatable, IDictionary, 73 | ICollection>, 74 | IEnumerable>, 75 | IEnumerable, ISerializable 76 | { 77 | Guid Id { get; } 78 | } 79 | 80 | public interface ITextTemplatingSessionHost 81 | { 82 | ITextTemplatingSession CreateSession (); 83 | ITextTemplatingSession Session { get; set; } 84 | } 85 | 86 | public interface IDirectiveProcessor 87 | { 88 | CompilerErrorCollection Errors { get; } 89 | bool RequiresProcessingRunIsHostSpecific { get; } 90 | 91 | void FinishProcessingRun (); 92 | string GetClassCodeForProcessingRun (); 93 | string[] GetImportsForProcessingRun (); 94 | string GetPostInitializationCodeForProcessingRun (); 95 | string GetPreInitializationCodeForProcessingRun (); 96 | string[] GetReferencesForProcessingRun (); 97 | CodeAttributeDeclarationCollection GetTemplateClassCustomAttributes (); //TODO 98 | void Initialize (ITextTemplatingEngineHost host); 99 | bool IsDirectiveSupported (string directiveName); 100 | void ProcessDirective (string directiveName, IDictionary arguments); 101 | void SetProcessingRunIsHostSpecific (bool hostSpecific); 102 | void StartProcessingRun (CodeDomProvider languageProvider, string templateContents, CompilerErrorCollection errors); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/Interfaces.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c42815b00e1ca9d4c810ad381dc27010 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/ParameterDirectiveProcessor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3f5169224a08c3941b9e2c62b89b4fa2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/RequiresProvidesDirectiveProcessor.cs: -------------------------------------------------------------------------------- 1 | // 2 | // RequiresProvidesDirectiveProcessor.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2009 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.CodeDom.Compiler; 30 | using System.Text; 31 | 32 | namespace Microsoft.VisualStudio.TextTemplating 33 | { 34 | 35 | 36 | public abstract class RequiresProvidesDirectiveProcessor : DirectiveProcessor 37 | { 38 | bool isInProcessingRun; 39 | ITextTemplatingEngineHost host; 40 | StringBuilder preInitBuffer = new StringBuilder (); 41 | StringBuilder postInitBuffer = new StringBuilder (); 42 | StringBuilder codeBuffer = new StringBuilder (); 43 | CodeDomProvider languageProvider; 44 | 45 | protected RequiresProvidesDirectiveProcessor () 46 | { 47 | } 48 | 49 | public override void Initialize (ITextTemplatingEngineHost host) 50 | { 51 | base.Initialize (host); 52 | this.host = host; 53 | } 54 | 55 | protected abstract void InitializeProvidesDictionary (string directiveName, IDictionary providesDictionary); 56 | protected abstract void InitializeRequiresDictionary (string directiveName, IDictionary requiresDictionary); 57 | protected abstract string FriendlyName { get; } 58 | 59 | protected abstract void GeneratePostInitializationCode (string directiveName, StringBuilder codeBuffer, CodeDomProvider languageProvider, 60 | IDictionary requiresArguments, IDictionary providesArguments); 61 | protected abstract void GeneratePreInitializationCode (string directiveName, StringBuilder codeBuffer, CodeDomProvider languageProvider, 62 | IDictionary requiresArguments, IDictionary providesArguments); 63 | protected abstract void GenerateTransformCode (string directiveName, StringBuilder codeBuffer, CodeDomProvider languageProvider, 64 | IDictionary requiresArguments, IDictionary providesArguments); 65 | 66 | protected virtual void PostProcessArguments (string directiveName, IDictionary requiresArguments, 67 | IDictionary providesArguments) 68 | { 69 | } 70 | 71 | public override string GetClassCodeForProcessingRun () 72 | { 73 | AssertNotProcessing (); 74 | return codeBuffer.ToString (); 75 | } 76 | 77 | public override string[] GetImportsForProcessingRun () 78 | { 79 | AssertNotProcessing (); 80 | return null; 81 | } 82 | 83 | public override string[] GetReferencesForProcessingRun () 84 | { 85 | AssertNotProcessing (); 86 | return null; 87 | } 88 | 89 | public override string GetPostInitializationCodeForProcessingRun () 90 | { 91 | AssertNotProcessing (); 92 | return postInitBuffer.ToString (); 93 | } 94 | 95 | public override string GetPreInitializationCodeForProcessingRun () 96 | { 97 | AssertNotProcessing (); 98 | return preInitBuffer.ToString (); 99 | } 100 | 101 | public override void StartProcessingRun (CodeDomProvider languageProvider, string templateContents, CompilerErrorCollection errors) 102 | { 103 | AssertNotProcessing (); 104 | isInProcessingRun = true; 105 | base.StartProcessingRun (languageProvider, templateContents, errors); 106 | 107 | this.languageProvider = languageProvider; 108 | codeBuffer.Length = 0; 109 | preInitBuffer.Length = 0; 110 | postInitBuffer.Length = 0; 111 | } 112 | 113 | public override void FinishProcessingRun () 114 | { 115 | isInProcessingRun = false; 116 | } 117 | 118 | void AssertNotProcessing () 119 | { 120 | if (isInProcessingRun) 121 | throw new InvalidOperationException (); 122 | } 123 | 124 | //FIXME: handle escaping 125 | IEnumerable> ParseArgs (string args) 126 | { 127 | var pairs = args.Split (';'); 128 | foreach (var p in pairs) { 129 | int eq = p.IndexOf ('='); 130 | var k = p.Substring (0, eq); 131 | var v = p.Substring (eq); 132 | yield return new KeyValuePair (k, v); 133 | } 134 | } 135 | 136 | public override void ProcessDirective (string directiveName, IDictionary arguments) 137 | { 138 | if (directiveName == null) 139 | throw new ArgumentNullException ("directiveName"); 140 | if (arguments == null) 141 | throw new ArgumentNullException ("arguments"); 142 | 143 | var providesDictionary = new Dictionary (); 144 | var requiresDictionary = new Dictionary (); 145 | 146 | string provides; 147 | if (arguments.TryGetValue ("provides", out provides)) { 148 | foreach (var arg in ParseArgs (provides)) { 149 | providesDictionary.Add (arg.Key, arg.Value); 150 | } 151 | } 152 | 153 | string requires; 154 | if (arguments.TryGetValue ("requires", out requires)) { 155 | foreach (var arg in ParseArgs (requires)) { 156 | requiresDictionary.Add (arg.Key, arg.Value); 157 | } 158 | } 159 | 160 | InitializeRequiresDictionary (directiveName, requiresDictionary); 161 | InitializeProvidesDictionary (directiveName, providesDictionary); 162 | 163 | var id = ProvideUniqueId (directiveName, arguments, requiresDictionary, providesDictionary); 164 | 165 | foreach (var req in requiresDictionary) { 166 | var val = host.ResolveParameterValue (id, FriendlyName, req.Key); 167 | if (val != null) 168 | requiresDictionary[req.Key] = val; 169 | else if (req.Value == null) 170 | throw new DirectiveProcessorException ("Could not resolve required value '" + req.Key + "'"); 171 | } 172 | 173 | foreach (var req in providesDictionary) { 174 | var val = host.ResolveParameterValue (id, FriendlyName, req.Key); 175 | if (val != null) 176 | providesDictionary[req.Key] = val; 177 | } 178 | 179 | PostProcessArguments (directiveName, requiresDictionary, providesDictionary); 180 | 181 | GeneratePreInitializationCode (directiveName, preInitBuffer, languageProvider, requiresDictionary, providesDictionary); 182 | GeneratePostInitializationCode (directiveName, postInitBuffer, languageProvider, requiresDictionary, providesDictionary); 183 | GenerateTransformCode (directiveName, codeBuffer, languageProvider, requiresDictionary, providesDictionary); 184 | } 185 | 186 | protected virtual string ProvideUniqueId (string directiveName, IDictionary arguments, 187 | IDictionary requiresArguments, IDictionary providesArguments) 188 | { 189 | return directiveName; 190 | } 191 | 192 | protected ITextTemplatingEngineHost Host { 193 | get { return host; } 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/RequiresProvidesDirectiveProcessor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 548dc2d199d9c664b9a1370d4690bd2e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/TextTemplatingSession.cs: -------------------------------------------------------------------------------- 1 | // 2 | // TextTemplatingSession.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2010 Novell, Inc. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | using System; 27 | using System.Collections.Generic; 28 | using System.Collections; 29 | using System.Runtime.Serialization; 30 | 31 | namespace Microsoft.VisualStudio.TextTemplating 32 | { 33 | [Serializable] 34 | public sealed class TextTemplatingSession : Dictionary, ITextTemplatingSession, ISerializable 35 | { 36 | public TextTemplatingSession () : this (Guid.NewGuid ()) 37 | { 38 | } 39 | 40 | TextTemplatingSession (SerializationInfo info, StreamingContext context) 41 | : base (info, context) 42 | { 43 | Id = (Guid)info.GetValue ("Id", typeof (Guid)); 44 | } 45 | 46 | public TextTemplatingSession (Guid id) 47 | { 48 | this.Id = id; 49 | } 50 | 51 | public Guid Id { 52 | get; private set; 53 | } 54 | 55 | public override int GetHashCode () 56 | { 57 | return Id.GetHashCode (); 58 | } 59 | 60 | public override bool Equals (object obj) 61 | { 62 | var o = obj as TextTemplatingSession; 63 | return o != null && o.Equals (this); 64 | } 65 | 66 | public bool Equals (Guid other) 67 | { 68 | return other.Equals (Id); 69 | } 70 | 71 | public bool Equals (ITextTemplatingSession other) 72 | { 73 | return other != null && other.Id == this.Id; 74 | } 75 | 76 | void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context) 77 | { 78 | base.GetObjectData (info, context); 79 | info.AddValue ("Id", Id); 80 | } 81 | } 82 | } 83 | 84 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/TextTemplatingSession.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 475fbdef91c329542bcd7b25a47a81c4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/TextTransformation.cs: -------------------------------------------------------------------------------- 1 | // 2 | // TextTransformation.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2009 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.CodeDom.Compiler; 29 | using System.Collections.Generic; 30 | using System.Text; 31 | 32 | namespace Microsoft.VisualStudio.TextTemplating 33 | { 34 | public abstract class TextTransformation : IDisposable 35 | { 36 | Stack indents; 37 | string currentIndent = string.Empty; 38 | CompilerErrorCollection errors; 39 | StringBuilder builder; 40 | bool endsWithNewline; 41 | 42 | public TextTransformation () 43 | { 44 | } 45 | 46 | public virtual void Initialize () 47 | { 48 | } 49 | 50 | public abstract string TransformText (); 51 | 52 | public virtual IDictionary Session { get; set; } 53 | 54 | #region Errors 55 | 56 | public void Error (string message) 57 | { 58 | Errors.Add (new CompilerError ("", 0, 0, "", message)); 59 | } 60 | 61 | public void Warning (string message) 62 | { 63 | Errors.Add (new CompilerError ("", 0, 0, "", message) { IsWarning = true }); 64 | } 65 | 66 | protected internal CompilerErrorCollection Errors { 67 | get { 68 | if (errors == null) 69 | errors = new CompilerErrorCollection (); 70 | return errors; 71 | } 72 | } 73 | 74 | Stack Indents { 75 | get { 76 | if (indents == null) 77 | indents = new Stack (); 78 | return indents; 79 | } 80 | } 81 | 82 | #endregion 83 | 84 | #region Indents 85 | 86 | public string PopIndent () 87 | { 88 | if (Indents.Count == 0) 89 | return ""; 90 | int lastPos = currentIndent.Length - Indents.Pop (); 91 | string last = currentIndent.Substring (lastPos); 92 | currentIndent = currentIndent.Substring (0, lastPos); 93 | return last; 94 | } 95 | 96 | public void PushIndent (string indent) 97 | { 98 | if (indent == null) 99 | throw new ArgumentNullException ("indent"); 100 | Indents.Push (indent.Length); 101 | currentIndent += indent; 102 | } 103 | 104 | public void ClearIndent () 105 | { 106 | currentIndent = string.Empty; 107 | Indents.Clear (); 108 | } 109 | 110 | public string CurrentIndent { 111 | get { return currentIndent; } 112 | } 113 | 114 | #endregion 115 | 116 | #region Writing 117 | 118 | protected StringBuilder GenerationEnvironment { 119 | get { 120 | if (builder == null) 121 | builder = new StringBuilder (); 122 | return builder; 123 | } 124 | set { 125 | builder = value; 126 | } 127 | } 128 | 129 | public void Write (string textToAppend) 130 | { 131 | if (string.IsNullOrEmpty (textToAppend)) 132 | return; 133 | 134 | if ((GenerationEnvironment.Length == 0 || endsWithNewline) && CurrentIndent.Length > 0) { 135 | GenerationEnvironment.Append (CurrentIndent); 136 | } 137 | endsWithNewline = false; 138 | 139 | char last = textToAppend[textToAppend.Length-1]; 140 | if (last == '\n' || last == '\r') { 141 | endsWithNewline = true; 142 | } 143 | 144 | if (CurrentIndent.Length == 0) { 145 | GenerationEnvironment.Append (textToAppend); 146 | return; 147 | } 148 | 149 | //insert CurrentIndent after every newline (\n, \r, \r\n) 150 | //but if there's one at the end of the string, ignore it, it'll be handled next time thanks to endsWithNewline 151 | int lastNewline = 0; 152 | for (int i = 0; i < textToAppend.Length - 1; i++) { 153 | char c = textToAppend[i]; 154 | if (c == '\r') { 155 | if (textToAppend[i + 1] == '\n') { 156 | i++; 157 | if (i == textToAppend.Length - 1) 158 | break; 159 | } 160 | } else if (c != '\n') { 161 | continue; 162 | } 163 | i++; 164 | int len = i - lastNewline; 165 | if (len > 0) { 166 | GenerationEnvironment.Append (textToAppend, lastNewline, i - lastNewline); 167 | } 168 | GenerationEnvironment.Append (CurrentIndent); 169 | lastNewline = i; 170 | } 171 | if (lastNewline > 0) 172 | GenerationEnvironment.Append (textToAppend, lastNewline, textToAppend.Length - lastNewline); 173 | else 174 | GenerationEnvironment.Append (textToAppend); 175 | } 176 | 177 | public void Write (string format, params object[] args) 178 | { 179 | Write (string.Format (format, args)); 180 | } 181 | 182 | public void WriteLine (string textToAppend) 183 | { 184 | Write (textToAppend); 185 | GenerationEnvironment.AppendLine (); 186 | endsWithNewline = true; 187 | } 188 | 189 | public void WriteLine (string format, params object[] args) 190 | { 191 | WriteLine (string.Format (format, args)); 192 | } 193 | 194 | #endregion 195 | 196 | #region Dispose 197 | 198 | public void Dispose () 199 | { 200 | Dispose (true); 201 | GC.SuppressFinalize (this); 202 | } 203 | 204 | protected virtual void Dispose (bool disposing) 205 | { 206 | } 207 | 208 | ~TextTransformation () 209 | { 210 | Dispose (false); 211 | } 212 | 213 | #endregion 214 | 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/TextTransformation.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c07619e2df4c61649adacacf0236fb63 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/ToStringHelper.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ToStringHelper.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2009 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Reflection; 29 | 30 | namespace Microsoft.VisualStudio.TextTemplating 31 | { 32 | public static class ToStringHelper 33 | { 34 | static readonly object[] formatProviderAsParameterArray; 35 | 36 | static IFormatProvider formatProvider = System.Globalization.CultureInfo.InvariantCulture; 37 | 38 | static ToStringHelper () 39 | { 40 | formatProviderAsParameterArray = new object[] { formatProvider }; 41 | } 42 | 43 | public static string ToStringWithCulture (object objectToConvert) 44 | { 45 | if (objectToConvert == null) 46 | throw new ArgumentNullException (nameof (objectToConvert)); 47 | 48 | IConvertible conv = objectToConvert as IConvertible; 49 | if (conv != null) 50 | return conv.ToString (formatProvider); 51 | 52 | var str = objectToConvert as string; 53 | if (str != null) 54 | return str; 55 | 56 | //TODO: implement a cache of types and DynamicMethods 57 | MethodInfo mi = objectToConvert.GetType ().GetMethod ("ToString", new Type[] { typeof (IFormatProvider) }); 58 | if (mi != null) 59 | return (string) mi.Invoke (objectToConvert, formatProviderAsParameterArray); 60 | return objectToConvert.ToString (); 61 | } 62 | 63 | public static IFormatProvider FormatProvider { 64 | get { return (IFormatProvider)formatProviderAsParameterArray[0]; } 65 | set { formatProviderAsParameterArray[0] = formatProvider = value; } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Microsoft.VisualStudio.TextTemplating/ToStringHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d88f75b9f0a0ed64d8ef1f7f1224d605 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.CodeCompilation.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2b912e88c44b4ca418ec4d3caf0017f6 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.CodeCompilation/CodeCompiler.cs: -------------------------------------------------------------------------------- 1 | // 2 | // CodeCompiler.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2018 Microsoft Corp 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.IO; 30 | using System.Threading; 31 | using System.Threading.Tasks; 32 | 33 | namespace Mono.TextTemplating.CodeCompilation 34 | { 35 | abstract class CodeCompiler 36 | { 37 | public abstract Task CompileFile (CodeCompilerArguments arguments, TextWriter log, CancellationToken token); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.CodeCompilation/CodeCompiler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: befe61388f5d4d64b87c5a7de04b8a7c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.CodeCompilation/CodeCompilerArguments.cs: -------------------------------------------------------------------------------- 1 | // 2 | // CodeCompiler.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2018 Microsoft Corp 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | using System.Collections.Generic; 27 | 28 | namespace Mono.TextTemplating.CodeCompilation 29 | { 30 | class CodeCompilerArguments 31 | { 32 | public List SourceFiles { get; } = new List (); 33 | public List AssemblyReferences { get; } = new List (); 34 | public string AdditionalArguments { get; set; } 35 | public bool Debug { get; set; } 36 | public string OutputPath { get; set; } 37 | public string TempDirectory { get; set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.CodeCompilation/CodeCompilerArguments.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d083fffdd430fbf49a48fa424b393954 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.CodeCompilation/CodeCompilerResult.cs: -------------------------------------------------------------------------------- 1 | // 2 | // CodeCompiler.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2018 Microsoft Corp 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System.Collections.Generic; 28 | 29 | namespace Mono.TextTemplating.CodeCompilation 30 | { 31 | class CodeCompilerResult 32 | { 33 | public bool Success { get; internal set; } 34 | public List Errors { get; internal set; } 35 | public int ExitCode { get; internal set; } 36 | public List Output { get; internal set; } 37 | public string ResponseFile { get; internal set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.CodeCompilation/CodeCompilerResult.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5c0751429198aa24cbf83e30ce0b2ec3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.CodeCompilation/CscCodeCompiler.cs: -------------------------------------------------------------------------------- 1 | // 2 | // CodeCompiler.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2018 Microsoft Corp 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | 28 | using System; 29 | using System.Collections.Generic; 30 | using System.IO; 31 | using System.Threading; 32 | using System.Threading.Tasks; 33 | using System.Linq; 34 | using System.Text; 35 | 36 | namespace Mono.TextTemplating.CodeCompilation 37 | { 38 | class CscCodeCompiler : CodeCompiler 39 | { 40 | readonly RuntimeInfo runtime; 41 | 42 | public CscCodeCompiler (RuntimeInfo runtime) 43 | { 44 | this.runtime = runtime; 45 | } 46 | 47 | static StreamWriter CreateTempTextFile (string extension, out string path) 48 | { 49 | path = null; 50 | Exception ex = null; 51 | try { 52 | var tempDir = Path.GetTempPath (); 53 | Directory.CreateDirectory (tempDir); 54 | 55 | //this is how msbuild does it... 56 | path = Path.Combine (tempDir, $"tmp{Guid.NewGuid ():N}{extension}"); 57 | if (!File.Exists (path)) { 58 | return File.CreateText (path); 59 | } 60 | } catch (Exception e) { 61 | ex = e; 62 | } 63 | throw new Exception ("Failed to create temp file", ex); 64 | } 65 | 66 | //attempt to resolve refs into the runtime dir if the host didn't already do so 67 | static string ResolveAssembly (RuntimeInfo runtime, string reference) 68 | { 69 | if (Path.IsPathRooted (reference) || File.Exists (reference)) { 70 | return reference; 71 | } 72 | 73 | var resolved = Path.Combine (runtime.RuntimeDir, reference); 74 | if (File.Exists (resolved)) { 75 | return resolved; 76 | } 77 | 78 | if (runtime.Kind != RuntimeKind.NetCore) { 79 | resolved = Path.Combine (runtime.RuntimeDir, "Facades", reference); 80 | if (File.Exists (resolved)) { 81 | return resolved; 82 | } 83 | } 84 | 85 | return reference; 86 | } 87 | 88 | /// 89 | /// Compiles the file. 90 | /// 91 | /// The file. 92 | /// Arguments. 93 | /// Token. 94 | public override async Task CompileFile (CodeCompilerArguments arguments, TextWriter log, CancellationToken token) 95 | { 96 | var asmFileNames = new HashSet ( 97 | arguments.AssemblyReferences.Select (Path.GetFileName), 98 | StringComparer.OrdinalIgnoreCase 99 | ); 100 | 101 | string rspPath; 102 | StreamWriter rsp; 103 | if (arguments.TempDirectory != null) { 104 | rspPath = Path.Combine (arguments.TempDirectory, "response.rsp"); 105 | rsp = File.CreateText (rspPath); 106 | } else { 107 | rsp = CreateTempTextFile (".rsp", out rspPath); 108 | } 109 | 110 | using (rsp) { 111 | rsp.WriteLine ("-target:library"); 112 | 113 | if (arguments.Debug) { 114 | rsp.WriteLine ("-debug"); 115 | } 116 | 117 | void AddIfNotPresent (string asm) 118 | { 119 | if (!asmFileNames.Contains (asm)) { 120 | rsp.Write ("\"-r:"); 121 | rsp.Write (Path.Combine (runtime.RuntimeDir, asm)); 122 | rsp.WriteLine ("\""); 123 | } 124 | } 125 | AddIfNotPresent ("mscorlib.dll"); 126 | 127 | if (runtime.Kind == RuntimeKind.NetCore) { 128 | AddIfNotPresent ("netstandard.dll"); 129 | AddIfNotPresent ("System.Runtime.dll"); 130 | //because we're referencing the impl not the ref asms, we end up 131 | //having to ref internals 132 | AddIfNotPresent ("System.Private.CoreLib.dll"); 133 | } 134 | 135 | foreach (var reference in arguments.AssemblyReferences) { 136 | rsp.Write ("-r:"); 137 | rsp.Write ("\""); 138 | rsp.Write (ResolveAssembly (runtime, reference)); 139 | rsp.WriteLine ("\""); 140 | } 141 | 142 | rsp.Write ("-out:"); 143 | rsp.Write ("\""); 144 | rsp.Write (arguments.OutputPath); 145 | rsp.WriteLine ("\""); 146 | 147 | //in older versions of csc, these must come last 148 | foreach (var file in arguments.SourceFiles) { 149 | rsp.Write ("\""); 150 | rsp.Write (file); 151 | rsp.WriteLine ("\""); 152 | } 153 | } 154 | 155 | var psi = new System.Diagnostics.ProcessStartInfo (runtime.CscPath) { 156 | Arguments = $"-nologo -noconfig \"@{rspPath}\" {arguments.AdditionalArguments}", 157 | CreateNoWindow = true, 158 | RedirectStandardOutput = true, 159 | RedirectStandardError = true, 160 | UseShellExecute = false 161 | }; 162 | 163 | if (log != null) { 164 | log.WriteLine ($"{psi.FileName} {psi.Arguments}"); 165 | } 166 | 167 | if (runtime.Kind == RuntimeKind.NetCore) { 168 | psi.Arguments = $"\"{psi.FileName}\" {psi.Arguments}"; 169 | psi.FileName = Path.GetFullPath (Path.Combine (runtime.RuntimeDir, "..", "..", "..", "dotnet")); 170 | } 171 | 172 | var stdout = new StringWriter (); 173 | var stderr = new StringWriter (); 174 | 175 | TextWriter outWriter = stderr, errWriter = stderr; 176 | if (log != null) { 177 | outWriter = new SplitOutputWriter (log, outWriter); 178 | errWriter = new SplitOutputWriter (log, errWriter); 179 | } 180 | 181 | var process = ProcessUtils.StartProcess (psi, outWriter, errWriter, token); 182 | 183 | var result = await process; 184 | 185 | var outputList = new List (); 186 | var errors = new List (); 187 | 188 | void ConsumeOutput (string s) 189 | { 190 | using (var sw = new StringReader (s)) { 191 | string line; 192 | while ((line = sw.ReadLine ()) != null) { 193 | outputList.Add (line); 194 | var err = MSBuildErrorParser.TryParseLine (line); 195 | if (err != null) { 196 | errors.Add (err); 197 | } 198 | } 199 | } 200 | } 201 | 202 | ConsumeOutput (stdout.ToString ()); 203 | ConsumeOutput (stderr.ToString ()); 204 | 205 | if (log != null) { 206 | log.WriteLine ($"{psi.FileName} {psi.Arguments}"); 207 | } 208 | 209 | return new CodeCompilerResult { 210 | Success = result == 0, 211 | Errors = errors, 212 | ExitCode = result, 213 | Output = outputList, 214 | ResponseFile = rspPath 215 | }; 216 | } 217 | 218 | //we know that ProcessUtils.StartProcess only uses WriteLine and Write(string) 219 | class SplitOutputWriter : TextWriter 220 | { 221 | readonly TextWriter a; 222 | readonly TextWriter b; 223 | 224 | public SplitOutputWriter (TextWriter a, TextWriter b) 225 | { 226 | this.a = a; 227 | this.b = b; 228 | } 229 | 230 | public override Encoding Encoding => Encoding.UTF8; 231 | 232 | public override void WriteLine () 233 | { 234 | a.WriteLine (); 235 | b.WriteLine (); 236 | } 237 | 238 | public override void Write (string value) 239 | { 240 | a.Write (value); 241 | b.Write (value); 242 | } 243 | } 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.CodeCompilation/CscCodeCompiler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a7324f90b0b75cf4ab0a1be0189e08e3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.CodeCompilation/MSBuildErrorParser.cs: -------------------------------------------------------------------------------- 1 | // 2 | // MSBuildErrorParser.cs: Parser for MSBuild-format error messages. 3 | // 4 | // Author: 5 | // Mikayla Hutchinson (m.j.hutchinson@gmail.com) 6 | // 7 | // Copyright 2014 Xamarin Inc. (http://www.xamarin.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining 10 | // a copy of this software and associated documentation files (the 11 | // "Software"), to deal in the Software without restriction, including 12 | // without limitation the rights to use, copy, modify, merge, publish, 13 | // distribute, sublicense, and/or sell copies of the Software, and to 14 | // permit persons to whom the Software is furnished to do so, subject to 15 | // the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | 28 | using System; 29 | 30 | namespace Mono.TextTemplating.CodeCompilation 31 | { 32 | class CodeCompilerError 33 | { 34 | public string Origin { get; set; } 35 | public int Line { get; set; } 36 | public int Column { get; set; } 37 | public int EndLine { get; set; } 38 | public int EndColumn { get; set; } 39 | public string Subcategory { get; set; } 40 | public bool IsError { get; set; } 41 | public string Code { get; set; } 42 | public string Message { get; set; } 43 | } 44 | 45 | //originally from mono/mcs/class/Microsoft.Build.Utilities/Microsoft.Build.Utilities/MSBuildErrorParser.cs 46 | //with many edits via monodevelop/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/MSBuildErrorParser.cs 47 | //see MonoDevelop repo for unit tests 48 | static class MSBuildErrorParser 49 | { 50 | // Parses single-line error message in the standard MSBuild error format: 51 | // 52 | // [origin[(position)]:][subcategory] category code: [message] 53 | // 54 | // Components in [] square brackets are optional. 55 | // Components are as follows: 56 | // origin: tool name or filename, may contain whitespace, no colons except the drive letter 57 | // position: line/col position or range in the file, with one of the following forms: 58 | // (l), (l,c), (l,c-c), (l,c,l,c) 59 | // subcategory: arbitrary text, may contain whitepsace 60 | // code: error code, no whietspace or punctuation 61 | // message: arbitrary text, no restrictions 62 | // 63 | public static CodeCompilerError TryParseLine (string line) 64 | { 65 | int originEnd, originStart = 0; 66 | var result = new CodeCompilerError (); 67 | 68 | MoveNextNonSpace (line, ref originStart); 69 | 70 | if (originStart >= line.Length) 71 | return null; 72 | 73 | //find the origin section 74 | //the filename may include a colon for Windows drive e.g. C:\foo, so ignore colon in first 2 chars 75 | if (line [originStart] != ':') { 76 | if (originStart + 2 >= line.Length) 77 | return null; 78 | 79 | if ((originEnd = line.IndexOf (':', originStart + 2) - 1) < 0) 80 | return null; 81 | } else { 82 | originEnd = originStart; 83 | } 84 | 85 | int categoryStart = originEnd + 2; 86 | 87 | if (categoryStart > line.Length) 88 | return null; 89 | 90 | MovePrevNonSpace (line, ref originEnd); 91 | 92 | //if there is no origin section, then we can't parse the message 93 | if (originEnd < 0 || originEnd < originStart) 94 | return null; 95 | 96 | //find the category section, if there is one 97 | MoveNextNonSpace (line, ref categoryStart); 98 | 99 | int categoryEnd = line.IndexOf (':', categoryStart) - 1; 100 | int messageStart = categoryEnd + 2; 101 | 102 | if (categoryEnd >= 0) { 103 | MovePrevNonSpace (line, ref categoryEnd); 104 | if (categoryEnd <= categoryStart) 105 | categoryEnd = -1; 106 | } 107 | 108 | //if there is a category section and it parses 109 | if (categoryEnd > 0 && ParseCategory (line, categoryStart, categoryEnd, result)) { 110 | //then parse the origin section 111 | if (originEnd > originStart && !ParseOrigin (line, originStart, originEnd, result)) 112 | return null; 113 | } else { 114 | //there is no origin, parse the origin section as if it were the category 115 | if (!ParseCategory (line, originStart, originEnd, result)) 116 | return null; 117 | messageStart = categoryStart; 118 | } 119 | 120 | //read the remaining message 121 | MoveNextNonSpace (line, ref messageStart); 122 | int messageEnd = line.Length - 1; 123 | MovePrevNonSpace (line, ref messageEnd, messageStart); 124 | if (messageEnd > messageStart) { 125 | result.Message = line.Substring (messageStart, messageEnd - messageStart + 1); 126 | } else { 127 | result.Message = ""; 128 | } 129 | 130 | return result; 131 | } 132 | 133 | // filename (line,col) | tool : 134 | static bool ParseOrigin (string line, int start, int end, CodeCompilerError result) 135 | { 136 | // no line/col 137 | if (line [end] != ')') { 138 | result.Origin = line.Substring (start, end - start + 1); 139 | return true; 140 | } 141 | 142 | //scan back for matching (, assuming at least one char between them 143 | int posStart = line.LastIndexOf ('(', end - 2, end - start - 1); 144 | if (posStart < 0) 145 | return false; 146 | 147 | if (!ParsePosition (line, posStart + 1, end, result)) { 148 | result.Origin = line.Substring (start, end - start + 1); 149 | return true; 150 | } 151 | 152 | end = posStart - 1; 153 | MovePrevNonSpace (line, ref end, start); 154 | 155 | //if there's an origin, capture it 156 | if (end >= start) { 157 | result.Origin = line.Substring (start, end - start + 1); 158 | } 159 | return true; 160 | } 161 | 162 | static bool ParseLineColVal (string str, out int val) 163 | { 164 | try { 165 | val = int.Parse (str); 166 | return true; 167 | } 168 | catch (OverflowException) { 169 | val = 0; 170 | return true; 171 | } 172 | catch (FormatException) { 173 | val = 0; 174 | return false; 175 | } 176 | } 177 | 178 | // Supported combos: 179 | // 180 | // (SL,SC,EL,EC) 181 | // (SL,SC-EC) 182 | // (SL-EL) 183 | // (SL,SC) 184 | // (SL) 185 | // 186 | // Unexpected patterns of commas/dashes abort parsing, discarding all values. 187 | // Any other characters abort parsing and the (...) gets treated as pert of the filename. 188 | // Overflows are silently treated as zeroes. 189 | // 190 | static bool ParsePosition (string str, int start, int end, CodeCompilerError result) 191 | { 192 | int line = 0, col = 0, endLine = 0, endCol = 0; 193 | 194 | var a = str.Substring (start, end - start).Split (','); 195 | 196 | if (a.Length > 4 || a.Length == 3) 197 | return true; 198 | 199 | if (a.Length == 4) { 200 | bool valid = 201 | ParseLineColVal (a [0], out line) && 202 | ParseLineColVal (a [1], out col) && 203 | ParseLineColVal (a [2], out endLine) && 204 | ParseLineColVal (a [3], out endCol); 205 | if (!valid) 206 | return false; 207 | } else { 208 | var b = a [0].Split ('-'); 209 | if (b.Length > 2) 210 | return true; 211 | if (!ParseLineColVal (b [0], out line)) 212 | return false; 213 | if (b.Length == 2) { 214 | if (a.Length == 2) 215 | return true; 216 | if (!ParseLineColVal (b [1], out endLine)) 217 | return false; 218 | } 219 | if (a.Length == 2) { 220 | var c = a [1].Split ('-'); 221 | if (c.Length > 2) 222 | return true; 223 | if (!ParseLineColVal (c [0], out col)) 224 | return false; 225 | if (c.Length == 2) { 226 | if (!ParseLineColVal (c [1], out endCol)) 227 | return false; 228 | } 229 | } 230 | } 231 | 232 | result.Line = line; 233 | result.Column = col; 234 | result.EndLine = endLine; 235 | result.EndColumn = endCol; 236 | return true; 237 | } 238 | 239 | static bool ParseCategory (string line, int start, int end, CodeCompilerError result) 240 | { 241 | int idx = end; 242 | MovePrevWordStart (line, ref idx, start); 243 | if (idx < start + 1) 244 | return false; 245 | 246 | string code = line.Substring (idx, end - idx + 1); 247 | 248 | idx--; 249 | MovePrevNonSpace (line, ref idx, start); 250 | end = idx; 251 | MovePrevWordStart (line, ref idx, start); 252 | if (idx < start) 253 | return false; 254 | 255 | string category = line.Substring (idx, end - idx + 1); 256 | if (string.Equals (category, "error", StringComparison.OrdinalIgnoreCase)) 257 | result.IsError = true; 258 | else if (!string.Equals (category, "warning", StringComparison.OrdinalIgnoreCase)) 259 | return false; 260 | 261 | result.Code = code; 262 | 263 | idx--; 264 | if (idx > start) { 265 | MovePrevNonSpace (line, ref idx, start); 266 | result.Subcategory = line.Substring (start, idx - start + 1); 267 | } else { 268 | result.Subcategory = ""; 269 | } 270 | 271 | return true; 272 | } 273 | 274 | static void MoveNextNonSpace (string s, ref int idx) 275 | { 276 | while (idx < s.Length && char.IsWhiteSpace (s [idx])) 277 | idx++; 278 | } 279 | 280 | static void MovePrevNonSpace (string s, ref int idx, int min = 0) 281 | { 282 | while (idx > min && char.IsWhiteSpace (s [idx])) 283 | idx--; 284 | } 285 | 286 | static void MovePrevWordStart (string s, ref int idx, int min = 0) 287 | { 288 | while (idx > min && char.IsLetterOrDigit (s [idx - 1])) 289 | idx--; 290 | } 291 | } 292 | } -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.CodeCompilation/MSBuildErrorParser.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cfa7f8ae6d8dd034a8d0948291cb26b1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.CodeCompilation/ProcessUtils.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessUtils.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // Jérémie Laval 7 | // 8 | // Copyright (c) 2012 Xamarin, Inc. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in 18 | // all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | // THE SOFTWARE. 27 | 28 | using System; 29 | using System.IO; 30 | using System.Diagnostics; 31 | using System.Threading; 32 | using System.Threading.Tasks; 33 | 34 | namespace Mono.TextTemplating.CodeCompilation 35 | { 36 | // there are many divergent copies of this file floating around; this particular 37 | // one comes from monodevelop/main/tests/ui/MonoDevelop.UserInterfaceTesting/MonoDevelop.UserInterfaceTesting/ProcessUtils.cs 38 | static class ProcessUtils 39 | { 40 | public static Task StartProcess (ProcessStartInfo psi, TextWriter stdout, TextWriter stderr, CancellationToken cancellationToken) 41 | { 42 | var tcs = new TaskCompletionSource (); 43 | if (cancellationToken.CanBeCanceled && cancellationToken.IsCancellationRequested) { 44 | tcs.TrySetCanceled (); 45 | return tcs.Task; 46 | } 47 | 48 | psi.UseShellExecute = false; 49 | psi.RedirectStandardOutput |= stdout != null; 50 | psi.RedirectStandardError |= stderr != null; 51 | 52 | var p = Process.Start (psi); 53 | 54 | if (cancellationToken.CanBeCanceled) { 55 | cancellationToken.Register (() => { 56 | try { 57 | if (!p.HasExited) { 58 | p.Kill (); 59 | } 60 | } catch (InvalidOperationException ex) { 61 | if (ex.Message.IndexOf ("already exited", StringComparison.Ordinal) < 0) 62 | throw; 63 | } 64 | }); 65 | } 66 | 67 | bool outputDone = false; 68 | bool errorDone = false; 69 | bool exitDone = false; 70 | 71 | p.EnableRaisingEvents = true; 72 | if (psi.RedirectStandardOutput) { 73 | bool stdOutInitialized = false; 74 | p.OutputDataReceived += (sender, e) => { 75 | try { 76 | if (e.Data == null) { 77 | outputDone = true; 78 | if (exitDone && errorDone) 79 | tcs.TrySetResult (p.ExitCode); 80 | return; 81 | } 82 | 83 | if (stdOutInitialized) 84 | stdout.WriteLine (); 85 | stdout.Write (e.Data); 86 | stdOutInitialized = true; 87 | } catch (Exception ex) { 88 | tcs.TrySetException (ex); 89 | } 90 | }; 91 | p.BeginOutputReadLine (); 92 | } else { 93 | outputDone = true; 94 | } 95 | 96 | if (psi.RedirectStandardError) { 97 | bool stdErrInitialized = false; 98 | p.ErrorDataReceived += (sender, e) => { 99 | try { 100 | if (e.Data == null) { 101 | errorDone = true; 102 | if (exitDone && outputDone) 103 | tcs.TrySetResult (p.ExitCode); 104 | return; 105 | } 106 | 107 | if (stdErrInitialized) 108 | stderr.WriteLine (); 109 | stderr.Write (e.Data); 110 | stdErrInitialized = true; 111 | } catch (Exception ex) { 112 | tcs.TrySetException (ex); 113 | } 114 | }; 115 | p.BeginErrorReadLine (); 116 | } else { 117 | errorDone = true; 118 | } 119 | 120 | p.Exited += (sender, e) => { 121 | exitDone = true; 122 | if (errorDone && outputDone) 123 | tcs.TrySetResult (p.ExitCode); 124 | }; 125 | 126 | return tcs.Task; 127 | } 128 | } 129 | } -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.CodeCompilation/ProcessUtils.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bbdab2a38c7a41e46a7f437f61a1b03d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs: -------------------------------------------------------------------------------- 1 | // 2 | // FrameworkHelpers.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2018 Microsoft Corp 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.IO; 29 | using System.Linq; 30 | 31 | namespace Mono.TextTemplating.CodeCompilation 32 | { 33 | enum RuntimeKind 34 | { 35 | NetCore, 36 | NetFramework, 37 | Mono 38 | } 39 | 40 | class RuntimeInfo 41 | { 42 | RuntimeInfo (RuntimeKind kind) => Kind = kind; 43 | 44 | static RuntimeInfo FromError (RuntimeKind kind, string error) => new RuntimeInfo (kind) { Error = error }; 45 | 46 | public RuntimeKind Kind { get; private set; } 47 | public string Error { get; private set; } 48 | public string RuntimeDir { get; private set; } 49 | public string CscPath { get; private set; } 50 | public bool IsValid => Error == null; 51 | 52 | public static RuntimeInfo GetRuntime () 53 | { 54 | var monoFx = GetMonoRuntime (); 55 | if (monoFx.IsValid) { 56 | return monoFx; 57 | } 58 | var netFx = GetNetFrameworkRuntime (); 59 | if (netFx.IsValid) { 60 | return netFx; 61 | } 62 | var coreFx = GetDotNetCoreRuntime (); 63 | if (coreFx.IsValid) { 64 | return coreFx; 65 | } 66 | return FromError (RuntimeKind.Mono, "Could not find any valid runtime" ); 67 | } 68 | 69 | public static RuntimeInfo GetMonoRuntime () 70 | { 71 | if (Type.GetType ("Mono.Runtime") == null) { 72 | return FromError (RuntimeKind.Mono, "Current runtime is not Mono" ); 73 | } 74 | 75 | var runtimeDir = Path.GetDirectoryName (typeof (int).Assembly.Location); 76 | var csc = Path.Combine (runtimeDir, "csc.exe"); 77 | if (!File.Exists (csc)) { 78 | return FromError (RuntimeKind.Mono, "Could not find csc in host Mono installation" ); 79 | } 80 | 81 | return new RuntimeInfo (RuntimeKind.Mono) { 82 | CscPath = csc, 83 | RuntimeDir = runtimeDir 84 | }; 85 | } 86 | 87 | public static RuntimeInfo GetNetFrameworkRuntime () 88 | { 89 | var runtimeDir = Path.GetDirectoryName (typeof (int).Assembly.Location); 90 | var csc = Path.Combine (runtimeDir, "csc.exe"); 91 | if (!File.Exists (csc)) { 92 | return FromError (RuntimeKind.NetFramework, "Could not find csc in host .NET Framework installation"); 93 | } 94 | return new RuntimeInfo (RuntimeKind.NetFramework) { 95 | CscPath = csc, 96 | RuntimeDir = runtimeDir 97 | }; 98 | } 99 | 100 | static string FindDotNetRoot () 101 | { 102 | string dotnetRoot; 103 | bool DotnetRootIsValid () => !string.IsNullOrEmpty (dotnetRoot) && (File.Exists (Path.Combine (dotnetRoot, "dotnet")) || File.Exists (Path.Combine (dotnetRoot, "dotnet.exe"))); 104 | 105 | string FindInPath (string name) => (Environment.GetEnvironmentVariable ("PATH") ?? "") 106 | .Split (new [] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries) 107 | .Select (p => Path.Combine (p, name)) 108 | .FirstOrDefault (File.Exists); 109 | 110 | dotnetRoot = Environment.GetEnvironmentVariable ("DOTNET_ROOT"); 111 | if (DotnetRootIsValid ()) { 112 | return dotnetRoot; 113 | } 114 | 115 | // this should get us something like /usr/local/share/dotnet/shared/Microsoft.NETCore.App/2.1.2/System.Runtime.dll 116 | var runtimeDir = Path.GetDirectoryName (typeof (int).Assembly.Location); 117 | dotnetRoot = Path.GetDirectoryName (Path.GetDirectoryName (Path.GetDirectoryName (runtimeDir))); 118 | 119 | if (DotnetRootIsValid ()) { 120 | return dotnetRoot; 121 | } 122 | 123 | dotnetRoot = Path.GetDirectoryName (FindInPath (Path.DirectorySeparatorChar == '\\' ? "dotnet.exe" : "dotnet")); 124 | if (DotnetRootIsValid ()) { 125 | return dotnetRoot; 126 | } 127 | 128 | return null; 129 | } 130 | 131 | static string FindHighestVersionedDirectory (string parentFolder, Func validate) 132 | { 133 | string bestMatch = null; 134 | var bestVersion = new Version(0, 0, 0); 135 | foreach (var dir in Directory.EnumerateDirectories (parentFolder)) { 136 | var name = Path.GetFileName (dir); 137 | if (Version.TryParse (name, out var version) && version.Build >= 0) { 138 | if (version > bestVersion && (validate == null || validate (dir))) { 139 | bestVersion = version; 140 | bestMatch = dir; 141 | } 142 | } 143 | } 144 | return bestMatch; 145 | } 146 | 147 | public static RuntimeInfo GetDotNetCoreRuntime () 148 | { 149 | var dotnetRoot = FindDotNetRoot (); 150 | if (dotnetRoot == null) { 151 | return FromError (RuntimeKind.NetCore, "Could not find .NET Core installation" ); 152 | } 153 | 154 | string MakeCscPath (string d) => Path.Combine (d, "Roslyn", "bincore", "csc.dll"); 155 | var sdkDir = FindHighestVersionedDirectory (Path.Combine (dotnetRoot, "sdk"), d => File.Exists (MakeCscPath (d))); 156 | if (sdkDir == null) { 157 | return FromError (RuntimeKind.NetCore, "Could not find csc.dll in any .NET Core SDK" ); 158 | } 159 | 160 | var runtimeDir = FindHighestVersionedDirectory (Path.Combine (dotnetRoot, "shared", "Microsoft.NETCore.App"), d => File.Exists (Path.Combine (d, "System.Runtime.dll"))); 161 | if (runtimeDir == null) { 162 | return FromError (RuntimeKind.NetCore, "Could not find System.Runtime.dll in any .NET shared runtime" ); 163 | } 164 | 165 | return new RuntimeInfo (RuntimeKind.NetCore) { RuntimeDir = runtimeDir, CscPath = MakeCscPath (sdkDir) }; 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.CodeCompilation/RuntimeInfo.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 257390ff10db05f4fb7664e5c6e50862 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cbb96be9bf8bc184f96da4cc0e4a8b05 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/CompiledTemplate.cs: -------------------------------------------------------------------------------- 1 | // 2 | // CompiledTemplate.cs 3 | // 4 | // Author: 5 | // Nathan Baulch 6 | // 7 | // Copyright (c) 2009 Nathan Baulch 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Reflection; 29 | using Microsoft.VisualStudio.TextTemplating; 30 | using System.CodeDom.Compiler; 31 | using System.Globalization; 32 | using System.Collections.Generic; 33 | 34 | namespace Mono.TextTemplating 35 | { 36 | public sealed class CompiledTemplate : 37 | #if FEATURE_APPDOMAINS 38 | MarshalByRefObject, 39 | #endif 40 | IDisposable 41 | { 42 | ITextTemplatingEngineHost host; 43 | object textTransformation; 44 | readonly CultureInfo culture; 45 | readonly string [] assemblyFiles; 46 | 47 | public CompiledTemplate (ITextTemplatingEngineHost host, CompilerResults results, string fullName, CultureInfo culture, 48 | string [] assemblyFiles) 49 | { 50 | #if FEATURE_APPDOMAINS 51 | AppDomain.CurrentDomain.AssemblyResolve += ResolveReferencedAssemblies; 52 | #endif 53 | this.host = host; 54 | this.culture = culture; 55 | this.assemblyFiles = assemblyFiles; 56 | Load (results, fullName); 57 | } 58 | 59 | void Load (CompilerResults results, string fullName) 60 | { 61 | //results.CompiledAssembly doesn't work on .NET core, it throws a cryptic internal error 62 | //use Assembly.LoadFile instead 63 | var assembly = System.Reflection.Assembly.LoadFile (results.PathToAssembly); 64 | Type transformType = assembly.GetType (fullName); 65 | //MS Templating Engine does not look on the type itself, 66 | //it checks only that required methods are exists in the compiled type 67 | textTransformation = Activator.CreateInstance (transformType); 68 | 69 | //set the host property if it exists 70 | Type hostType = null; 71 | var gen = host as TemplateGenerator; 72 | if (gen != null) { 73 | hostType = gen.SpecificHostType; 74 | } 75 | var hostProp = transformType.GetProperty ("Host", hostType ?? typeof (ITextTemplatingEngineHost)); 76 | if (hostProp != null && hostProp.CanWrite) 77 | hostProp.SetValue (textTransformation, host, null); 78 | 79 | var sessionHost = host as ITextTemplatingSessionHost; 80 | if (sessionHost != null) { 81 | //FIXME: should we create a session if it's null? 82 | var sessionProp = transformType.GetProperty ("Session", typeof (IDictionary)); 83 | sessionProp.SetValue (textTransformation, sessionHost.Session, null); 84 | } 85 | } 86 | 87 | public string Process () 88 | { 89 | var ttType = textTransformation.GetType (); 90 | 91 | var errorProp = ttType.GetProperty ("Errors", BindingFlags.Instance | BindingFlags.NonPublic); 92 | if (errorProp == null) 93 | throw new ArgumentException ("Template must have 'Errors' property"); 94 | var errorMethod = ttType.GetMethod ("Error", new Type [] { typeof (string) }); 95 | if (errorMethod == null) { 96 | throw new ArgumentException ("Template must have 'Error(string message)' method"); 97 | } 98 | 99 | var errors = (CompilerErrorCollection)errorProp.GetValue (textTransformation, null); 100 | errors.Clear (); 101 | 102 | //set the culture 103 | if (culture != null) 104 | ToStringHelper.FormatProvider = culture; 105 | else 106 | ToStringHelper.FormatProvider = CultureInfo.InvariantCulture; 107 | 108 | string output = null; 109 | 110 | var initMethod = ttType.GetMethod ("Initialize"); 111 | var transformMethod = ttType.GetMethod ("TransformText"); 112 | 113 | if (initMethod == null) { 114 | errorMethod.Invoke (textTransformation, new object [] { "Error running transform: no method Initialize()" }); 115 | } else if (transformMethod == null) { 116 | errorMethod.Invoke (textTransformation, new object [] { "Error running transform: no method TransformText()" }); 117 | } else try { 118 | initMethod.Invoke (textTransformation, null); 119 | output = (string)transformMethod.Invoke (textTransformation, null); 120 | } catch (Exception ex) { 121 | errorMethod.Invoke (textTransformation, new object [] { "Error running transform: " + ex }); 122 | } 123 | 124 | host.LogErrors (errors); 125 | 126 | ToStringHelper.FormatProvider = CultureInfo.InvariantCulture; 127 | return output; 128 | } 129 | 130 | 131 | Assembly ResolveReferencedAssemblies (object sender, ResolveEventArgs args) 132 | { 133 | AssemblyName asmName = new AssemblyName (args.Name); 134 | foreach (var asmFile in assemblyFiles) { 135 | if (asmName.Name == System.IO.Path.GetFileNameWithoutExtension (asmFile)) 136 | return Assembly.LoadFrom (asmFile); 137 | } 138 | 139 | var path = host.ResolveAssemblyReference (asmName.Name + ".dll"); 140 | if (System.IO.File.Exists (path)) 141 | return Assembly.LoadFrom (path); 142 | 143 | return null; 144 | } 145 | 146 | public void Dispose () 147 | { 148 | #if FEATURE_APPDOMAINS 149 | if (host != null) { 150 | host = null; 151 | AppDomain.CurrentDomain.AssemblyResolve -= ResolveReferencedAssemblies; 152 | } 153 | #endif 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/CompiledTemplate.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9f589ada2fabff6498c7a32a0a05118b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/CrossAppDomainAssemblyResolver.cs: -------------------------------------------------------------------------------- 1 | // 2 | // CrossAppDomainAssemblyResolver.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2010 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | 29 | #if FEATURE_APPDOMAINS 30 | 31 | namespace Mono.TextTemplating 32 | { 33 | /// 34 | /// Provides a handler for AssemblyResolve events that looks them up in the domain that created the resolver. 35 | /// 36 | [Serializable] 37 | public class CrossAppDomainAssemblyResolver 38 | { 39 | readonly ParentDomainLookup parent = new ParentDomainLookup (); 40 | 41 | public System.Reflection.Assembly Resolve (object sender, ResolveEventArgs args) 42 | { 43 | var location = parent.GetAssemblyPath (args.Name); 44 | if (location != null) 45 | return System.Reflection.Assembly.LoadFrom (location); 46 | return null; 47 | } 48 | 49 | class ParentDomainLookup : MarshalByRefObject 50 | { 51 | public string GetAssemblyPath (string name) 52 | { 53 | var assem = System.Reflection.Assembly.Load (name); 54 | if (assem != null) 55 | return assem.Location; 56 | return null; 57 | } 58 | } 59 | } 60 | } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/CrossAppDomainAssemblyResolver.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7eb63e3054ca9dc43b7b4dba39e1f73b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/FileUtil.cs: -------------------------------------------------------------------------------- 1 | // 2 | // FileUtil.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2013 Xamarin Inc. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | using System; 27 | using System.IO; 28 | 29 | namespace Mono.TextTemplating 30 | { 31 | static class FileUtil 32 | { 33 | //from MonoDevelop.Core.FileService, copied here so Mono.TextTemplating can be used w/o MD dependency 34 | public static string AbsoluteToRelativePath (string baseDirectoryPath, string absPath) 35 | { 36 | var fileUri = new Uri(absPath); 37 | var referenceUri = new Uri(baseDirectoryPath); 38 | return Uri.UnescapeDataString(referenceUri.MakeRelativeUri(fileUri).ToString()).Replace('/', Path.DirectorySeparatorChar); 39 | } 40 | 41 | static bool IsSeparator (char ch) 42 | { 43 | return ch == Path.DirectorySeparatorChar || ch == Path.AltDirectorySeparatorChar || ch == Path.VolumeSeparatorChar; 44 | } 45 | 46 | static string GetFullPath (string path) 47 | { 48 | if (path == null) 49 | throw new ArgumentNullException ("path"); 50 | if (!isWindows || path.IndexOf ('*') == -1) 51 | return Path.GetFullPath (path); 52 | else { 53 | // On Windows, GetFullPath doesn't work if the path contains wildcards. 54 | path = path.Replace ("*", wildcardMarker); 55 | path = Path.GetFullPath (path); 56 | return path.Replace (wildcardMarker, "*"); 57 | } 58 | } 59 | 60 | static readonly string wildcardMarker = "_" + Guid.NewGuid () + "_"; 61 | static readonly bool isWindows = Path.DirectorySeparatorChar == '\\'; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/FileUtil.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 16d6518098fbcdd4c9be5c7701b4f8b3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/ParsedTemplate.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2be1f22a52a7e5247928c48d4f3ed5c6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/RecyclableAppDomain.cs: -------------------------------------------------------------------------------- 1 | // 2 | // RecyclableAppDomain.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2009 Novell, Inc. (http://www.novell.com) 8 | // Copyright (c) 2012 Xamarin Inc. (http://xamarin.com_ 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in 18 | // all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | // THE SOFTWARE. 27 | 28 | using System; 29 | using System.Collections.Generic; 30 | 31 | #if FEATURE_APPDOMAINS 32 | 33 | namespace Mono.TextTemplating 34 | { 35 | public class TemplatingAppDomainRecycler 36 | { 37 | const int DEFAULT_TIMEOUT_MS = 2 * 60 * 1000; 38 | const int DEFAULT_MAX_USES = 20; 39 | 40 | readonly string name; 41 | readonly object lockObj = new object (); 42 | 43 | RecyclableAppDomain domain; 44 | 45 | public TemplatingAppDomainRecycler (string name) 46 | { 47 | this.name = name; 48 | } 49 | 50 | public TemplatingAppDomainRecycler.Handle GetHandle () 51 | { 52 | lock (lockObj) { 53 | if (domain == null || domain.Domain == null || domain.UnusedHandles == 0) { 54 | domain = new RecyclableAppDomain (name); 55 | } 56 | return domain.GetHandle (); 57 | } 58 | } 59 | 60 | internal class RecyclableAppDomain 61 | { 62 | //TODO: implement timeout based recycling 63 | //DateTime lastUsed; 64 | 65 | AppDomain domain; 66 | DomainAssemblyLoader assemblyMap; 67 | 68 | int liveHandles; 69 | int unusedHandles = DEFAULT_MAX_USES; 70 | 71 | public RecyclableAppDomain (string name) 72 | { 73 | var info = new AppDomainSetup () { 74 | //appbase needs to allow loading this assembly, for remoting 75 | ApplicationBase = System.IO.Path.GetDirectoryName (typeof (TemplatingAppDomainRecycler).Assembly.Location), 76 | DisallowBindingRedirects = false, 77 | DisallowCodeDownload = true, 78 | DisallowApplicationBaseProbing = false, 79 | ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile, 80 | }; 81 | domain = AppDomain.CreateDomain (name, null, info); 82 | var t = typeof(DomainAssemblyLoader); 83 | AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; 84 | assemblyMap = (DomainAssemblyLoader) domain.CreateInstanceFromAndUnwrap(t.Assembly.Location, t.FullName); 85 | AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve; 86 | domain.AssemblyResolve += assemblyMap.Resolve;// new DomainAssemblyLoader(assemblyMap).Resolve; 87 | } 88 | 89 | System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 90 | { 91 | var a = typeof(RecyclableAppDomain).Assembly; 92 | if (args.Name == a.FullName) 93 | return a; 94 | return null; 95 | } 96 | 97 | public int UnusedHandles { get { return unusedHandles; } } 98 | public int LiveHandles { get { return liveHandles; } } 99 | public AppDomain Domain { get { return domain; } } 100 | 101 | public void AddAssembly (System.Reflection.Assembly assembly) 102 | { 103 | assemblyMap.Add (assembly.FullName, assembly.Location); 104 | } 105 | 106 | public Handle GetHandle () 107 | { 108 | lock (this) { 109 | if (unusedHandles <= 0) { 110 | throw new InvalidOperationException ("No handles left"); 111 | } 112 | unusedHandles--; 113 | liveHandles++; 114 | } 115 | return new Handle (this); 116 | } 117 | 118 | public void ReleaseHandle () 119 | { 120 | int lh; 121 | lock (this) { 122 | liveHandles--; 123 | lh = liveHandles; 124 | } 125 | //We must unload domain every time after using it for generation 126 | //Otherwise we could not load new version of the project-generated 127 | //assemblies into it. So remove checking for unusedHandles == 0 128 | if (lh == 0) { 129 | UnloadDomain (); 130 | } 131 | } 132 | 133 | void UnloadDomain () 134 | { 135 | AppDomain.Unload (domain); 136 | domain = null; 137 | assemblyMap = null; 138 | GC.SuppressFinalize (this); 139 | } 140 | 141 | ~RecyclableAppDomain () 142 | { 143 | if (liveHandles != 0) 144 | Console.WriteLine ("WARNING: recyclable AppDomain's handles were not all disposed"); 145 | } 146 | } 147 | 148 | public class Handle : IDisposable 149 | { 150 | RecyclableAppDomain parent; 151 | 152 | internal Handle (RecyclableAppDomain parent) 153 | { 154 | this.parent = parent; 155 | } 156 | 157 | public AppDomain Domain { 158 | get { return parent.Domain; } 159 | } 160 | 161 | public void Dispose () 162 | { 163 | if (parent == null) 164 | return; 165 | var p = parent; 166 | lock (this) { 167 | if (parent == null) 168 | return; 169 | parent = null; 170 | } 171 | p.ReleaseHandle (); 172 | } 173 | 174 | public void AddAssembly (System.Reflection.Assembly assembly) 175 | { 176 | parent.AddAssembly (assembly); 177 | } 178 | } 179 | 180 | [Serializable] 181 | class DomainAssemblyLoader : MarshalByRefObject 182 | { 183 | readonly Dictionary map = new Dictionary(); 184 | 185 | public DomainAssemblyLoader () 186 | { 187 | } 188 | 189 | public System.Reflection.Assembly Resolve (object sender, ResolveEventArgs args) 190 | { 191 | var assemblyFile = ResolveAssembly (args.Name); 192 | if (assemblyFile != null) 193 | return System.Reflection.Assembly.LoadFrom (assemblyFile); 194 | return null; 195 | } 196 | 197 | public string ResolveAssembly(string name) 198 | { 199 | string result; 200 | if (map.TryGetValue(name, out result)) 201 | return result; 202 | return null; 203 | } 204 | 205 | public void Add(string name, string location) 206 | { 207 | map[name] = location; 208 | } 209 | 210 | //keep this alive as long as the app domain is alive 211 | public override object InitializeLifetimeService () 212 | { 213 | return null; 214 | } 215 | } 216 | } 217 | } 218 | 219 | #endif -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/RecyclableAppDomain.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: da34de857715afd42ad71bfb964dce63 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/StringUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Mono.TextTemplating 4 | { 5 | public static class StringUtil 6 | { 7 | public static Boolean IsNullOrWhiteSpace (String value) 8 | { 9 | if (value == null) return true; 10 | 11 | for (int i = 0; i < value.Length; i++) { 12 | if (!Char.IsWhiteSpace (value[i])) return false; 13 | } 14 | 15 | return true; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/StringUtil.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 44f4092750832b14cbc18bd6ea706d77 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/TemplateGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2756d2870e5f69c4f8c82029e5d51b90 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/TemplateSettings.cs: -------------------------------------------------------------------------------- 1 | // 2 | // TemplateSettings.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2009 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Text; 29 | using System.Collections.Generic; 30 | using Microsoft.VisualStudio.TextTemplating; 31 | using System.IO; 32 | 33 | namespace Mono.TextTemplating 34 | { 35 | public class TemplateSettings 36 | { 37 | public TemplateSettings () 38 | { 39 | Imports = new HashSet (); 40 | Assemblies = new HashSet (); 41 | CustomDirectives = new List (); 42 | DirectiveProcessors = new Dictionary (); 43 | } 44 | 45 | public bool HostSpecific { get; set; } 46 | public bool HostPropertyOnBase { get; set; } 47 | public bool Debug { get; set; } 48 | public TextWriter Log { get; set; } 49 | public string Inherits { get; set; } 50 | public string Name { get; set; } 51 | public string Namespace { get; set; } 52 | public HashSet Imports { get; private set; } 53 | public HashSet Assemblies { get; private set; } 54 | public System.CodeDom.Compiler.CodeDomProvider Provider { get; set; } 55 | public string Language { get; set; } 56 | public string CompilerOptions { get; set; } 57 | public Encoding Encoding { get; set; } 58 | public string Extension { get; set; } 59 | public System.Globalization.CultureInfo Culture { get; set; } 60 | public List CustomDirectives { get; private set; } 61 | public Dictionary DirectiveProcessors { get; private set; } 62 | public bool IncludePreprocessingHelpers { get; set; } 63 | public bool IsPreprocessed { get; set; } 64 | public bool RelativeLinePragmas { get; set; } 65 | public bool NoLinePragmas { get; set; } 66 | public bool InternalVisibility { get; set; } 67 | public Type HostType { get; set; } 68 | public string GetFullName () => string.IsNullOrEmpty (Namespace) ? Name : Namespace + "." + Name; 69 | } 70 | 71 | public class CustomDirective 72 | { 73 | public CustomDirective (string processorName, Directive directive) 74 | { 75 | ProcessorName = processorName; 76 | Directive = directive; 77 | } 78 | 79 | public string ProcessorName { get; set; } 80 | public Directive Directive { get; set; } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/TemplateSettings.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 48d268d88ea35c742afa771264f47345 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/TemplatingEngine.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c7d42dce4afeb324f979311551e48741 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/Tokeniser.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d26faa62d56702f47ad5490f48ba8b9c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/Utf8.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Utf8.cs 3 | // 4 | // Author: 5 | // Atif Aziz 6 | // 7 | // Copyright (c) 2019 Atif Aziz 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System.Text; 28 | 29 | namespace Mono.TextTemplating 30 | { 31 | static class Utf8 32 | { 33 | public static Encoding BomlessEncoding = new UTF8Encoding (encoderShouldEmitUTF8Identifier: false); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Editor/TextTemplating/Mono.TextTemplating/Utf8.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 87f5bf73008b72b43b4a707c84fbd0a6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/UnityDataHost.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using FasterGames.T4.Runtime; 6 | using Mono.TextTemplating; 7 | using UnityEditor; 8 | using Object = UnityEngine.Object; 9 | 10 | namespace FasterGames.T4.Editor 11 | { 12 | /// 13 | /// Template generator with data hosting support 14 | /// 15 | /// user data type 16 | public class UnityDataHost : TemplateGenerator, IDataHost where TData : Object 17 | { 18 | /// 19 | /// Creates an instance using a runtime type 20 | /// 21 | /// data to host 22 | /// additional types to bring in 23 | /// Instance of host 24 | public static TemplateGenerator CreateInstance(object data, List additionalRuntimeTypes) 25 | { 26 | var dataHostType = typeof(UnityDataHost<>).MakeGenericType(new Type[] {data.GetType()}); 27 | 28 | return (TemplateGenerator) Activator.CreateInstance(dataHostType, new object[]{ data, additionalRuntimeTypes }); 29 | } 30 | 31 | /// 32 | /// Default ctor 33 | /// 34 | /// 35 | /// If your type pulls in non default-referenced types, you'll need to add them to 36 | /// 37 | /// data to host 38 | /// additional types to bring in 39 | public UnityDataHost(TData data, IEnumerable additionalRuntimeTypes) 40 | { 41 | var dataType = data.GetType(); 42 | 43 | Data = data; 44 | 45 | SafeAddRangeRef(new []{typeof(Object).Assembly.Location, typeof(IDataHost<>).Assembly.Location, dataType.Assembly.Location}); 46 | SafeAddRangeImport(new []{typeof(Object).Namespace, typeof(IDataHost<>).Namespace, dataType.Namespace}); 47 | 48 | foreach (var childType in ReflectionUtils.ChildTypes(dataType)) 49 | { 50 | SafeAddRef(childType.Assembly.Location); 51 | SafeAddImport(childType.Namespace); 52 | } 53 | 54 | foreach (var additionalType in additionalRuntimeTypes) 55 | { 56 | var typ = Type.GetType(additionalType); 57 | SafeAddRef(typ?.Assembly.Location); 58 | SafeAddImport(typ?.Namespace); 59 | } 60 | 61 | var apiCompatLevel = PlayerSettings.GetApiCompatibilityLevel(EditorUserBuildSettings.selectedBuildTargetGroup); 62 | if (apiCompatLevel == ApiCompatibilityLevel.NET_Standard_2_0) 63 | { 64 | // always add netstandard - if you're in an editor only assembly it's a no-op, and you need it for non-editor dlls 65 | var netStandardPath = Assembly.Load(new AssemblyName("netstandard")).Location; 66 | SafeAddRef(netStandardPath); 67 | } 68 | } 69 | 70 | /// 71 | public override Type SpecificHostType => typeof(UnityDataHost); 72 | 73 | /// 74 | public TData Data { get; private set; } 75 | 76 | /// 77 | /// Adds a ref, only if it won't cause any issues to the template generator 78 | /// 79 | /// ref to add 80 | private void SafeAddRef(string re) 81 | { 82 | if (string.IsNullOrWhiteSpace(re)) 83 | { 84 | return; 85 | } 86 | 87 | Refs.Add(re); 88 | } 89 | 90 | /// 91 | /// Adds refs, only if it won't cause any issues to the template generator 92 | /// 93 | /// refs to add 94 | private void SafeAddRangeRef(IEnumerable res) 95 | { 96 | Refs.AddRange(res.Where(r => !string.IsNullOrWhiteSpace(r))); 97 | } 98 | 99 | /// 100 | /// Adds an import, only if it won't cause any issues to the template generator 101 | /// 102 | /// import to add 103 | private void SafeAddImport(string import) 104 | { 105 | if (string.IsNullOrWhiteSpace(import)) 106 | { 107 | return; 108 | } 109 | 110 | Imports.Add(import); 111 | } 112 | 113 | /// 114 | /// Adds imports, only if it won't cause any issues to the template generator 115 | /// 116 | /// imports to add 117 | private void SafeAddRangeImport(IEnumerable imports) 118 | { 119 | Imports.AddRange(imports.Where(i => !string.IsNullOrWhiteSpace(i))); 120 | } 121 | } 122 | } -------------------------------------------------------------------------------- /Editor/UnityDataHost.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8e8b341d01e7431d8771cf61ebadbac7 3 | timeCreated: 1626810464 -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9071e72369aea40428658f9202c4e311 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # t4 2 | 3 | T4 text template generative importer for Unity3D. 📝🏗 4 | 5 | ![Project logo; A pink package on a grey background, next to the text "T4 Templates" in purple](./Documentation~/header.png) 6 | 7 | ![GitHub package.json version](https://img.shields.io/github/package-json/v/faster-games/t4) 8 | [![openupm](https://img.shields.io/npm/v/com.faster-games.t4?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/com.faster-games.t4/) 9 | [![CI](https://github.com/faster-games/t4/actions/workflows/main.yml/badge.svg)](https://github.com/faster-games/t4/actions/workflows/main.yml) 10 | [![Discord](https://img.shields.io/discord/862006447919726604)](https://discord.gg/QfQE6rWQqq) 11 | 12 | [T4 Text Templates](https://docs.microsoft.com/en-us/visualstudio/modeling/code-generation-and-t4-text-templates) provide a way to generate csharp code from templates, which are a mixture of text blocks and control logic. If you've ever used [Mushtache](http://mustache.github.io/mustache.5.html) or [Go's html/template](https://gowebexamples.com/templates/), T4 templates are pretty similar. This package allows [Unity](http://unity3d.com/) developers to author T4 templates (`.tt` files), and rely on the [Editor](https://docs.unity3d.com/Manual/UsingTheEditor.html) to process them and generate code. 13 | 14 | ## Installing 15 | 16 | This package supports [openupm](https://openupm.com/packages/com.faster-games.t4/) - you can install it using the following command: 17 | 18 | ``` 19 | openupm add com.faster-games.t4 20 | ``` 21 | 22 | Or by adding directly to your `manifest.json`: 23 | 24 | > Note: You may also use specific versions by appending `#{version}` where version is a [Release tag](https://github.com/faster-games/t4/releases) - e.g. `#v1.2.0`. 25 | 26 | ``` 27 | dependencies: { 28 | ... 29 | "com.faster-games.t4": "git+https://github.com/faster-games/t4.git" 30 | } 31 | ``` 32 | 33 | Or by using [Package Manager](https://docs.unity3d.com/Manual/upm-ui-giturl.html) to "Add a package from Git URL", using the following url: 34 | 35 | ``` 36 | https://github.com/faster-games/t4.git 37 | ``` 38 | 39 | ## Documentation 40 | 41 |
42 | 43 | [Manual 📖](https://t4.faster-games.com/manual/getting-started.html) | [Scripting API 🔎](https://t4.faster-games.com/ref/FasterGames.T4.Editor.html) 44 | 45 |
46 | 47 | Please also see these resources from Microsoft, as they are the authors and maintainers of the `T4` templating featureset and format: 48 | 49 | - [MS Docs: Code Generation and T4 Text Templates](https://docs.microsoft.com/en-us/visualstudio/modeling/code-generation-and-t4-text-templates) 50 | - [MS Docs: Design Time Templates](https://docs.microsoft.com/en-us/visualstudio/modeling/design-time-code-generation-by-using-t4-text-templates) 51 | 52 | ### Quickstart 53 | 54 | - Add a `.tt` file under `Assets` 55 | - Select it in the [Project window](https://docs.unity3d.com/Manual/ProjectView.html) 56 | - Note that the importer used is `TextTemplateImporter` - that's us! 57 | - Any processing errors will be shown in the [Console](https://docs.unity3d.com/Manual/Console.html) 58 | 59 | ## Supporting the project 60 | 61 | If this project saved you some time, and you'd like to see it continue to be invested in, consider [buying me a coffee. ☕](https://www.buymeacoffee.com/bengreenier) I do this full-time, and every little bit helps! 💙 62 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e0d3eb368a4e4c345922d2ccdf9981be 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bd2841dc5b8cf7345b323a4760d6283c 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/FasterGames.T4.Runtime.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "FasterGames.T4.Runtime", 3 | "rootNamespace": "FasterGames.T4.Runtime", 4 | "references": [], 5 | "includePlatforms": [], 6 | "excludePlatforms": [], 7 | "allowUnsafeCode": false, 8 | "overrideReferences": false, 9 | "precompiledReferences": [], 10 | "autoReferenced": true, 11 | "defineConstraints": [], 12 | "versionDefines": [], 13 | "noEngineReferences": false 14 | } -------------------------------------------------------------------------------- /Runtime/FasterGames.T4.Runtime.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 70eadbddef1576040aa024086713826d 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime/IDataHost.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Object = UnityEngine.Object; 3 | 4 | namespace FasterGames.T4.Runtime 5 | { 6 | /// 7 | /// Represents a Template parsing host that contains user data 8 | /// 9 | /// user data type 10 | public interface IDataHost where TData : Object 11 | { 12 | /// 13 | /// The user data 14 | /// 15 | public TData Data { get; } 16 | } 17 | } -------------------------------------------------------------------------------- /Runtime/IDataHost.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b5dabaf0dafc47ba88ec372e102ae3ef 3 | timeCreated: 1626816509 -------------------------------------------------------------------------------- /Samples~/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faster-games/t4/954234411b76686e106e8da305fbd85d69a31cc9/Samples~/.gitkeep -------------------------------------------------------------------------------- /Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe09c0e5ff738e244b84b97a95163985 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 80a3d27d605172344b52c95df8e703f4 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/Editor/EditorTestRuntime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 56865e70726648ca987e80fd19aa03d1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/Editor/EditorTestRuntime/Data.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace FasterGames.T4.Editor.Tests.EditorTestRuntime 5 | { 6 | public class Data : ScriptableObject 7 | { 8 | public List Animals; 9 | } 10 | } -------------------------------------------------------------------------------- /Tests/Editor/EditorTestRuntime/Data.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 02db62e765b34f3e9aaab386e9ced7e1 3 | timeCreated: 1626824772 -------------------------------------------------------------------------------- /Tests/Editor/EditorTestRuntime/FasterGames.T4.Editor.Tests.EditorTestRuntime.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "FasterGames.T4.Editor.Tests.EditorTestRuntime", 3 | "rootNamespace": "FasterGames.T4.Editor.Tests.EditorTestRuntime", 4 | "references": [], 5 | "includePlatforms": [ 6 | "Editor" 7 | ], 8 | "excludePlatforms": [], 9 | "allowUnsafeCode": false, 10 | "overrideReferences": false, 11 | "precompiledReferences": [], 12 | "autoReferenced": true, 13 | "defineConstraints": [], 14 | "versionDefines": [], 15 | "noEngineReferences": false 16 | } -------------------------------------------------------------------------------- /Tests/Editor/EditorTestRuntime/FasterGames.T4.Editor.Tests.EditorTestRuntime.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b3a31a2d4ff36e749b4e77be95d93d3b 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Tests/Editor/Example.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | 4 | [Serializable] 5 | public class DogTest {} 6 | 7 | 8 | [Serializable] 9 | public class CatTest {} 10 | 11 | 12 | [Serializable] 13 | public class SquidTest {} 14 | 15 | -------------------------------------------------------------------------------- /Tests/Editor/Example.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1540d3fd9337b7b48bf01209f798297a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Tests/Editor/Example.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="false" hostspecific="true" language="C#" #> 2 | <#@ output extension=".cs" #> 3 | <#@ import namespace="System.IO" #> 4 | using System; 5 | 6 | <# 7 | foreach (var animal in Host.Data.Animals) 8 | { 9 | #> 10 | 11 | [Serializable] 12 | public class <#= animal#>Test {} 13 | 14 | <# 15 | } 16 | #> -------------------------------------------------------------------------------- /Tests/Editor/Example.tt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 029ef4be6f79467c8c2d8b8afe815443 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 11500000, guid: 0d7b524045e7470296c8e842826841f7, type: 3} 11 | importerVersion: 1 12 | removeIfEmptyGeneration: 0 13 | embeddedData: {fileID: 11400000, guid: dc0376b5ddd1ffb4f9232d91629b059b, type: 2} 14 | additionalTypes: [] 15 | -------------------------------------------------------------------------------- /Tests/Editor/FasterGames.T4.Editor.Tests.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "FasterGames.T4.Editor.Tests", 3 | "rootNamespace": "FasterGames.T4.Editor.Tests", 4 | "references": [ 5 | "UnityEngine.TestRunner", 6 | "UnityEditor.TestRunner", 7 | "FasterGames.T4.Editor", 8 | "FasterGames.T4.Runtime", 9 | "FasterGames.T4.Editor.Tests.EditorTestRuntime" 10 | ], 11 | "includePlatforms": [ 12 | "Editor" 13 | ], 14 | "excludePlatforms": [], 15 | "allowUnsafeCode": false, 16 | "overrideReferences": true, 17 | "precompiledReferences": [ 18 | "nunit.framework.dll" 19 | ], 20 | "autoReferenced": false, 21 | "defineConstraints": [ 22 | "UNITY_INCLUDE_TESTS" 23 | ], 24 | "versionDefines": [], 25 | "noEngineReferences": false 26 | } -------------------------------------------------------------------------------- /Tests/Editor/FasterGames.T4.Editor.Tests.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: da57ee7b1c1b6034c9258a03480d7c50 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 44a090da22857be4596550e66fa52218 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating/DummyHost.cs: -------------------------------------------------------------------------------- 1 | // 2 | // IncludeFileProviderHost.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2009 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.CodeDom.Compiler; 30 | using Microsoft.VisualStudio.TextTemplating; 31 | 32 | namespace Mono.TextTemplating.Tests 33 | { 34 | 35 | public class DummyHost : ITextTemplatingEngineHost 36 | { 37 | public readonly Dictionary Locations = new Dictionary (); 38 | public readonly Dictionary Contents = new Dictionary (); 39 | public readonly Dictionary HostOptions = new Dictionary (); 40 | List standardAssemblyReferences = new List (); 41 | List standardImports = new List (); 42 | public readonly CompilerErrorCollection Errors = new CompilerErrorCollection (); 43 | public readonly Dictionary DirectiveProcessors = new Dictionary (); 44 | 45 | public virtual object GetHostOption (string optionName) 46 | { 47 | object o; 48 | HostOptions.TryGetValue (optionName, out o); 49 | return o; 50 | } 51 | 52 | public virtual bool LoadIncludeText (string requestFileName, out string content, out string location) 53 | { 54 | content = null; 55 | return Locations.TryGetValue (requestFileName, out location) 56 | && Contents.TryGetValue (requestFileName, out content); 57 | } 58 | 59 | public virtual void LogErrors (CompilerErrorCollection errors) 60 | { 61 | Errors.AddRange (errors); 62 | } 63 | 64 | public virtual AppDomain ProvideTemplatingAppDomain (string content) 65 | { 66 | return null; 67 | } 68 | 69 | public virtual string ResolveAssemblyReference (string assemblyReference) 70 | { 71 | throw new System.NotImplementedException(); 72 | } 73 | 74 | public virtual Type ResolveDirectiveProcessor (string processorName) 75 | { 76 | Type t; 77 | DirectiveProcessors.TryGetValue (processorName, out t); 78 | return t; 79 | } 80 | 81 | public virtual string ResolveParameterValue (string directiveId, string processorName, string parameterName) 82 | { 83 | throw new System.NotImplementedException(); 84 | } 85 | 86 | public virtual string ResolvePath (string path) 87 | { 88 | throw new System.NotImplementedException(); 89 | } 90 | 91 | public virtual void SetFileExtension (string extension) 92 | { 93 | throw new System.NotImplementedException(); 94 | } 95 | 96 | public virtual void SetOutputEncoding (System.Text.Encoding encoding, bool fromOutputDirective) 97 | { 98 | throw new System.NotImplementedException(); 99 | } 100 | 101 | public virtual IList StandardAssemblyReferences { 102 | get { return standardAssemblyReferences; } 103 | } 104 | 105 | public virtual IList StandardImports { 106 | get { return standardImports; } 107 | } 108 | 109 | public virtual string TemplateFile { 110 | get; set; 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating/DummyHost.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 34894c1ce2b657d48b21885c59481ac9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating/EngineTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // EngineTests.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2016 Xamarin Inc. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using NUnit.Framework; 29 | 30 | namespace Mono.TextTemplating.Tests 31 | { 32 | [TestFixture] 33 | public class EngineTests 34 | { 35 | #pragma warning disable 414 36 | static object [] ParameterParsingCases = { 37 | new object [] { "foo=bar", true, "", "", "foo", "bar" }, 38 | new object [] { "a=b", true, "", "", "a", "b" }, 39 | new object [] { "a=b=c", true, "", "", "a", "b=c" }, 40 | new object [] { "!!c!d", true, "", "", "c", "d" }, 41 | new object [] { "!!!", false, "", "", "", "" }, 42 | new object [] { "a=", true, "", "", "a", "" }, 43 | new object [] { "=", false, "", "", "", "" }, 44 | new object [] { "", false, "", "", "", "" }, 45 | new object [] { "!", false, "", "", "", "" }, 46 | new object [] { "a!", true, "", "", "a", "" }, 47 | new object [] { "!b!c!d", true, "", "b", "c", "d" }, 48 | new object [] { "a!b!c!d", true, "a", "b", "c", "d" }, 49 | new object [] { "a=b!c!d!e", true, "", "", "a", "b!c!d!e" }, 50 | new object [] { "a!b!c!d!e", true, "a", "b", "c", "d!e" }, 51 | new object [] { "foo!bar!baz!wibb!le", true, "foo", "bar", "baz", "wibb!le" }, 52 | }; 53 | #pragma warning restore 414 54 | 55 | [Test] 56 | [TestCaseSource(nameof (ParameterParsingCases))] 57 | public void ParameterParsing ( 58 | string parameter, bool valid, 59 | string expectedProcessor, string expectedDirective, 60 | string expectedName, string expectedValue) 61 | { 62 | string processor, directive, name, value; 63 | var success = TemplateGenerator.TryParseParameter (parameter, out processor, out directive, out name, out value); 64 | 65 | Assert.AreEqual (valid, success); 66 | Assert.AreEqual (expectedProcessor, processor); 67 | Assert.AreEqual (expectedDirective, directive); 68 | Assert.AreEqual (expectedName, name); 69 | Assert.AreEqual (expectedValue, value); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating/EngineTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8bd90439f90d18b42bb4178b5bf3d592 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating/GenerateIndentedClassCodeTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // GenerateIndentedClassCodeTests.cs 3 | // 4 | // Author: 5 | // Matt Ward 6 | // 7 | // Copyright (c) 2015 Xamarin Inc. (http://xamarin.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.CodeDom; 29 | using System.CodeDom.Compiler; 30 | using NUnit.Framework; 31 | using System.IO; 32 | 33 | namespace Mono.TextTemplating.Tests 34 | { 35 | [TestFixture] 36 | public class GenerateIndentedClassCodeTests 37 | { 38 | [Test] 39 | public void FieldAndPropertyGenerated () 40 | { 41 | var provider = CodeDomProvider.CreateProvider ("C#"); 42 | var field = CreateBoolField (); 43 | var property = CreateBoolProperty (); 44 | 45 | string output = TemplatingEngine.GenerateIndentedClassCode (provider, field, property); 46 | output = FixOutput (output); 47 | string expectedOutput = FixOutput (MethodAndFieldGeneratedOutput); 48 | 49 | Assert.AreEqual (expectedOutput, output); 50 | } 51 | 52 | static CodeTypeMember CreateVoidMethod () 53 | { 54 | var meth = new CodeMemberMethod { Name = "MyMethod" }; 55 | meth.ReturnType = new CodeTypeReference (typeof(void)); 56 | return meth; 57 | } 58 | 59 | static CodeTypeMember CreateBoolField () 60 | { 61 | var type = new CodeTypeReference (typeof(bool)); 62 | return new CodeMemberField { Name = "myField", Type = type }; 63 | } 64 | 65 | static CodeTypeMember CreateBoolProperty () 66 | { 67 | var type = new CodeTypeReference (typeof(bool)); 68 | var prop = new CodeMemberProperty { Name = "MyProperty", Type = type }; 69 | prop.GetStatements.Add ( 70 | new CodeMethodReturnStatement ( 71 | new CodePrimitiveExpression (true) 72 | ) 73 | ); 74 | return prop; 75 | } 76 | 77 | /// 78 | /// Remove empty lines which are not generated on Mono. 79 | /// 80 | static string FixOutput (string output, string newLine = "\n") 81 | { 82 | using (var writer = new StringWriter ()) { 83 | using (var reader = new StringReader (output)) { 84 | 85 | string line; 86 | while ((line = reader.ReadLine ()) != null) { 87 | if (!StringUtil.IsNullOrWhiteSpace (line)) { 88 | writer.Write (line); 89 | writer.Write (newLine); 90 | } 91 | } 92 | } 93 | return writer.ToString (); 94 | } 95 | } 96 | 97 | public static string MethodAndFieldGeneratedOutput = 98 | @" 99 | private bool myField; 100 | 101 | private bool MyProperty { 102 | get { 103 | return true; 104 | } 105 | } 106 | "; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating/GenerateIndentedClassCodeTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 809b2a0856b176d4bb897f5f58b7bc76 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating/GenerationTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // GenerationTests.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2009 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.IO; 30 | using NUnit.Framework; 31 | using Microsoft.VisualStudio.TextTemplating; 32 | using System.Linq; 33 | using System.CodeDom.Compiler; 34 | 35 | namespace Mono.TextTemplating.Tests 36 | { 37 | 38 | 39 | [TestFixture] 40 | public class GenerationTests 41 | { 42 | [Test] 43 | public void TemplateGeneratorTest () 44 | { 45 | var gen = new TemplateGenerator (); 46 | string tmp = null; 47 | gen.ProcessTemplate (null, "<#@ template language=\"C#\" #>", ref tmp, out tmp); 48 | Assert.IsNull (gen.Errors.OfType ().FirstOrDefault (), "ProcessTemplate"); 49 | } 50 | 51 | [Test] 52 | public void ImportReferencesTest () 53 | { 54 | var gen = new TemplateGenerator (); 55 | string tmp = null; 56 | gen.ReferencePaths.Add (Path.GetDirectoryName (typeof (Uri).Assembly.Location)); 57 | gen.ReferencePaths.Add (Path.GetDirectoryName (typeof (System.Linq.Enumerable).Assembly.Location)); 58 | gen.ProcessTemplate (null, "<#@ assembly name=\"System.dll\" #>\n<#@ assembly name=\"System.Core.dll\" #>", ref tmp, out tmp); 59 | Assert.IsNull (gen.Errors.OfType ().FirstOrDefault (), "ProcessTemplate"); 60 | } 61 | 62 | [Test] 63 | public void IncludeFileThatDoesNotExistTest () 64 | { 65 | var gen = new TemplateGenerator (); 66 | string tmp = null; 67 | gen.ProcessTemplate (null, "<#@ include file=\"none.tt\" #>", ref tmp, out tmp); 68 | Assert.IsTrue (gen.Errors.OfType ().First ().ErrorText 69 | .StartsWith ("Could not read included file 'none.tt'")); 70 | } 71 | 72 | [Test] 73 | public void Generate () 74 | { 75 | string Input = ParsingTests.ParseSample1; 76 | string Output = OutputSample1; 77 | Generate (Input, Output, "\n"); 78 | } 79 | 80 | [Test] 81 | public void GenerateMacNewlines () 82 | { 83 | string MacInput = ParsingTests.ParseSample1.Replace ("\n", "\r"); 84 | string MacOutput = OutputSample1.Replace ("\\n", "\\r").Replace ("\n", "\r");; 85 | Generate (MacInput, MacOutput, "\r"); 86 | } 87 | 88 | [Test] 89 | public void GenerateWindowsNewlines () 90 | { 91 | string WinInput = ParsingTests.ParseSample1.Replace ("\n", "\r\n"); 92 | string WinOutput = OutputSample1.Replace ("\\n", "\\r\\n").Replace ("\n", "\r\n"); 93 | Generate (WinInput, WinOutput, "\r\n"); 94 | } 95 | 96 | [Test] 97 | public void DefaultLanguage () 98 | { 99 | DummyHost host = new DummyHost (); 100 | string template = @"<#= DateTime.Now #>"; 101 | ParsedTemplate pt = ParsedTemplate.FromText (template, host); 102 | Assert.AreEqual (0, host.Errors.Count); 103 | TemplateSettings settings = TemplatingEngine.GetSettings (host, pt); 104 | Assert.AreEqual (settings.Language, "C#"); 105 | } 106 | 107 | //NOTE: we set the newline property on the code generator so that the whole files has matching newlines, 108 | // in order to match the newlines in the verbatim code blocks 109 | void Generate (string input, string expectedOutput, string newline) 110 | { 111 | DummyHost host = new DummyHost (); 112 | string className = "GeneratedTextTransformation4f504ca0"; 113 | string code = GenerateCode (host, input, className, newline); 114 | Assert.AreEqual (0, host.Errors.Count); 115 | 116 | var generated = TemplatingEngineHelper.CleanCodeDom (code, newline); 117 | expectedOutput = TemplatingEngineHelper.CleanCodeDom (expectedOutput, newline); 118 | Assert.AreEqual (expectedOutput, generated); 119 | } 120 | 121 | #region Helpers 122 | 123 | string GenerateCode (ITextTemplatingEngineHost host, string content, string name, string generatorNewline) 124 | { 125 | ParsedTemplate pt = ParsedTemplate.FromText (content, host); 126 | if (pt.Errors.HasErrors) { 127 | host.LogErrors (pt.Errors); 128 | return null; 129 | } 130 | 131 | TemplateSettings settings = TemplatingEngine.GetSettings (host, pt); 132 | if (name != null) 133 | settings.Name = name; 134 | if (pt.Errors.HasErrors) { 135 | host.LogErrors (pt.Errors); 136 | return null; 137 | } 138 | 139 | var ccu = TemplatingEngine.GenerateCompileUnit (host, content, pt, settings); 140 | if (pt.Errors.HasErrors) { 141 | host.LogErrors (pt.Errors); 142 | return null; 143 | } 144 | 145 | var opts = new System.CodeDom.Compiler.CodeGeneratorOptions (); 146 | using (var writer = new System.IO.StringWriter ()) { 147 | writer.NewLine = generatorNewline; 148 | settings.Provider.GenerateCodeFromCompileUnit (ccu, writer, opts); 149 | return writer.ToString (); 150 | } 151 | } 152 | 153 | #endregion 154 | 155 | #region Expected output strings 156 | 157 | public static string OutputSample1 = 158 | @" 159 | namespace Microsoft.VisualStudio.TextTemplating { 160 | 161 | 162 | public partial class GeneratedTextTransformation4f504ca0 : global::Microsoft.VisualStudio.TextTemplating.TextTransformation { 163 | 164 | 165 | #line 9 """" 166 | 167 | var s = ""baz \\#>""; 168 | 169 | #line default 170 | #line hidden 171 | 172 | public override string TransformText() { 173 | this.GenerationEnvironment = null; 174 | 175 | #line 2 """" 176 | this.Write(""Line One\nLine Two\n""); 177 | 178 | #line default 179 | #line hidden 180 | 181 | #line 4 """" 182 | 183 | var foo = 5; 184 | 185 | 186 | #line default 187 | #line hidden 188 | 189 | #line 7 """" 190 | this.Write(""Line Three ""); 191 | 192 | #line default 193 | #line hidden 194 | 195 | #line 7 """" 196 | this.Write(global::Microsoft.VisualStudio.TextTemplating.ToStringHelper.ToStringWithCulture( bar )); 197 | 198 | #line default 199 | #line hidden 200 | 201 | #line 7 """" 202 | this.Write(""\nLine Four\n""); 203 | 204 | #line default 205 | #line hidden 206 | return this.GenerationEnvironment.ToString(); 207 | } 208 | 209 | public override void Initialize() { 210 | base.Initialize(); 211 | } 212 | } 213 | } 214 | "; 215 | #endregion 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating/GenerationTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0e5741fdf33b1474fb6889306829eb22 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating/ParsingTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Test.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2009 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using NUnit.Framework; 30 | 31 | namespace Mono.TextTemplating.Tests 32 | { 33 | 34 | 35 | [TestFixture] 36 | public class ParsingTests 37 | { 38 | public static string ParseSample1 = 39 | @"<#@ template language=""C#v3.5"" #> 40 | Line One 41 | Line Two 42 | <# 43 | var foo = 5; 44 | #> 45 | Line Three <#= bar #> 46 | Line Four 47 | <#+ 48 | var s = ""baz \\#>""; 49 | #> 50 | "; 51 | 52 | [Test] 53 | public void TokenTest () 54 | { 55 | string tf = "test.input"; 56 | Tokeniser tk = new Tokeniser (tf, ParseSample1); 57 | 58 | //line 1 59 | Assert.IsTrue (tk.Advance ()); 60 | Assert.AreEqual (new Location (tf, 1, 1), tk.Location); 61 | Assert.AreEqual (State.Content, tk.State); 62 | Assert.AreEqual ("", tk.Value); 63 | Assert.IsTrue (tk.Advance ()); 64 | Assert.AreEqual (State.Directive, tk.State); 65 | Assert.IsTrue (tk.Advance ()); 66 | Assert.AreEqual (new Location (tf, 1, 5), tk.Location); 67 | Assert.AreEqual (State.DirectiveName, tk.State); 68 | Assert.AreEqual ("template", tk.Value); 69 | Assert.IsTrue (tk.Advance ()); 70 | Assert.AreEqual (State.Directive, tk.State); 71 | Assert.IsTrue (tk.Advance ()); 72 | Assert.AreEqual (new Location (tf, 1, 14), tk.Location); 73 | Assert.AreEqual (State.DirectiveName, tk.State); 74 | Assert.AreEqual ("language", tk.Value); 75 | Assert.IsTrue (tk.Advance ()); 76 | Assert.AreEqual (State.Directive, tk.State); 77 | Assert.IsTrue (tk.Advance ()); 78 | Assert.AreEqual (State.DirectiveValue, tk.State); 79 | Assert.AreEqual (new Location (tf, 1, 23), tk.Location); 80 | Assert.AreEqual ("C#v3.5", tk.Value); 81 | Assert.IsTrue (tk.Advance ()); 82 | Assert.AreEqual (State.Directive, tk.State); 83 | 84 | //line 2, 3 85 | Assert.IsTrue (tk.Advance ()); 86 | Assert.AreEqual (new Location (tf, 2, 1), tk.Location); 87 | Assert.AreEqual (State.Content, tk.State); 88 | Assert.AreEqual ("Line One\nLine Two\n", tk.Value); 89 | 90 | //line 4, 5, 6 91 | Assert.IsTrue (tk.Advance ()); 92 | Assert.AreEqual (new Location (tf, 4, 1), tk.TagStartLocation); 93 | Assert.AreEqual (new Location (tf, 4, 3), tk.Location); 94 | Assert.AreEqual (new Location (tf, 6, 3), tk.TagEndLocation); 95 | Assert.AreEqual (State.Block, tk.State); 96 | Assert.AreEqual ("\nvar foo = 5;\n", tk.Value); 97 | 98 | //line 7 99 | Assert.IsTrue (tk.Advance ()); 100 | Assert.AreEqual (new Location (tf, 7, 1), tk.Location); 101 | Assert.AreEqual (State.Content, tk.State); 102 | Assert.AreEqual ("Line Three ", tk.Value); 103 | Assert.IsTrue (tk.Advance ()); 104 | Assert.AreEqual (new Location (tf, 7, 12), tk.TagStartLocation); 105 | Assert.AreEqual (new Location (tf, 7, 15), tk.Location); 106 | Assert.AreEqual (new Location (tf, 7, 22), tk.TagEndLocation); 107 | Assert.AreEqual (State.Expression, tk.State); 108 | Assert.AreEqual (" bar ", tk.Value); 109 | 110 | //line 8 111 | Assert.IsTrue (tk.Advance ()); 112 | Assert.AreEqual (new Location (tf, 7, 22), tk.Location); 113 | Assert.AreEqual (State.Content, tk.State); 114 | Assert.AreEqual ("\nLine Four\n", tk.Value); 115 | 116 | //line 9, 10, 11 117 | Assert.IsTrue (tk.Advance ()); 118 | Assert.AreEqual (new Location (tf, 9, 1), tk.TagStartLocation); 119 | Assert.AreEqual (new Location (tf, 9, 4), tk.Location); 120 | Assert.AreEqual (new Location (tf, 11, 3), tk.TagEndLocation); 121 | Assert.AreEqual (State.Helper, tk.State); 122 | Assert.AreEqual (" \nvar s = \"baz \\\\#>\";\n", tk.Value); 123 | 124 | //line 12 125 | Assert.IsTrue (tk.Advance ()); 126 | Assert.AreEqual (new Location (tf, 12, 1), tk.Location); 127 | Assert.AreEqual (State.Content, tk.State); 128 | Assert.AreEqual ("", tk.Value); 129 | 130 | //EOF 131 | Assert.IsFalse (tk.Advance ()); 132 | Assert.AreEqual (new Location (tf, 12, 1), tk.Location); 133 | Assert.AreEqual (State.EOF, tk.State); 134 | } 135 | 136 | [Test] 137 | public void ParseTest () 138 | { 139 | string tf = "test.input"; 140 | 141 | ParsedTemplate pt = new ParsedTemplate ("test.input"); 142 | Tokeniser tk = new Tokeniser (tf, ParseSample1); 143 | DummyHost host = new DummyHost (); 144 | pt.Parse (host, tk); 145 | 146 | Assert.AreEqual (0, pt.Errors.Count); 147 | var content = new List (pt.Content); 148 | var dirs = new List (pt.Directives); 149 | 150 | Assert.AreEqual (1, dirs.Count); 151 | Assert.AreEqual (6, content.Count); 152 | 153 | Assert.AreEqual ("template", dirs[0].Name); 154 | Assert.AreEqual (1, dirs[0].Attributes.Count); 155 | Assert.AreEqual ("C#v3.5", dirs[0].Attributes["language"]); 156 | Assert.AreEqual (new Location (tf, 1, 1), dirs[0].TagStartLocation); 157 | Assert.AreEqual (new Location (tf, 1, 34), dirs[0].EndLocation); 158 | 159 | Assert.AreEqual ("Line One\nLine Two\n", content[0].Text); 160 | Assert.AreEqual ("\nvar foo = 5;\n", content[1].Text); 161 | Assert.AreEqual ("Line Three ", content[2].Text); 162 | Assert.AreEqual (" bar ", content[3].Text); 163 | Assert.AreEqual ("\nLine Four\n", content[4].Text); 164 | Assert.AreEqual (" \nvar s = \"baz \\\\#>\";\n", content[5].Text); 165 | 166 | Assert.AreEqual (SegmentType.Content, content[0].Type); 167 | Assert.AreEqual (SegmentType.Block, content[1].Type); 168 | Assert.AreEqual (SegmentType.Content, content[2].Type); 169 | Assert.AreEqual (SegmentType.Expression, content[3].Type); 170 | Assert.AreEqual (SegmentType.Content, content[4].Type); 171 | Assert.AreEqual (SegmentType.Helper, content[5].Type); 172 | 173 | Assert.AreEqual (new Location (tf, 4, 1), content[1].TagStartLocation); 174 | Assert.AreEqual (new Location (tf, 7, 12), content[3].TagStartLocation); 175 | Assert.AreEqual (new Location (tf, 9, 1), content[5].TagStartLocation); 176 | 177 | Assert.AreEqual (new Location (tf, 2, 1), content[0].StartLocation); 178 | Assert.AreEqual (new Location (tf, 4, 3), content[1].StartLocation); 179 | Assert.AreEqual (new Location (tf, 7, 1), content[2].StartLocation); 180 | Assert.AreEqual (new Location (tf, 7, 15), content[3].StartLocation); 181 | Assert.AreEqual (new Location (tf, 7, 22), content[4].StartLocation); 182 | Assert.AreEqual (new Location (tf, 9, 4), content[5].StartLocation); 183 | 184 | Assert.AreEqual (new Location (tf, 6, 3), content[1].EndLocation); 185 | Assert.AreEqual (new Location (tf, 7, 22), content[3].EndLocation); 186 | Assert.AreEqual (new Location (tf, 11, 3), content[5].EndLocation); 187 | } 188 | 189 | 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating/ParsingTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2b259465500fe64498532c5d18f4d0dd 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating/TemplateEnginePreprocessTemplateTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 168dd24d6ac5c1c4a8be9968c612154f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating/TemplatingEngineHelper.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Test.cs 3 | // 4 | // Author: 5 | // Mikayla Hutchinson 6 | // 7 | // Copyright (c) 2009 Novell, Inc. (http://www.novell.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.IO; 29 | 30 | namespace Mono.TextTemplating.Tests 31 | { 32 | public static class TemplatingEngineHelper 33 | { 34 | /// 35 | /// Cleans CodeDOM generated code so that Windows/Mac and Mono/.NET output can be compared. 36 | /// 37 | public static string CleanCodeDom (string input, string newLine) 38 | { 39 | using (var writer = new StringWriter ()) { 40 | using (var reader = new StringReader (input)) { 41 | 42 | bool afterLineDirective = true; 43 | bool stripHeader = true; 44 | 45 | string line; 46 | while ((line = reader.ReadLine ()) != null) { 47 | 48 | if (stripHeader) { 49 | if (line.StartsWith ("//", StringComparison.Ordinal) || StringUtil.IsNullOrWhiteSpace (line)) 50 | continue; 51 | stripHeader = false; 52 | } 53 | 54 | if (afterLineDirective) { 55 | if (StringUtil.IsNullOrWhiteSpace (line)) 56 | continue; 57 | afterLineDirective = false; 58 | } 59 | 60 | if (line.Contains ("#line")) { 61 | afterLineDirective = true; 62 | } 63 | 64 | writer.Write (line); 65 | writer.Write (newLine); 66 | } 67 | } 68 | return writer.ToString (); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating/TemplatingEngineHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3704d45387729cd4e98568eba8be6d98 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating/TextTemplatingSessionTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // TextTemplatingSessionTests.cs 3 | // 4 | // Author: 5 | // Matt Ward 6 | // 7 | // Copyright (c) 2016 Xamarin Inc. (http://xamarin.com) 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Reflection; 29 | using Microsoft.VisualStudio.TextTemplating; 30 | using NUnit.Framework; 31 | 32 | namespace Mono.TextTemplating.Tests 33 | { 34 | [TestFixture] 35 | public class TextTemplatingSessionTests 36 | { 37 | [Test] 38 | public void AppDomainSerializationTest () 39 | { 40 | var guid = Guid.NewGuid (); 41 | var appDomain = AppDomain.CreateDomain ("TextTemplatingSessionSerializationTestAppDomain"); 42 | 43 | var session = (TextTemplatingSession)appDomain.CreateInstanceFromAndUnwrap ( 44 | typeof(TextTemplatingSession).Assembly.Location, 45 | typeof(TextTemplatingSession).FullName, 46 | false, 47 | BindingFlags.Public | BindingFlags.Instance, 48 | null, 49 | new object[] { guid }, 50 | null, 51 | null); 52 | 53 | Assert.AreEqual (guid, session.Id); 54 | } 55 | 56 | class TestHost : TemplateGenerator { } 57 | 58 | [Test] 59 | public void TestCustomHost () 60 | { 61 | var gen = new TestHost (); 62 | var outFilename = "test.txt"; 63 | var success = gen.ProcessTemplate ( 64 | "test.tt", 65 | "<#@ template hostspecific=\"true\" #><#=Host.GetType().Name#>", 66 | ref outFilename, 67 | out var outContent 68 | ); 69 | Assert.True (success); 70 | Assert.AreEqual ("TestHost", outContent); 71 | } 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /Tests/Editor/TextTemplating/TextTemplatingSessionTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c5f59fd85e3731d49bcbfb2d95f40ccc 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Tests/Editor/exampleData.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 02db62e765b34f3e9aaab386e9ced7e1, type: 3} 13 | m_Name: exampleData 14 | m_EditorClassIdentifier: 15 | Animals: 16 | - Dog 17 | - Cat 18 | - Squid 19 | -------------------------------------------------------------------------------- /Tests/Editor/exampleData.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dc0376b5ddd1ffb4f9232d91629b059b 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 11400000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Third Party Notices.md: -------------------------------------------------------------------------------- 1 | # mono/t4 2 | 3 | This library uses [mono/t4](https://github.com/mono/t4) to provide T4 template generation. This is only possible due to the great work done by those folks. Thank you! 4 | -------------------------------------------------------------------------------- /Third Party Notices.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ef7754ef2676c2a41a8dc8e3d1afb02a 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /docfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": [ 3 | { 4 | "src": [ 5 | { 6 | "files": ["Runtime/**/*.cs", "Editor/**/*.cs"] 7 | } 8 | ], 9 | "dest": "dist/.tmp/ref", 10 | "disableGitFeatures": false, 11 | "disableDefaultFilter": false 12 | } 13 | ], 14 | "build": { 15 | "content": [ 16 | { 17 | "files": ["**/*.yml"], 18 | "src": "dist/.tmp/ref/", 19 | "dest": "ref/" 20 | }, 21 | { 22 | "files": ["README.md"], 23 | "src": "./", 24 | "dest": "./" 25 | }, 26 | { 27 | "files": ["**/*.md", "**/toc.yml"], 28 | "src": "Documentation~/", 29 | "dest": "./" 30 | } 31 | ], 32 | "resource": [ 33 | { 34 | "files": ["favicon.ico", "header.png", "logo.svg"], 35 | "src": "Documentation~/" 36 | } 37 | ], 38 | "overwrite": [], 39 | "dest": "dist/docs", 40 | "globalMetadataFiles": [], 41 | "fileMetadataFiles": [], 42 | "template": [ 43 | "dist/.unityfx/templates/default", 44 | "dist/.unityfx/templates/unity" 45 | ], 46 | "postProcessors": [], 47 | "markdownEngineName": "markdig", 48 | "noLangKeyword": false, 49 | "keepFileLink": false, 50 | "cleanupCacheHistory": false, 51 | "disableGitFeatures": false, 52 | "globalMetadata": { 53 | "_appTitle": "T4", 54 | "_appFooter": "Copyright FasterGames ©", 55 | "_description": "T4 text template generative importer for Unity3D", 56 | "_appLogoPath": "logo.svg", 57 | "_appFaviconPath": "favicon.ico", 58 | "_enableSearch": false 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /docfx.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3022007d7d6d8c1418d20a308fc9ea87 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.faster-games.t4", 3 | "version": "1.4.1", 4 | "displayName": "T4 Templates", 5 | "description": "T4 text template generative importer for Unity3D", 6 | "unity": "2020.3", 7 | "unityRelease": "13f1", 8 | "documentationUrl": "https://t4.faster-games.com/", 9 | "changelogUrl": "https://github.com/faster-games/t4/blob/main/CHANGELOG.md", 10 | "licensesUrl": "https://github.com/faster-games/t4/blob/main/LICENSE.md", 11 | "dependencies": {}, 12 | "keywords": [ 13 | "faster-games", 14 | "template" 15 | ], 16 | "author": { 17 | "name": "Ben Greenier", 18 | "email": "ben+faster-games@bengreenier.com", 19 | "url": "https://bengreenier.com" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b2e3942451f511943862f9b52b3995b1 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------