Exemple #1
0
        protected bool TryGetValidProject(out Project project, out MDKProjectProperties projectProperties)
        {
            var package = (MDKPackage)Package;

            package.Echo("MDK Command", Id, "is attempting to retrieve an MDK project");
            var dte2 = (EnvDTE80.DTE2)Package.DTE;

            project = ((IEnumerable)dte2.ToolWindows.SolutionExplorer.SelectedItems)
                      .OfType <UIHierarchyItem>()
                      .Select(item => item.Object)
                      .OfType <Project>()
                      .FirstOrDefault();
            if (project == null)
            {
                package.Echo("MDK Command", Id, "failed because no project could be found");
                projectProperties = null;
                return(false);
            }
            projectProperties = MDKProjectProperties.Load(project.FullName, project.Name);
            if (projectProperties.IsValid)
            {
                package.Echo("MDK Command", Id, "retrieved a valid project");
                return(true);
            }
            package.Echo("MDK Command", Id, "did not retrieve a valid project");
            return(false);
        }
Exemple #2
0
        bool IsDebugDocument(string filePath, MDKProjectProperties config)
        {
            var fileName = Path.GetFileName(filePath);

            if (string.IsNullOrWhiteSpace(fileName))
            {
                return(true);
            }

            if (fileName.Contains(".NETFramework,Version="))
            {
                return(true);
            }

            if (fileName.EndsWith(".debug", StringComparison.CurrentCultureIgnoreCase))
            {
                return(true);
            }

            if (fileName.IndexOf(".debug.", StringComparison.CurrentCultureIgnoreCase) >= 0)
            {
                return(true);
            }

            return(config.IsIgnoredFilePath(filePath));
        }
        async void Refresh()
        {
            SaveAndCloseCommand.IsEnabled = false;
            CancelCommand.IsEnabled       = false;
            _isWorking = true;
            var cache = new WhitelistCache();
            await cache.RefreshAsync(_package.InstallPath.FullName);

            var dte2     = (EnvDTE80.DTE2)_package.DTE;
            var projects = ((IEnumerable)dte2.ToolWindows.SolutionExplorer.SelectedItems)
                           .OfType <UIHierarchyItem>()
                           .Select(item => item.Object)
                           .OfType <Project>();

            foreach (var project in projects)
            {
                var projectProperties = MDKProjectProperties.Load(project.FullName, project.Name);
                if (projectProperties.IsValid)
                {
                    var targetCacheFile = Path.Combine(Path.GetDirectoryName(projectProperties.FileName) ?? ".", "MDK\\whitelist.cache");
                    var sourceCacheFile = Path.Combine(_package.InstallPath.FullName, "Analyzers\\whitelist.cache");
                    if (File.Exists(sourceCacheFile))
                    {
                        File.Copy(sourceCacheFile, targetCacheFile, true);
                    }
                }
            }

            _isDone = true;
            SaveAndCloseCommand.IsEnabled = true;
            SaveAndClose();
        }
Exemple #4
0
 /// <summary>
 /// Creates a new instance of <see cref="ScriptOptionsDialogModel"/>
 /// </summary>
 /// <param name="package"></param>
 /// <param name="projectProperties"></param>
 public ScriptOptionsDialogModel([NotNull] MDKPackage package, [NotNull] MDKProjectProperties projectProperties)
 {
     if (package == null)
     {
         throw new ArgumentNullException(nameof(package));
     }
     ActiveProject = projectProperties ?? throw new ArgumentNullException(nameof(projectProperties));
 }
