예제 #1
0
        public void InitialiseSolutionSettings(ISettingsStorageMountPoint mountPoint)
        {
            // This is called on the main thread, load the settings and initialise in the background
            myThreading.Tasks.Factory.StartNew(() =>
            {
                var streamName = GetType().Namespace + ".Abbreviations.txt";
                var stream     = GetType().Assembly.GetManifestResourceStream(streamName);
                if (stream == null)
                {
                    myLogger.Warn($"Cannot load resource stream: {streamName}");
                    return;
                }

                using (var streamReader = new StreamReader(stream))
                {
                    var entry = mySettingsSchema.GetIndexedEntry((CSharpNamingSettings s) => s.Abbreviations);

                    string abbreviation;
                    while ((abbreviation = streamReader.ReadLine()) != null)
                    {
                        ScalarSettingsStoreAccess.SetIndexedValue(mountPoint, entry, abbreviation, null, abbreviation,
                                                                  null, myLogger);
                    }
                }
            });
        }
예제 #2
0
 private void SetValue <TKeyClass, TEntryValue>([NotNull] ISettingsStorageMountPoint mount,
                                                [NotNull] Expression <Func <TKeyClass, TEntryValue> > lambdaexpression, [NotNull] TEntryValue value,
                                                IDictionary <SettingsKey, object> keyIndices = null)
 {
     ScalarSettingsStoreAccess.SetValue(mount, settingsSchema.GetScalarEntry(lambdaexpression), keyIndices, value,
                                        false, null, logger);
 }
        public void InitialiseSolutionSettings(ISettingsStorageMountPoint mountPoint)
        {
            var entry = mySettingsSchema.GetIndexedEntry((InstalledDictionariesSettings s) => s.InstalledDictionaries);
            var path  = (FileSystemPath.Parse(GetType().Assembly.Location).Parent / "Extensions/JetBrains.unity/dictionaries/unity.dic").FullPath;

            ScalarSettingsStoreAccess.SetIndexedValue(mountPoint, entry, path, null, true, null, myLogger);
        }
        private void ExcludeFolderFromNamespace(ISettingsStorageMountPoint mountPoint, string path)
        {
            var index = NamespaceFolderProvider.GetIndexFromOldIndex(FileSystemPath.Parse(path,
                                                                                          FileSystemPathInternStrategy.TRY_GET_INTERNED_BUT_DO_NOT_INTERN));

            SetIndexedValue(mountPoint, NamespaceProviderSettingsAccessor.NamespaceFoldersToSkip, index, true);
        }
        private void ExcludePackageRootFolderFromNamespace(ISettingsStorageMountPoint mountPoint,
                                                           IProjectFolder folder, string path)
        {
            ExcludeFolderFromNamespace(mountPoint, path);

            // Is it a package folder? Exclude Scripts, Runtime, Scripts/Runtime and Runtime/Scripts
            if (folder.Location.Combine("package.json").ExistsFile)
            {
                // The folder will be linked if the project's files belong to a package that is external to the solution
                // folder. With a linked folder, the namespace provider must be the actual path, relative to the parent
                // folder, rather than the visible path in the Solution Explorer
                //
                // NOTE: KEEP UP TO DATE WITH ExternalPackageCustomNamespaceProvider!
                if (folder.IsLinked && folder.ParentFolder != null)
                {
                    path = folder.Location.ConvertToRelativePath(folder.ParentFolder.Location).FullPath;
                }
                ExcludeFolderFromNamespace(mountPoint, path + @"\Runtime");
                ExcludeFolderFromNamespace(mountPoint, path + @"\Scripts");
                ExcludeFolderFromNamespace(mountPoint, path + @"\Runtime\Scripts");
                ExcludeFolderFromNamespace(mountPoint, path + @"\Scripts\Runtime");
                return;
            }

            // Recurse until we hit the package root
            ExcludePackageSubFoldersFromNamespace(mountPoint, folder, path);
        }
