예제 #1
0
        /// <summary>
        ///     Get hover content for an <see cref="MSBuildUnusedProperty"/>.
        /// </summary>
        /// <param name="unusedProperty">
        ///     The <see cref="MSBuildUnusedProperty"/>.
        /// </param>
        /// <returns>
        ///     The content, or <c>null</c> if no content is provided.
        /// </returns>
        public MarkedStringContainer UnusedProperty(MSBuildUnusedProperty unusedProperty)
        {
            if (unusedProperty == null)
            {
                throw new ArgumentNullException(nameof(unusedProperty));
            }

            List <MarkedString> content = new List <MarkedString>
            {
                $"Unused Property: `{unusedProperty.Name}` (condition is false)"
            };

            string propertyHelp = MSBuildSchemaHelp.ForProperty(unusedProperty.Name);

            if (propertyHelp != null)
            {
                content.Add(propertyHelp);
            }

            content.Add(
                $"Value would have been: `{unusedProperty.Value}`"
                );

            return(new MarkedStringContainer(content));
        }
예제 #2
0
        /// <summary>
        ///     Get hover content for an <see cref="MSBuildProperty"/>.
        /// </summary>
        /// <param name="property">
        ///     The <see cref="MSBuildProperty"/>.
        /// </param>
        /// <returns>
        ///     The content, or <c>null</c> if no content is provided.
        /// </returns>
        public MarkedStringContainer Property(MSBuildProperty property)
        {
            if (property == null)
            {
                throw new ArgumentNullException(nameof(property));
            }

            List <MarkedString> content = new List <MarkedString>
            {
                $"Property: `{property.Name}`"
            };

            string propertyHelp = MSBuildSchemaHelp.ForProperty(property.Name);

            if (propertyHelp != null)
            {
                content.Add(propertyHelp);
            }

            if (property.IsOverridden)
            {
                Position overridingDeclarationPosition = property.DeclaringXml.Location.ToNative();

                StringBuilder overrideDescription = new StringBuilder();
                string        declarationFile     = property.DeclaringXml.Location.File;
                if (declarationFile != property.Property.Xml.Location.File)
                {
                    Uri declarationDocumentUri = VSCodeDocumentUri.FromFileSystemPath(declarationFile);
                    overrideDescription.AppendLine(
                        $"Value overridden at {overridingDeclarationPosition} in [{Path.GetFileName(declarationFile)}]({declarationDocumentUri})."
                        );
                }
                else
                {
                    overrideDescription.AppendLine($"Value overridden at {overridingDeclarationPosition} in this file.");
                }

                overrideDescription.AppendLine();
                overrideDescription.AppendLine();
                overrideDescription.AppendLine(
                    $"Unused value: `{property.DeclaringXml.Value}`"
                    );
                overrideDescription.AppendLine();
                overrideDescription.AppendLine(
                    $"Actual value: `{property.Value}`"
                    );

                content.Add(overrideDescription.ToString());
            }
            else
            {
                content.Add($"Value: `{property.Value}`");
            }

            return(new MarkedStringContainer(content));
        }
        /// <summary>
        ///     Get property element completions.
        /// </summary>
        /// <param name="projectDocument">
        ///     The <see cref="ProjectDocument"/> for which completions will be offered.
        /// </param>
        /// <param name="replaceRange">
        ///     The range of text to be replaced by the completions.
        /// </param>
        /// <returns>
        ///     A sequence of <see cref="CompletionItem"/>s.
        /// </returns>
        public IEnumerable <CompletionItem> GetCompletionItems(ProjectDocument projectDocument, Range replaceRange)
        {
            if (replaceRange == null)
            {
                throw new ArgumentNullException(nameof(replaceRange));
            }

            LspModels.Range replaceRangeLsp = replaceRange.ToLsp();

            HashSet <string> offeredPropertyNames = new HashSet <string>();

            // Well-known properties.
            foreach (string wellKnownPropertyName in MSBuildSchemaHelp.WellKnownPropertyNames)
            {
                if (!offeredPropertyNames.Add(wellKnownPropertyName))
                {
                    continue;
                }

                yield return(PropertyCompletionItem(wellKnownPropertyName, replaceRangeLsp,
                                                    description: MSBuildSchemaHelp.ForProperty(wellKnownPropertyName)
                                                    ));
            }

            if (!projectDocument.HasMSBuildProject)
            {
                yield break; // Without a valid MSBuild project (even a cached one will do), we can't inspect existing MSBuild properties.
            }
            if (!projectDocument.Workspace.Configuration.Language.CompletionsFromProject.Contains(CompletionSource.Property))
            {
                yield break;
            }

            int otherPropertyPriority = Priority + 10;

            string[] otherPropertyNames =
                projectDocument.MSBuildProject.Properties
                .Select(property => property.Name)
                .Where(propertyName => !propertyName.StartsWith("_"))     // Ignore private properties.
                .ToArray();
            foreach (string propertyName in otherPropertyNames)
            {
                if (!offeredPropertyNames.Add(propertyName))
                {
                    continue;
                }

                yield return(PropertyCompletionItem(propertyName, replaceRangeLsp, otherPropertyPriority,
                                                    description: "Property defined in this project (or a project it imports)."
                                                    ));
            }
        }
        /// <summary>
        ///     Get hover content for an <see cref="MSBuildUnusedProperty"/>.
        /// </summary>
        /// <param name="unusedProperty">
        ///     The <see cref="MSBuildUnusedProperty"/>.
        /// </param>
        /// <returns>
        ///     The content, or <c>null</c> if no content is provided.
        /// </returns>
        public MarkedStringContainer UnusedProperty(MSBuildUnusedProperty unusedProperty)
        {
            if (unusedProperty == null)
            {
                throw new ArgumentNullException(nameof(unusedProperty));
            }

            List <MarkedString> content = new List <MarkedString>();

            if (unusedProperty.Element.HasParentPath(WellKnownElementPaths.DynamicPropertyGroup))
            {
                content.Add(
                    $"Dynamic Property: `{unusedProperty.Name}`"
                    );
                content.Add(
                    "(properties declared in targets are only evaluated when building the project)"
                    );
            }
            else
            {
                content.Add(
                    $"Unused Property: `{unusedProperty.Name}` (condition is false)"
                    );
            }

            string propertyHelp = MSBuildSchemaHelp.ForProperty(unusedProperty.Name);

            if (propertyHelp != null)
            {
                content.Add(propertyHelp);
            }

            content.Add(
                $"Value would have been: `{unusedProperty.Value}`"
                );

            string helpLink = MSBuildSchemaHelp.HelpLinkForProperty(unusedProperty.Name);

            if (!String.IsNullOrWhiteSpace(helpLink))
            {
                content.Add(
                    $"[Help]({helpLink})"
                    );
            }

            return(new MarkedStringContainer(content));
        }
        /// <summary>
        ///     Get hover content for an <see cref="MSBuildProperty"/>.
        /// </summary>
        /// <param name="property">
        ///     The <see cref="MSBuildProperty"/>.
        /// </param>
        /// <returns>
        ///     The content, or <c>null</c> if no content is provided.
        /// </returns>
        public MarkedStringContainer Property(MSBuildProperty property)
        {
            if (property == null)
            {
                throw new ArgumentNullException(nameof(property));
            }

            List <MarkedString> content = new List <MarkedString>
            {
                $"Property: `{property.Name}`"
            };

            string propertyHelp = MSBuildSchemaHelp.ForProperty(property.Name);

            if (propertyHelp != null)
            {
                content.Add(propertyHelp);
            }

            if (property.IsOverridden)
            {
                // BUG: This is the location of the *overridden* property, not the *overriding* property.
                //      We'll need to build a lookup by recursively following ProjectProperty.Predecessor.
                Position overridingDeclarationPosition = property.DeclaringXml.Location.ToNative();

                StringBuilder overrideDescription = new StringBuilder();
                string        declarationFile     = property.DeclaringXml.Location.File;
                if (declarationFile != property.Property.Xml.Location.File)
                {
                    Uri declarationDocumentUri = VSCodeDocumentUri.FromFileSystemPath(declarationFile);
                    overrideDescription.AppendLine(
                        $"Value overridden at {overridingDeclarationPosition} in [{Path.GetFileName(declarationFile)}]({declarationDocumentUri})."
                        );
                }
                else
                {
                    overrideDescription.AppendLine($"Value overridden at {overridingDeclarationPosition} in this file.");
                }

                overrideDescription.AppendLine();
                overrideDescription.AppendLine();
                overrideDescription.AppendLine(
                    $"Unused value: `{property.DeclaringXml.Value}`"
                    );
                overrideDescription.AppendLine();
                overrideDescription.AppendLine(
                    $"Actual value: `{property.Value}`"
                    );

                content.Add(overrideDescription.ToString());
            }
            else
            {
                content.Add($"Value: `{property.Value}`");
            }

            string helpLink = MSBuildSchemaHelp.HelpLinkForProperty(property.Name);

            if (!String.IsNullOrWhiteSpace(helpLink))
            {
                content.Add(
                    $"[Help]({helpLink})"
                    );
            }

            return(new MarkedStringContainer(content));
        }