Exemple #5
0
        /// <summary>
        /// Composes a script solution into a single <c>Program</c> document
        /// </summary>
        /// <param name="project"></param>
        /// <param name="config"></param>
        /// <returns></returns>
        public async Task <ProgramComposition> ComposeAsync(Project project, MDKProjectProperties config)
        {
            var content = await LoadContentAsync(project, config).ConfigureAwait(false);

            var document = CreateProgramDocument(project, content);

            return(await ProgramComposition.CreateAsync(document, content.Readme).ConfigureAwait(false));
        }
 /// <summary>
 /// Creates a new instance of <see cref="ScriptOptionsDialogModel"/>
 /// </summary>
 /// <param name="package"></param>
 /// <param name="projectProperties"></param>
 public ScriptOptionsDialogModel([NotNull] MDKPackage package, [NotNull] MDKProjectProperties projectProperties)
 {
     if (package == null)
     {
         throw new ArgumentNullException(nameof(package));
     }
     Minifiers = new Collection <KeyValuePair <MinifyLevel, string> >
     {
         new KeyValuePair <MinifyLevel, string>(MinifyLevel.None, "None"),
         new KeyValuePair <MinifyLevel, string>(MinifyLevel.StripComments, "Strip Comments"),
         new KeyValuePair <MinifyLevel, string>(MinifyLevel.Full, "Full"),
     };
     ActiveProject     = projectProperties ?? throw new ArgumentNullException(nameof(projectProperties));
     _selectedMinifier = this.Minifiers.FirstOrDefault(m => ActiveProject.Options.MinifyLevel == m.Key);
 }
Exemple #7
0
        protected bool TryGetValidProject(out Project project, out MDKProjectProperties projectProperties)
        {
            var dte2 = (EnvDTE80.DTE2)Package.DTE;

            project = ((IEnumerable)dte2.ToolWindows.SolutionExplorer.SelectedItems)
                      .OfType <UIHierarchyItem>()
                      .Select(item => item.Object)
                      .OfType <Project>()
                      .FirstOrDefault();
            if (project == null)
            {
                projectProperties = null;
                return(false);
            }
            projectProperties = MDKProjectProperties.Load(project.FullName, project.Name);
            return(projectProperties.IsValid);
        }
Exemple #8
0
        //static char[] GetSymbolChars()
        //{
        //    var chars = new List<char>(50000);
        //    for (var u = 0; u <= ushort.MaxValue; u++)
        //    {
        //        var ch = (char)u;
        //        if (IsDeniedCharacter(ch))
        //            continue;
        //        if (char.IsLetter(ch))
        //            chars.Add(ch);
        //    }
        //    return chars.ToArray();
        //}

        //static bool IsDeniedCharacter(char ch)
        //{
        //    switch (ch)
        //    {
        //        case '\u180E':
        //        case '\u0600':
        //        case '\u00AD':
        //            return true;
        //    }

        //    return false;
        //}

        //static readonly char[] BaseNChars = GetSymbolChars();

        public async Task <ProgramComposition> ProcessAsync([NotNull] ProgramComposition composition, [NotNull] MDKProjectProperties config)
        {
            if (composition == null)
            {
                throw new ArgumentNullException(nameof(composition));
            }
            if (config == null)
            {
                throw new ArgumentNullException(nameof(config));
            }
            var analyzer          = new SymbolAnalyzer();
            var symbolDefinitions = analyzer.FindSymbols(composition, config).ToList();

            symbolDefinitions.Sort((a, b) => a.SyntaxNode.FullSpan.Start);
            var distinctSymbolNames = new HashSet <string>(symbolDefinitions
                                                           .Where(s => !s.IsProtected)
                                                           .Select(s => s.Symbol.Name)
                                                           .Distinct());
            var symbolSrc           = 0;
            var minifiedSymbolNames = distinctSymbolNames
                                      .ToDictionary(n => n, n => GenerateNewName(distinctSymbolNames, ref symbolSrc));

            while (true)
            {
                SymbolDefinitionInfo definition = null;
                string newName = null;
                foreach (var symbolDefinition in symbolDefinitions)
                {
                    if (symbolDefinition.IsProtected)
                    {
                        continue;
                    }
                    if (!minifiedSymbolNames.TryGetValue(symbolDefinition.Symbol.Name, out newName))
                    {
                        continue;
                    }
                    definition = symbolDefinition;
                    break;
                }
                if (definition == null)
                {
                    break;
                }

                var document    = composition.Document;
                var documentId  = document.Id;
                var newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, definition.Symbol, newName, document.Project.Solution.Options);

                composition = await composition.WithDocumentAsync(newSolution.GetDocument(documentId));

                symbolDefinitions = analyzer.FindSymbols(composition, config).ToList();
                symbolDefinitions.Sort((a, b) => a.SyntaxNode.FullSpan.Start);
            }

            return(composition);
        }