예제 #6
0
        private void InitialiseQuickList(ISettingsStorageMountPoint mountPoint, IMainScopePoint quickList)
        {
            var settings = new QuickListSettings {
                Name = quickList.QuickListTitle
            };

            SetIndexedKey(mountPoint, settings, new GuidIndex(quickList.QuickListUID));
        }
예제 #7
0
        public void InitialiseProjectSettings(Lifetime projectLifetime, IProject project,
                                              ISettingsStorageMountPoint mountPoint)
        {
            SetProjectLangVersion(project, mountPoint);

            // If the project data cache isn't ready yet, or changes at a later date, reset the overridden lang version
            myUnityProjectFileCache.RegisterDataChangedCallback(projectLifetime, project.ProjectFileLocation,
                                                                () => SetProjectLangVersion(project, mountPoint));
        }
예제 #8
0
 private void SetIndexedValue <TKeyClass, TEntryIndex, TEntryValue>([NotNull] ISettingsStorageMountPoint mount,
                                                                    [NotNull] Expression <Func <TKeyClass, IIndexedEntry <TEntryIndex, TEntryValue> > > lambdaexpression,
                                                                    [NotNull] TEntryIndex index,
                                                                    [NotNull] TEntryValue value,
                                                                    IDictionary <SettingsKey, object> keyIndices = null)
 {
     ScalarSettingsStoreAccess.SetIndexedValue(mount, mySettingsSchema.GetIndexedEntry(lambdaexpression), index,
                                               keyIndices, value, null, myLogger);
 }
 private void ExcludePackageSubFoldersFromNamespace(ISettingsStorageMountPoint mountPoint,
                                                    IProjectFolder thisFolder, string thisPath)
 {
     foreach (var subFolder in thisFolder.GetSubFolders())
     {
         var path = thisPath + @"\" + subFolder.Name;
         ExcludePackageRootFolderFromNamespace(mountPoint, subFolder, path);
     }
 }
예제 #10
0
        private void InitNamespaceProviderSettings(ISettingsStorageMountPoint mountPoint)
        {
            var assetsPathIndex = NamespaceFolderProvider.GetIndexFromOldIndex(FileSystemPath.Parse("Assets"));

            SetIndexedValue(mountPoint, NamespaceProviderSettingsAccessor.NamespaceFoldersToSkip, assetsPathIndex, true);

            var scriptsPathIndex = NamespaceFolderProvider.GetIndexFromOldIndex(FileSystemPath.Parse(@"Assets\Scripts"));

            SetIndexedValue(mountPoint, NamespaceProviderSettingsAccessor.NamespaceFoldersToSkip, scriptsPathIndex, true);
        }