예제 #6
0
        /// <summary>
        ///     Get property element completions.
        /// </summary>
        /// <param name="projectDocument">
        ///     The <see cref="ProjectDocument"/> for which completions will be offered.
        /// </param>
        /// <param name="replaceRange">
        ///     The range of text to be replaced by the completions.
        /// </param>
        /// <returns>
        ///     A sequence of <see cref="CompletionItem"/>s.
        /// </returns>
        public IEnumerable <CompletionItem> GetCompletionItems(ProjectDocument projectDocument, Range replaceRange)
        {
            if (replaceRange == null)
            {
                throw new ArgumentNullException(nameof(replaceRange));
            }

            LspModels.Range replaceRangeLsp = replaceRange.ToLsp();

            HashSet <string> offeredPropertyNames = new HashSet <string>();

            // Special-case properties

            // Output type
            yield return(new CompletionItem
            {
                Label = "<OutputType>",
                Detail = "Property",
                Kind = CompletionItemKind.Property,
                Documentation = MSBuildSchemaHelp.ForProperty("OutputType"),
                SortText = Priority + "<OutputType>",
                TextEdit = new TextEdit
                {
                    NewText = "<OutputType>${1|Library,Exe|}</OutputType>",
                    Range = replaceRangeLsp
                },
                InsertTextFormat = InsertTextFormat.Snippet
            });

            offeredPropertyNames.Add("OutputType");

            // Target framework
            yield return(new CompletionItem
            {
                Label = "<TargetFramework>",
                Detail = "Property",
                Kind = CompletionItemKind.Property,
                Documentation = MSBuildSchemaHelp.ForProperty("TargetFramework"),
                SortText = Priority + "<TargetFramework>",
                TextEdit = new TextEdit
                {
                    NewText = "<TargetFramework>${1|netstandard1.0,netstandard1.1,netstandard1.2,netstandard1.3,netstandard1.4,netstandard1.5,netstandard1.6,netstandard2.0,netcoreapp1.0,netcoreapp1.1,netcoreapp2.0,net4,net451,net452,net46,net461,net462,net47|}</TargetFramework>",
                    Range = replaceRangeLsp
                },
                InsertTextFormat = InsertTextFormat.Snippet
            });

            offeredPropertyNames.Add("TargetFramework");

            // Well-known (but standard-format) properties.

            foreach (string wellKnownPropertyName in MSBuildSchemaHelp.WellKnownPropertyNames)
            {
                if (!offeredPropertyNames.Add(wellKnownPropertyName))
                {
                    continue;
                }

                var propertyDefaults = MSBuildSchemaHelp.DefaultsForProperty(wellKnownPropertyName);

                yield return(PropertyCompletionItem(wellKnownPropertyName, replaceRangeLsp,
                                                    description: MSBuildSchemaHelp.ForProperty(wellKnownPropertyName),
                                                    defaultValue: propertyDefaults.defaultValue,
                                                    defaultValues: propertyDefaults.defaultValues
                                                    ));
            }

            if (!projectDocument.HasMSBuildProject)
            {
                yield break; // Without a valid MSBuild project (even a cached one will do), we can't inspect existing MSBuild properties.
            }
            if (!projectDocument.Workspace.Configuration.Language.CompletionsFromProject.Contains(CompletionSource.Property))
            {
                yield break;
            }

            int otherPropertyPriority = Priority + 10;

            string[] otherPropertyNames =
                projectDocument.MSBuildProject.Properties
                .Select(property => property.Name)
                .Where(propertyName => !propertyName.StartsWith("_"))     // Ignore private properties.
                .ToArray();
            foreach (string propertyName in otherPropertyNames)
            {
                if (!offeredPropertyNames.Add(propertyName))
                {
                    continue;
                }

                yield return(PropertyCompletionItem(propertyName, replaceRangeLsp, otherPropertyPriority,
                                                    description: $"I don't know anything about the '{propertyName}' property, but it's defined in this project (or a project that it imports); you can override its value by specifying it here."
                                                    ));
            }
        }