Exemple #9
0
        public ImmutableArray <SymbolDefinitionInfo> FindSymbols(ProgramComposition composition, MDKProjectProperties config)
        {
            var root          = composition.RootNode;
            var semanticModel = composition.SemanticModel;

            return(root.DescendantNodes().Where(node => node.IsSymbolDeclaration())
                   .Select(n => new SymbolDefinitionInfo(semanticModel.GetDeclaredSymbol(n), n))
                   .Where(IsNotSpecialDefinitions)
                   .Select(WithUpdatedProtectionFlag)
                   .ToImmutableArray());
        }
Exemple #10
0
        /// <summary>
        /// Generates a final script of the given document. This document has been generated by the build process and
        /// contains the entire script in syntax tree form.
        /// </summary>
        /// <param name="composition"></param>
        /// <param name="config"></param>
        /// <returns></returns>
        public override async Task <string> GenerateAsync(ProgramComposition composition, MDKProjectProperties config)
        {
            //var dumper = new PreserveDebugDumper(@"e:\dump0.txt");
            //dumper.Visit(await composition.Document.GetSyntaxRootAsync());

            var simplifier = new CommentStripper();

            composition = await simplifier.ProcessAsync(composition, config);

            //dumper = new PreserveDebugDumper(@"e:\dump1.txt");
            //dumper.Visit(await composition.Document.GetSyntaxRootAsync());

            return(await GenerateScriptAsync(composition));
        }
Exemple #11
0
 /// <summary>
 /// Generate a Space Engineers script file from the given document
 /// </summary>
 /// <param name="composition"></param>
 /// <param name="config"></param>
 /// <returns></returns>
 public abstract Task <string> GenerateAsync(ProgramComposition composition, MDKProjectProperties config);
Exemple #12
0
        public async Task <ProgramComposition> ProcessAsync(ProgramComposition composition, MDKProjectProperties config)
        {
            var root = composition.RootNode;

            root = Visit(root);
            return(await composition.WithNewDocumentRootAsync(root));
        }
Exemple #13
0
 protected bool TryGetValidProject(out MDKProjectProperties projectProperties)
 => TryGetValidProject(out _, out projectProperties);
Exemple #14
0
        /// <summary>
        /// Generates a final script of the given document. This document has been generated by the build process and
        /// contains the entire script in syntax tree form.
        /// </summary>
        /// <param name="composition"></param>
        /// <param name="config"></param>
        /// <returns></returns>
        public override async Task <string> GenerateAsync(ProgramComposition composition, MDKProjectProperties config)
        {
            var analyzer = new DocumentAnalyzer();
            var result   = await analyzer.AnalyzeAsync(composition.Document);

            var buffer = new StringBuilder();

            var programContent = string.Join("\n", result.Parts.OfType <ProgramScriptPart>().Select(p => p.GenerateContent()));

            buffer.Append(programContent);
            buffer.Append("\n");

            var extensionContent = string.Join("\n", result.Parts.OfType <ExtensionScriptPart>().Select(p => p.GenerateContent()));

            if (!string.IsNullOrWhiteSpace(extensionContent))
            {
                // Extension classes are made possible by forcefully ending Space Engineer's wrapping Program class
                // and removing the final ending brace of the last extension class to let Space Engineers close it
                // for itself.

                // Close off the Program class
                buffer.Append("}\n");
                buffer.Append(extensionContent);
                // Remove the ending brace of the last extension class
                var index = FindEndBrace(buffer);
                if (index >= 0)
                {
                    buffer.Length = index;
                }
            }

            return(TrimPointlessWhitespace(buffer.ToString()));
        }