예제 #11
0
        public override void InitDefaultSettings(ISettingsStorageMountPoint mountPoint)
        {
            InitialiseQuickList(mountPoint, myProjectMainPoint);
            InitialiseQuickList(mountPoint, myFilesMainPoint);

            // TODO: Not sure if this would be better handled in a .dotSettings file
            var pos = 0;

            AddToQuickList(mountPoint, myProjectMainPoint, "Node", ++pos, "67A1E56D-859B-4BEF-A4EE-1D7A06F1A2B9");
        }
        public override void InitDefaultSettings(ISettingsStorageMountPoint mountPoint)
        {
            InitialiseQuickList(mountPoint, myProjectMainPoint);
            InitialiseQuickList(mountPoint, myFilesMainPoint);

            // TODO: Not sure if this would be better handled in a .dotSettings file
            AddToQuickList(mountPoint, myProjectMainPoint, "MonoBehaviour", 1, "5ff5ac38-7207-4256-91ae-b5436552db13");
            AddToQuickList(mountPoint, myProjectMainPoint, "PlayModeTest", 2, "0bcdbc13-d26e-4512-9750-fb930f532e88");
            AddToQuickList(mountPoint, myProjectMainPoint, "EditModeTest", 3, "7b7fa2c7-0ee5-4d4f-bb1f-ddbeacdbfc94");
            AddToQuickList(mountPoint, myProjectMainPoint, "StandardSurfaceShader", 4, "4b8178a2-8110-4068-a788-43b8227564e5");
            AddToQuickList(mountPoint, myProjectMainPoint, "UnlitShader", 5, "fdbd3ad2-8db2-466a-a934-4ce25cb40564");
            AddToQuickList(mountPoint, myProjectMainPoint, "ImageEffectShader", 6, "7b10542b-0a61-4bd8-ba91-e5bad4d39f5b");
        }
        private void AddAutoImportExclusions(ISettingsStorageMountPoint mountPoint, params string[] settings)
        {
            var entry      = mySettingsSchema.GetIndexedEntry((AutoImport2Settings s) => s.BlackLists);
            var indexedKey = new Dictionary <SettingsKey, object>
            {
                { mySettingsSchema.GetKey <AutoImport2Settings>(), CSharpLanguage.Name }
            };

            foreach (var setting in settings)
            {
                ScalarSettingsStoreAccess.SetIndexedValue(mountPoint, entry, setting, indexedKey, true, null, myLogger);
            }
        }
        public void InitialiseSolutionSettings(ISettingsStorageMountPoint mountPoint)
        {
            // Show type conversion hints always. The default is push-to-hint, but the big benefit for Unity developers
            // is to see when an implicit conversion is happening between Vector2 and Vector3, as this is a lossy conversion
            // This can still be overridden at the solution or personal level
            var entry = mySettingsSchema.GetScalarEntry((CSharpTypeConversionHintsOptions o) => o.ShowTypeConversionHints);

            ScalarSettingsStoreAccess.SetValue(mountPoint, entry, null, InlayHintsMode.Always, true, null, myLogger);

            // Show as a hint, not as an icon
            entry = mySettingsSchema.GetScalarEntry((CSharpTypeConversionHintsOptions o) =>
                                                    o.ShowHintsInSimplifiedMode);
            ScalarSettingsStoreAccess.SetValue(mountPoint, entry, null, false, true, null, myLogger);
        }