Exemple #15
0
        public async override Task <string> GenerateAsync(ProgramComposition composition, MDKProjectProperties config)
        {
            //simplify
            var simplifier = new CodeSimplifier();

            composition = await simplifier.ProcessAsync(composition, config);

            //Compact
            var compactor = new WhitespaceCompactor();

            composition = await compactor.ProcessAsync(composition, config);

            //Line Wrapper
            var lineWrapper = new LineWrapper();

            composition = await lineWrapper.ProcessAsync(composition, config);

            return(await base.GenerateScriptAsync(composition));
        }
Exemple #16
0
        async Task <ProjectContent> LoadContentAsync(Project project, MDKProjectProperties config)
        {
            var usingDirectives = ImmutableArray.CreateBuilder <UsingDirectiveSyntax>();
            var parts           = ImmutableArray.CreateBuilder <ScriptPart>();
            var documents       = project.Documents
                                  .Where(document => !IsDebugDocument(document.FilePath, config))
                                  .ToList();

            var readmeDocuments = project.AdditionalDocuments
                                  .Where(document => DirectoryOf(document)?.Equals(Path.GetDirectoryName(project.FilePath), StringComparison.CurrentCultureIgnoreCase) ?? false)
                                  .Where(document => ExtensionOf(document).Equals("readme", StringComparison.CurrentCultureIgnoreCase))
                                  .OrderBy(NameOf)
                                  .ToList();

            var readMe = new StringBuilder();

            for (int i = 0, n = readmeDocuments.Count - 1; i <= n; i++)
            {
                var document = readmeDocuments[i];
                if (i > 0)
                {
                    readMe.Append('\n');
                }
                readMe.Append(await LoadReadMeContentsAsync(document));
            }
            documents.RemoveAll(d => readmeDocuments.Contains(d));
            WrapAsComment(readMe);

            var legacyReadmeDocument = project.Documents
                                       .Where(document => DirectoryOf(document)?.Equals(Path.GetDirectoryName(project.FilePath), StringComparison.CurrentCultureIgnoreCase) ?? false)
                                       .FirstOrDefault(document => NameOf(document).Equals("readme", StringComparison.CurrentCultureIgnoreCase));

            if (legacyReadmeDocument != null)
            {
                documents.Remove(legacyReadmeDocument);
                if (readMe.Length > 0)
                {
                    readMe.Append('\n');
                }
                readMe.Append(await LoadReadMeContentsAsync(legacyReadmeDocument));
            }

            readmeDocuments.Add(legacyReadmeDocument);

            for (var index = 0; index < documents.Count; index++)
            {
                var document = documents[index];
                var result   = await _analyzer.AnalyzeAndTransformAsync(document, Macros).ConfigureAwait(false);

                if (result == null)
                {
                    continue;
                }
                usingDirectives.AddRange(result.UsingDirectives);
                parts.AddRange(result.Parts);
            }

            var comparer = new UsingDirectiveComparer();

            return(new ProjectContent(usingDirectives.Distinct(comparer).ToImmutableArray(), parts.ToImmutable(), readMe.Length > 0? readMe.ToString() : null));
        }