예제 #15
0
        public void InitialiseProjectSettings(Lifetime projectLifetime, IProject project,
                                              ISettingsStorageMountPoint mountPoint)
        {
            var assetsPathIndex = NamespaceFolderProvider.GetIndexFromOldIndex(FileSystemPath.Parse("Assets"));

            SetIndexedValue(mountPoint, NamespaceProviderSettingsAccessor.NamespaceFoldersToSkip, assetsPathIndex,
                            true);

            var scriptsPathIndex =
                NamespaceFolderProvider.GetIndexFromOldIndex(FileSystemPath.Parse(@"Assets\Scripts"));

            SetIndexedValue(mountPoint, NamespaceProviderSettingsAccessor.NamespaceFoldersToSkip, scriptsPathIndex,
                            true);
        }
        // The reasoning behind this is fairly simple:
        // * Package location should not affect namespace
        //   The package owner is not in control of the location of the package on an end user's system. It might be
        //   cloned into the Packages folder, or referenced and cached in the Library/PackageCache folder. It might also
        //   be referenced in an external location with the file: syntax
        // * Assembly definition location should affect location, but only relative to Assets or package root folder
        //   Packages are self contained units. The location of an assembly definition in a folder structure (especially
        //   the Assets folder) is deliberate on the part of the user and should be part of the namespace
        // * If the asmdef defines a root namespace (Unity 2020.2a12+) this overrides everything, up to and including
        //   the location of the .asmdef file
        // * Exclude some folder names, based on observed convention. E.g. Assets, Runtime, Scripts.
        //   Editor is deliberately not excluded.
        //
        // There are subtleties:
        // * Exclude Assets and Assets/Scripts, Packages and Library/PackageCache
        // * Exclude the package root folder. The package owner is not in control of this.
        //   Referenced packages are stored in Library/PackageCache with a folder name based on ID and version
        //   End users can clone git repos or tarballs into any folder
        // * Exclude any folder until we get to the package root (the location of the package.json)
        //   If we clone a git repo into Packages, and the repo doesn't have a package in the root of the repo, skip all
        //   folders until we get to the package root. The package can be included via a file: entry in manifest.json
        // * A package that lives inside the solution structure, but outside of Assets or Packages will have a project
        //   with a path that is relative to the solution root. Ignore all intermediary folders between solution and
        //   package root
        // * A package that lives outside of the solution structure will have a root folder that is a link to the common
        //   parent of all files in the project. This is usually the asmdef location, AND IS INCORRECT.
        //   The linked folder is not included in namespace suggestions
        //   TODO: The linked folder should be the package root folder (which we normally ignore)
        //   This requires changes to the generated files. Either we include package.json to make a new default folder,
        //   or we add Link attributes to each file item
        // * After package root, ignore Runtime, Scripts and any combination of the two
        //
        // And implications:
        // * If there is no root namespace specified for an assembly definition in a package, one can be inferred from
        //   the path from the package root to the assembly definition file
        //   E.g. /Packages/[email protected]/Unity.Collections/Unity.Collections.asmdef will have
        //   a "root namespace" of Unity.Collections
        public void InitialiseProjectSettings(Lifetime projectLifetime, IProject project,
                                              ISettingsStorageMountPoint mountPoint)
        {
            ExcludeFolderFromNamespace(mountPoint, "Assets");
            ExcludeFolderFromNamespace(mountPoint, @"Assets\Scripts");

            ExcludePackagesFoldersFromNamespace(mountPoint, project, "Packages");
            foreach (var projectFolder in project.GetSubFolders("Library"))
            {
                ExcludeFolderFromNamespace(mountPoint, "Library");
                ExcludePackagesFoldersFromNamespace(mountPoint, projectFolder, "PackageCache", @"Library");
            }

            ExcludeExternalPackagesFromNamespace(mountPoint, project);
        }
        private void ExcludePackagesFoldersFromNamespace(ISettingsStorageMountPoint mountPoint,
                                                         IProjectFolder packageHierarchyParentFolder,
                                                         string packageHierarchyFolderName,
                                                         string parentProjectRelativePath = "")
        {
            var packageHierarchyRootFolderPath = parentProjectRelativePath.Length == 0
                ? packageHierarchyFolderName
                : parentProjectRelativePath + @"\" + packageHierarchyFolderName;

            foreach (var subFolder in packageHierarchyParentFolder.GetSubFolders(packageHierarchyFolderName))
            {
                // Exclude the root of the package hierarchy (Packages or PackageCache)
                ExcludeFolderFromNamespace(mountPoint, packageHierarchyRootFolderPath);
                ExcludePackageSubFoldersFromNamespace(mountPoint, subFolder, packageHierarchyRootFolderPath);
            }
        }
        public void InitialiseSolutionSettings(ISettingsStorageMountPoint mountPoint)
        {
            // Remove items from auto completion. Anything in these namespaces, or matching the method name will not
            // show in the auto import completion lists, and will not get the auto-import alt+enter tooltip popup.
            // If you want to use a type that matches, you need to add the using statement manually.
            // * Ignore Bool.Lang.* and UnityScript.* as they were deprecated in late 2017, and most of the code there
            //   is not intended to be consumed by users, but the assemblies are still referenced. This prevents e.g.:
            //   Boo.Lang.List`1 from appearing in the completion list above System.Collections.Generic.List`1
            // * Also exclude System.Diagnostics.Debug() to prevent similar clashes with UnityEngine.Debug()

            // See the internal DumpDuplicateTypeNamesAction to generate a list of types that can clash. There are about
            // 80 types on this list. It's not worth ignoring all of them. But some candidates:
            // * System.Numerics.Vector{2,3,4} + Quaternion + Plane
            // * System.Random + UnityEngine.Random
            AddAutoImportExclusions(mountPoint, "Boo.Lang.*", "UnityScript.*", "System.Diagnostics.Debug");
        }
        public override void InitDefaultSettings(ISettingsStorageMountPoint mountPoint)
        {
            InitialiseQuickList(mountPoint, myProjectMainPoint);
            InitialiseQuickList(mountPoint, myFilesMainPoint);

            // TODO: Not sure if this would be better handled in a .dotSettings file
            var pos = 0;

            AddToQuickList(mountPoint, myProjectMainPoint, "MonoBehaviour", ++pos, "5ff5ac38-7207-4256-91ae-b5436552db13");
            AddToQuickList(mountPoint, myProjectMainPoint, "PlayModeTest", ++pos, "0bcdbc13-d26e-4512-9750-fb930f532e88");
            AddToQuickList(mountPoint, myProjectMainPoint, "EditModeTest", ++pos, "7b7fa2c7-0ee5-4d4f-bb1f-ddbeacdbfc94");
            AddToQuickList(mountPoint, myProjectMainPoint, "StandardSurfaceShader", ++pos, "4b8178a2-8110-4068-a788-43b8227564e5");
            AddToQuickList(mountPoint, myProjectMainPoint, "UnlitShader", ++pos, "fdbd3ad2-8db2-466a-a934-4ce25cb40564");
            AddToQuickList(mountPoint, myProjectMainPoint, "ImageEffectShader", ++pos, "7b10542b-0a61-4bd8-ba91-e5bad4d39f5b");
            AddToQuickList(mountPoint, myProjectMainPoint, "AsmDef", ++pos, "bf263f0d-4315-42f7-8813-d7afe13fcdeb");
            AddToQuickList(mountPoint, myProjectMainPoint, "EditorEntryPoint", ++pos, "DA24767F-E6BB-4463-ACB4-799D7CE68822");
        }
예제 #20
0
        private void AddToQuickList(ISettingsStorageMountPoint mountPoint, IMainScopePoint quickList, string name, int position, string guid)
        {
            var quickListKey = mySettingsSchema.GetIndexedKey <QuickListSettings>();
            var entryKey     = mySettingsSchema.GetIndexedKey <EntrySettings>();
            var dictionary   = new Dictionary <SettingsKey, object>
            {
                { quickListKey, new GuidIndex(quickList.QuickListUID) },
                { entryKey, new GuidIndex(new Guid(guid)) }
            };

            if (!ScalarSettingsStoreAccess.IsIndexedKeyDefined(mountPoint, entryKey, dictionary, null, myLogger))
            {
                ScalarSettingsStoreAccess.CreateIndexedKey(mountPoint, entryKey, dictionary, null, myLogger);
            }
            SetValue(mountPoint, (EntrySettings e) => e.EntryName, name, dictionary);
            SetValue(mountPoint, (EntrySettings e) => e.Position, position, dictionary);
        }
        public void InitialiseSolutionSettings(ISettingsStorageMountPoint mountPoint)
        {
            // Navigate to source for external symbols (ensure default value is still set)
            var entry = mySettingsSchema.GetScalarEntry((ExternalSourcesSettings s) => s.NavigationMode);

            ScalarSettingsStoreAccess.SetValue(mountPoint, entry, null, ExternalSourcesNavigationMode.Sources, true,
                                               null, myLogger);

            // Use source files from PDBs, if available (ensure default value is still set)
            // This is the important setting. Without this, we would show decompiled code, even though we can navigate
            // to source from the Unity Explorer
            entry = mySettingsSchema.GetScalarEntry((PdbNavigationSettings s) => s.UseSymbolFiles);
            ScalarSettingsStoreAccess.SetValue(mountPoint, entry, null, true, true, null, myLogger);

            // Allow navigating to private and internal package symbols (not the default)
            entry = mySettingsSchema.GetScalarEntry((ExternalSourcesSettings s) => s.ShowNonPublicCompiledElementsInGoto);
            ScalarSettingsStoreAccess.SetValue(mountPoint, entry, null, true, true, null, myLogger);
        }
        private void ExcludeExternalPackagesFromNamespace(ISettingsStorageMountPoint mountPoint, IProject project)
        {
            // Handle assembly definitions for packages that live outside of the Unity project structure (i.e. not under
            // Assets, Packages or Library/PackageCache), or that lives outside of the solution completely.
            // If the assembly definition lives outside of the solution, this folder will be a link to the assembly
            // definition location, NOT the package root. If it lives in the Unity solution folder, it will be the start
            // of the path to the project root
            foreach (var projectFolder in project.GetSubFolders())
            {
                if (projectFolder.Name.Equals("Assets", StringComparison.OrdinalIgnoreCase) ||
                    projectFolder.Name.Equals("Library", StringComparison.OrdinalIgnoreCase) ||
                    projectFolder.Name.Equals("Packages", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                ExcludePackageRootFolderFromNamespace(mountPoint, projectFolder, projectFolder.Name);
            }
        }
        public override void InitDefaultSettings(ISettingsStorageMountPoint mountPoint)
        {
            InitialiseQuickList(mountPoint, myProjectMainPoint);
            InitialiseQuickList(mountPoint, myFilesMainPoint);

            // TODO: Not sure if this would be better handled in a .dotSettings file
            var pos = 0;

            AddToQuickList(mountPoint, myProjectMainPoint, "MonoBehaviour", ++pos, "5ff5ac38-7207-4256-91ae-b5436552db13");
            AddToQuickList(mountPoint, myProjectMainPoint, "ScriptableObject", ++pos, "1404A333-DA7C-47AC-8CB5-7C944DD1422D");
            AddToQuickList(mountPoint, myProjectMainPoint, "StateMachineBehaviour", ++pos, "AFA01340-773E-488A-93D6-E19540AE2F1B");
            AddToQuickList(mountPoint, myProjectMainPoint, "PlayModeTest", ++pos, "0bcdbc13-d26e-4512-9750-fb930f532e88");
            AddToQuickList(mountPoint, myProjectMainPoint, "CustomEditor", ++pos, "2E5D288C-A209-41EE-93B2-7CACDCAE18C6");
            AddToQuickList(mountPoint, myProjectMainPoint, "EditorWindow", ++pos, "CA9DFEEA-D5B5-4DDC-933F-8D618D71538E");
            AddToQuickList(mountPoint, myProjectMainPoint, "PropertyDrawer", ++pos, "7901AA8B-4060-4763-8FD5-B7B5384FABAA");
            AddToQuickList(mountPoint, myProjectMainPoint, "ScriptableWizard", ++pos, "E1BD73A0-0145-4A1A-B4AA-7744144744AF");
            AddToQuickList(mountPoint, myProjectMainPoint, "AssetPostprocessor", ++pos, "B669492E-B3A6-4F98-9998-9AF480374340");
            AddToQuickList(mountPoint, myProjectMainPoint, "EditModeTest", ++pos, "7b7fa2c7-0ee5-4d4f-bb1f-ddbeacdbfc94");
            AddToQuickList(mountPoint, myProjectMainPoint, "StandardSurfaceShader", ++pos, "4b8178a2-8110-4068-a788-43b8227564e5");
            AddToQuickList(mountPoint, myProjectMainPoint, "UnlitShader", ++pos, "fdbd3ad2-8db2-466a-a934-4ce25cb40564");
            AddToQuickList(mountPoint, myProjectMainPoint, "ImageEffectShader", ++pos, "7b10542b-0a61-4bd8-ba91-e5bad4d39f5b");
            AddToQuickList(mountPoint, myProjectMainPoint, "AsmDef", ++pos, "bf263f0d-4315-42f7-8813-d7afe13fcdeb");
            AddToQuickList(mountPoint, myProjectMainPoint, "EditorEntryPoint", ++pos, "DA24767F-E6BB-4463-ACB4-799D7CE68822");
        }
        public override void InitDefaultSettings(ISettingsStorageMountPoint mountPoint)
        {
            var text = AdditionalFileLayoutResources.DefaultAdditionalFileLayoutPatterns;

            SetValue(mountPoint, (AdditionalFileLayoutSettings s) => s.Pattern, text);
        }
예제 #25
0
 public override void InitDefaultSettings(ISettingsStorageMountPoint mountPoint)
 {
     SetIndexedValue(mountPoint, (CSharpNamingSettings key) => key.UserRules, SerializedFieldRuleGuid,
                     GetUnitySerializedFieldRule());
 }
예제 #26
0
        public void InitialiseSolutionSettings(ISettingsStorageMountPoint mountPoint)
        {
            var entry = mySettingsSchema.GetScalarEntry((CppFormattingSettingsKey s) => s.INDENT_PREPROCESSOR_DIRECTIVES);

            ScalarSettingsStoreAccess.SetValue(mountPoint, entry, null, PreprocessorIndent.Normal, true, null, myLogger);
        }
예제 #27
0
 public override void InitDefaultSettings(ISettingsStorageMountPoint mountPoint)
 {
     SetIndexedValue(mountPoint, UnitySettingsAccessor.UnityClasses, "UnityEngine.MonoBehaviour");
     SetIndexedValue(mountPoint, UnitySettingsAccessor.UnityClasses, "UnityEngine.ScriptableObject");
     SetIndexedValue(mountPoint, UnitySettingsAccessor.UnityAttributes, "UnityEngine.SerializeField");
 }
예제 #28
0
        public void InitialiseProjectSettings(Lifetime projectLifetime, IProject project, ISettingsStorageMountPoint mountPoint)
        {
            if (myInTests)
            {
                return;
            }

            // hide, because for Unity projects this wouldn't work.
            // for Unity we have `UnityRunMarkerProvider` instead.
            var entry = mySettingsSchema.GetScalarEntry((RunMarkerSettings o) => o.ShowMarkerOnStaticMethods);

            ScalarSettingsStoreAccess.SetValue(mountPoint, entry, null, false, true, null, myLogger);
        }
예제 #29
0
        private void SetProjectLangVersion(IProject project, ISettingsStorageMountPoint mountPoint)
        {
            // Only if it's a generated project. Class libraries can use whatever language version they want
            if (!project.IsUnityGeneratedProject())
            {
                return;
            }

            #region Explanation
            // Make sure we don't suggest code changes that won't compile in Unity due to mismatched C# language levels
            // (e.g. C#6 "elvis" operator)
            //
            // * Unity prior to 5.5 uses an old mono compiler that only supports C# 4
            // * Unity 5.5 and later adds C# 6 support as an option. This is enabled by setting
            //   the API compatibility level to NET_4_6
            // * The CSharp60Support plugin replaces the compiler with either C# 6 or C# 7.0 or 8.0
            //   It can be recognised by a folder called `CSharp60Support` or `CSharp70Support` or `CSharp80Support`
            //   in the root of the project
            //   (https://bitbucket.org/alexzzzz/unity-c-5.0-and-6.0-integration)
            // * Note that since Unity 2017.2 till 2018.3, we've been special-cased in the Unity csproj generation
            //   and we've been getting v4.5 for old runtime and default values (4.7.1) for new. So where
            //   it says 3.5 below, that depends on the version of Unity. Older versions will give us 3.5,
            //   newer versions 4.5.
            //
            // Scenarios:
            // * No VSTU installed (including Unity 5.5)
            //   .csproj has NO `LangVersion`. `TargetFrameworkVersion` will be `v3.5`
            // * Early versions of VSTU
            //   .csproj has NO `LangVersion`. `TargetFrameworkVersion` will be `v3.5`
            // * Later versions of VSTU
            //   `LangVersion` is correctly set to "4". `TargetFrameworkVersion` will be `v3.5`
            //   OR `LangVersion` is set to "6" or "latest".
            // * VSTU for 5.5
            //   `LangVersion` is set to "default". `TargetFrameworkVersion` will be `v3.5` or `v4.6`
            //   Note that "default" for VS"15" or Rider will be C# 7.0!
            // * Unity3dRider is installed
            //   Uses Unity's own generation and adds correct `LangVersion`
            //   `TargetFrameworkVersion` will be correct for the selected runtime
            // * CSharp60Support is installed
            //   .csproj has NO `LangVersion`
            //   `TargetFrameworkVersion` is NOT accurate (support for C# 6 is not dependent on/trigger by .net 4.6)
            //   Look for `CSharp60Support` or `CSharp70Support` folders
            // * Unity 2018.x+. LangVersion is `latest`. MSBuild 16 treats `newest` as C# 8. Re# and Rider start suggesting it.
            //
            // Actions:
            // * If `LangVersion` is missing or "default"
            // then override based on `TargetFrameworkVersion` or presence of `CSharp60Support`/`CSharp70Support`
            // else do nothing
            // * If `LangVersion` is "latest"
            // then override based on `CSharp80Support` presence or LangVersion matching Roslyn bundled in Unity
            //
            // Notes:
            // * Unity and VSTU have two separate .csproj routines. VSTU adds extra references,
            //   the VSTU project flavour GUID and imports UnityVs.targets, which disables the
            //   `GenerateTargetFrameworkMonikerAttribute` target
            // * CSharp60Support post-processes the .csproj file directly if VSTU is not installed.
            //   If it is installed, it registers a delegate with `ProjectFilesGenerator.ProjectFileGeneration`
            //   and removes it before it's written to disk
            // * `LangVersion` can be conditionally specified, which makes checking for "default" awkward
            // * If Unity3dRider + CSharp60Support are both installed, last write wins
            //   Order of post-processing is non-deterministic, so Rider's LangVersion might be removed
            #endregion

            var languageLevel = ReSharperSettingsCSharpLanguageLevel.Default;
            if (IsLangVersionMissing(project) || IsLangVersionDefault(project))
            {
                // Support for https://bitbucket.org/alexzzzz/unity-c-5.0-and-6.0-integration
                // See also https://github.com/JetBrains/resharper-unity/issues/50#issuecomment-257611218
                if (project.Location.CombineWithShortName("CSharp70Support").ExistsDirectory)
                {
                    languageLevel = ReSharperSettingsCSharpLanguageLevel.CSharp70;
                }
                else if (project.Location.CombineWithShortName("CSharp60Support").ExistsDirectory)
                {
                    languageLevel = ReSharperSettingsCSharpLanguageLevel.CSharp60;
                }
                else
                {
                    languageLevel = IsTargetFrameworkAtLeast46(project)
                        ? ReSharperSettingsCSharpLanguageLevel.CSharp60
                        : ReSharperSettingsCSharpLanguageLevel.CSharp40;
                }
            }

            if (IsLangVersionLatest(project))
            {
                if (project.Location.CombineWithShortName("CSharp80Support").ExistsDirectory) // https://forum.unity.com/threads/would-the-roslyn-compiler-compile-c-8-0-preview.598069/
                {
                    languageLevel = ReSharperSettingsCSharpLanguageLevel.CSharp80;
                }
                else
                {
                    var appPath     = myUnityProjectFileCache.GetAppPath(project);
                    var contentPath = UnityInstallationFinder.GetApplicationContentsPath(appPath);
                    if (!contentPath.IsNullOrEmpty())
                    {
                        var roslynDir = contentPath.Combine("Tools").Combine("Roslyn");
                        if (roslynDir.ExistsDirectory)
                        {
                            languageLevel = myLanguageLevelProjectProperty.GetLatestAvailableLanguageLevel(roslynDir).ToSettingsLanguageLevel();
                        }
                    }
                }
            }

            // Always set a value. It's either the overridden value, or Default, which resets to whatever is in the
            // project file
            SetValue(mountPoint, (CSharpLanguageProjectSettings s) => s.LanguageLevel, languageLevel);
        }