Exemple #17
0
        /// <summary>
        /// Generates a final script of the given document. This document has been generated by the build process and
        /// contains the entire script in syntax tree form.
        /// </summary>
        /// <param name="composition"></param>
        /// <param name="config"></param>
        /// <returns></returns>
        public override async Task <string> GenerateAsync(ProgramComposition composition, MDKProjectProperties config)
        {
            //var dumper = new PreserveDebugDumper(@"e:\dump0.txt");
            //dumper.Visit(await composition.Document.GetSyntaxRootAsync());

            var simplifier = new CodeSimplifier();

            composition = await simplifier.ProcessAsync(composition, config);

            //dumper = new PreserveDebugDumper(@"e:\dump1.txt");
            //dumper.Visit(await composition.Document.GetSyntaxRootAsync());

            var renamer = new SymbolRenamer();

            composition = await renamer.ProcessAsync(composition, config);

            //dumper = new PreserveDebugDumper(@"e:\dump2.txt");
            //dumper.Visit(await composition.Document.GetSyntaxRootAsync());

            var compactor = new WhitespaceCompactor();

            composition = await compactor.ProcessAsync(composition, config);

            //dumper = new PreserveDebugDumper(@"e:\dump3.txt");
            //dumper.Visit(await composition.Document.GetSyntaxRootAsync());

            var lineWrapper = new LineWrapper();

            composition = await lineWrapper.ProcessAsync(composition, config);

            //dumper = new PreserveDebugDumper(@"e:\dump4.txt");
            //dumper.Visit(await composition.Document.GetSyntaxRootAsync());

            return(await GenerateScriptAsync(composition));
        }
Exemple #18
0
        public async Task <ProgramComposition> ProcessAsync(ProgramComposition composition, MDKProjectProperties config)
        {
            _externallyReferencedTypes.Clear();
            var usageAnalyzer = new UsageAnalyzer();
            var typeUsages    = await usageAnalyzer.FindUsagesAsync(composition, config);

            foreach (var typeUsage in typeUsages)
            {
                foreach (var part in typeUsage.Usage)
                {
                    foreach (var location in part.Locations)
                    {
                        var node = composition.RootNode.FindNode(location.Location.SourceSpan);
                        if (IsInProgram(node))
                        {
                            _externallyReferencedTypes.Add(typeUsage.FullName);
                        }
                    }
                }
            }

            var root = composition.RootNode;

            root = Visit(root);
            return(await composition.WithNewDocumentRootAsync(root));
        }
Exemple #19
0
        public async Task <ProgramComposition> ProcessAsync(ProgramComposition composition, MDKProjectProperties config)
        {
            var newDocument = await Simplifier.ReduceAsync(composition.Document).ConfigureAwait(false);

            composition = await(composition.WithDocumentAsync(newDocument).ConfigureAwait(false));

            _externallyReferencedMembers.Clear();

            var root = composition.RootNode;

            root = Visit(root);
            return(await composition.WithNewDocumentRootAsync(root));
        }
Exemple #20
0
        public async Task <ProgramComposition> ProcessAsync([NotNull] ProgramComposition composition, [NotNull] MDKProjectProperties config)
        {
            if (composition == null)
            {
                throw new ArgumentNullException(nameof(composition));
            }
            if (config == null)
            {
                throw new ArgumentNullException(nameof(config));
            }
            var nodes             = new Dictionary <ISymbol, Node>();
            var analyzer          = new UsageAnalyzer();
            var symbolDefinitions = await analyzer.FindUsagesAsync(composition, config);

            var symbolLookup = symbolDefinitions.GroupBy(d => d.Symbol).ToDictionary(g => g.Key, g => g.ToList());
            var rootNode     = composition.RootNode;

            foreach (var definition in symbolDefinitions)
            {
                if (!(definition.Symbol is ITypeSymbol typeSymbol))
                {
                    continue;
                }
                if (typeSymbol.TypeKind == TypeKind.TypeParameter)
                {
                    continue;
                }

                if (!nodes.TryGetValue(definition.Symbol, out var node))
                {
                    nodes[definition.Symbol] = node = new Node(definition);
                }
                else
                {
                    node.Definitions.Add(definition);
                }

                foreach (var usage in definition.Usage)
                {
                    foreach (var location in usage.Locations)
                    {
                        var enclosingSymbol = await FindTypeSymbolAsync(rootNode, location);

                        var enclosingSymbolDefinitions = symbolLookup[enclosingSymbol];
                        if (!nodes.TryGetValue(enclosingSymbol, out var referencingNode))
                        {
                            nodes[enclosingSymbol] = referencingNode = new Node(enclosingSymbolDefinitions);
                        }
                        if (node != referencingNode)
                        {
                            referencingNode.References.Add(node);
                        }
                    }
                }
            }

            var program = symbolDefinitions.FirstOrDefault(d => d.FullName == "Program");

            if (program == null || !nodes.TryGetValue(program.Symbol, out var programNode))
            {
                throw new BuildException(string.Format(Text.TypeTrimmer_ProcessAsync_NoEntryPoint, composition.Document.Project.FilePath));
            }

            var usedNodes    = new List <Node>();
            var queue        = new Queue <Node>();
            var visitedNodes = new HashSet <Node>();

            queue.Enqueue(programNode);
            while (queue.Count > 0)
            {
                var node = queue.Dequeue();
                if (!visitedNodes.Add(node))
                {
                    continue;
                }
                usedNodes.Add(node);
                foreach (var reference in node.References)
                {
                    queue.Enqueue(reference);
                }
            }

            var usedSymbolDefinitions   = usedNodes.SelectMany(n => n.Definitions).ToImmutableHashSet();
            var unusedSymbolDefinitions = symbolDefinitions.Where(definition => IsEligibleForRemoval(definition) && !usedSymbolDefinitions.Contains(definition)).ToList();
            var nodesToRemove           = unusedSymbolDefinitions.Select(definition => definition.FullName).ToImmutableHashSet();

            var walker = new RemovalWalker(nodesToRemove);

            rootNode = walker.Visit(rootNode);
            foreach (var symbol in unusedSymbolDefinitions)
            {
                rootNode = RemoveDefinition(rootNode, symbol);
            }

            return(await composition.WithNewDocumentRootAsync(rootNode));
        }
Exemple #21
0
        public async Task <ProgramComposition> ProcessAsync(ProgramComposition composition, MDKProjectProperties config)
        {
            var newDocument = await Simplifier.ReduceAsync(composition.Document).ConfigureAwait(false);

            composition = await(composition.WithDocumentAsync(newDocument).ConfigureAwait(false));

            _externallyReferencedMembers.Clear();
            var usageAnalyzer = new UsageAnalyzer();
            var typeUsages    = await usageAnalyzer.FindUsagesAsync(composition, config);

            foreach (var typeUsage in typeUsages)
            {
                foreach (var part in typeUsage.Usage)
                {
                    foreach (var location in part.Locations)
                    {
                        var node = composition.RootNode.FindNode(location.Location.SourceSpan);
                        if (!IsInProgram(node))
                        {
                            _externallyReferencedMembers.Add(typeUsage.FullName);
                            if (typeUsage.Symbol is ITypeSymbol typeSymbol)
                            {
                                foreach (var interfaceName in typeSymbol.AllInterfaces.Select(GetFullName))
                                {
                                    _externallyReferencedMembers.Add(interfaceName);
                                }
                                if (typeSymbol.BaseType != null)
                                {
                                    _externallyReferencedMembers.Add(GetFullName(typeSymbol.BaseType));
                                }
                            }
                        }
                    }
                }
            }

            var root = composition.RootNode;

            root = Visit(root);
            return(await composition.WithNewDocumentRootAsync(root));
        }
Exemple #22
0
        public async Task <ImmutableArray <SymbolDefinitionInfo> > FindUsagesAsync(ProgramComposition composition, MDKProjectProperties config)
        {
            var symbolDefinitions = _symbolAnalyzer.FindSymbols(composition, config).ToArray();

            for (var index = 0; index < symbolDefinitions.Length; index++)
            {
                symbolDefinitions[index] = await WithUsageDataAsync(symbolDefinitions[index], composition);
            }

            return(symbolDefinitions.ToImmutableArray());
        }