Beispiel #1
0
        protected override string ProcessRange(ClassifiedRange range, string text)
        {
            if (range.Classification == XmlClassificationTypes.XmlAttributeName)
            {
                text = ProcessAttributeName(range, text, isRootProject);
            }
            else if (range.Classification == XmlClassificationTypes.XmlAttributeValue)
            {
                text = ProcessAttributeValue(range, text, isRootProject);
            }
            else if (range.Classification == XmlClassificationTypes.XmlText || range.Classification == XmlClassificationTypes.None)
            {
                text = ProcessXmlText(range, text, isRootProject);
            }
            else if (range.Classification == XmlClassificationTypes.XmlName)
            {
                text = ProcessXmlName(range, text, isRootProject);
            }
            else
            {
                text = base.ProcessRange(range, text);
            }

            return(text);
        }
        protected void GenerateRange(ClassifiedRange range, StringBuilder sb)
        {
            var text      = range.Text;
            var spanClass = GetSpanClass(range.Classification);

            if (spanClass != null)
            {
                sb.Append("<span class=\"");
                sb.Append(spanClass);
                sb.Append("\">");
            }

            try
            {
                text = ProcessRange(range, text);
            }
            catch (Exception)
            {
                text = Markup.HtmlEscape(range.Text);
            }

            sb.Append(text);
            if (spanClass != null)
            {
                sb.Append("</span>");
            }
        }
Beispiel #3
0
        private string ProcessSemicolonSeparatedList(ClassifiedRange range, string text, bool isRootProject, int currentPosition)
        {
            var sb = new StringBuilder();

            var parts = text.SplitSemicolonSeparatedList();

            foreach (var part in parts)
            {
                if (string.IsNullOrWhiteSpace(part) || part == ";")
                {
                    sb.Append(part);
                }
                else
                {
                    var line       = TextUtilities.GetLineFromPosition(currentPosition, sourceText);
                    var lineNumber = TextUtilities.GetLineNumber(currentPosition, this.lineLengths);
                    var lineText   = sourceText.Substring(line.Item1, line.Item2);
                    var url        = ProcessTargetName(
                        lineText,
                        lineNumber + 1,
                        currentPosition - line.Item1,
                        part,
                        isRootProject,
                        isUsage: true);

                    sb.Append(url);
                }

                currentPosition += part.Length;
            }

            return(sb.ToString());
        }
Beispiel #4
0
        protected void GenerateRange(ClassifiedRange range, StringBuilder sb)
        {
            var text = range.Text;
            var spanClass = GetSpanClass(range.Classification);
            if (spanClass != null)
            {
                sb.Append("<span class=\"");
                sb.Append(spanClass);
                sb.Append("\">");
            }

            try
            {
                text = ProcessRange(range, text);
            }
            catch (Exception)
            {
                text = Markup.HtmlEscape(range.Text);
            }

            sb.Append(text);
            if (spanClass != null)
            {
                sb.Append("</span>");
            }
        }
Beispiel #5
0
        private static ClassifiedRange ChooseBetterRange(ClassifiedRange left, ClassifiedRange right)
        {
            if (left == null)
            {
                return(right);
            }

            if (right == null)
            {
                return(left);
            }

            if (left.IsSemantic != right.IsSemantic)
            {
                if (left.IsSemantic)
                {
                    right.classification = left.classification;
                    return(right);
                }
                else
                {
                    left.classification = right.classification;
                    return(left);
                }
            }

            ClassifiedRange victim = left;
            ClassifiedRange winner = right;

            if (left.classification == "comment")
            {
                victim = left;
                winner = right;
            }

            if (right.classification == "comment")
            {
                victim = right;
                winner = left;
            }

            if (winner.hyperlinks == null && victim.hyperlinks != null)
            {
                winner.hyperlinks = victim.hyperlinks;
            }

            if (winner.classification == "text")
            {
                winner.classification = victim.classification;
            }

            return(winner);
        }
Beispiel #6
0
        private string ProcessXmlText(ClassifiedRange range, string text, bool isRootProject)
        {
            var element = range.Node == null ? null : range.Node.ParentElement;

            if (element != null &&
                element.Name?.EndsWith("DependsOn", StringComparison.Ordinal) == true &&
                element.Parent?.Name == "PropertyGroup")
            {
                return(ProcessExpressions(range, text, isRootProject, ProcessSemicolonSeparatedList));
            }

            return(ProcessExpressions(range, text, isRootProject));
        }
        public static ClassifiedRange[] PrepareRanges(
            ClassifiedRange[] syntacticRanges,
            ClassifiedRange[] semanticRanges,
            string text)
        {
            foreach (var range in semanticRanges)
            {
                range.IsSemantic = true;
            }

            var rangesSortedByStart = syntacticRanges
                .Concat(semanticRanges)
                .Where(r => r.length > 0)
                .OrderBy(r => r.start)
                .ToArray();

            var midpoints = rangesSortedByStart
                .Select(r => r.start)
                .Concat(
                    rangesSortedByStart
                    .Select(r => r.end))
                .Distinct()
                .OrderBy(n => n)
                .ToArray();

            var ranges = RemoveIntersectingRanges(
                text,
                rangesSortedByStart,
                midpoints);

            ranges = RemoveOverlappingRanges(
                text,
                ranges);

            ranges = RangeUtilities.FillGaps(
                text,
                ranges,
                r => r.start,
                r => r.length,
                (s, l, t) => new ClassifiedRange(t, s, l));

            foreach (var range in ranges)
            {
                if (range.text == null)
                {
                    range.text = text.Substring(range.start, range.length);
                }
            }

            return ranges;
        }
Beispiel #8
0
        private string ProcessImportAttributeName(ClassifiedRange range, string text, string importedProjectString)
        {
            foreach (var import in project.Imports)
            {
                if (import.ImportingElement.Project == importedProjectString && Path.GetFullPath(import.ImportingElement.ProjectLocation.File) == this.sourceXmlFilePath)
                {
                    var path = import.ImportedProject.FullPath;
                    var url  = EnsureFileGeneratedAndGetUrl(path, project);
                    text = string.Format("<a href=\"{0}\" class=\"msbuildlink\">{1}</a>", url, text);
                    return(text);
                }
            }

            return(text);
        }
Beispiel #9
0
        public static ClassifiedRange[] RemoveOverlappingRanges(string text, ClassifiedRange[] ranges)
        {
            var output = new List <ClassifiedRange>(ranges.Length);

            for (int i = 0; i < ranges.Length; i++)
            {
                ClassifiedRange best = ranges[i];
                while (i < ranges.Length - 1 && ranges[i].start == ranges[i + 1].start)
                {
                    best = ChooseBetterRange(best, ranges[i + 1]);
                    i++;
                }

                output.Add(best);
            }

            return(output.ToArray());
        }
Beispiel #10
0
        private string ProcessAttributeName(ClassifiedRange range, string text, bool isRootProject)
        {
            var node = range.Node;

            if (node is XmlNameTokenSyntax)
            {
                node = node.Parent;
            }

            var element = node.GetParent(2) as IXmlElement ?? node.GetParent(3) as IXmlElement;

            if (element != null && element.Name == "Import" && text == "Project")
            {
                return(ProcessImportAttributeName(range, text, element["Project"]));
            }

            return(text);
        }
Beispiel #11
0
        private string ProcessXmlName(ClassifiedRange range, string text, bool isRootProject)
        {
            var node   = range.Node;
            var parent = node.Parent;

            if (parent is XmlElementStartTagSyntax)
            {
                if (parent.Parent is IXmlElement element)
                {
                    return(ProcessXmlElementName(range, text, isRootProject, element));
                }
            }
            else if (parent is XmlEmptyElementSyntax)
            {
                if (parent is IXmlElement emptyElement)
                {
                    return(ProcessXmlElementName(range, text, isRootProject, emptyElement));
                }
            }

            return(text);
        }
        private string ProcessXmlName(ClassifiedRange range, string text, bool isRootProject)
        {
            var node = range.Node;
            var parent = node.Parent;
            if (parent is XmlElementStartTagSyntax)
            {
                var element = parent.Parent as IXmlElement;
                if (element != null)
                {
                    return ProcessXmlElementName(range, text, isRootProject, element);
                }
            }
            else if (parent is XmlEmptyElementSyntax)
            {
                var emptyElement = parent as IXmlElement;
                if (emptyElement != null)
                {
                    return ProcessXmlElementName(range, text, isRootProject, emptyElement);
                }
            }

            return text;
        }
Beispiel #13
0
        private string ProcessXmlElementName(ClassifiedRange range, string text, bool isRootProject, IXmlElement element)
        {
            if (element.Name == "UsingTask")
            {
                var taskName = element.Attributes.FirstOrDefault(a => a.Key == "TaskName").Value;
                if (taskName != null)
                {
                    int lastDot = taskName.LastIndexOf('.');
                    if (lastDot > -1)
                    {
                        taskName = taskName.Substring(lastDot + 1);
                    }

                    return(ProcessTaskName(
                               range.LineText,
                               range.LineNumber + 1,
                               range.Column,
                               text,
                               taskName,
                               isRootProject,
                               isUsage: false));
                }
            }

            var parentElement = element.Parent;

            if (parentElement != null)
            {
                if (parentElement.Name == "PropertyGroup")
                {
                    return(ProcessPropertyName(
                               range.LineText,
                               range.LineNumber + 1,
                               range.Column,
                               text,
                               isRootProject,
                               isUsage: false));
                }
                else if (parentElement.Name == "ItemGroup" && !ExcludeItem(element.Name))
                {
                    return(ProcessItemName(
                               range.LineText,
                               range.LineNumber + 1,
                               range.Column,
                               text,
                               isRootProject,
                               isUsage: false));
                }
                else if (parentElement.Name == "Target" && element.Name != "ItemGroup" && element.Name != "PropertyGroup")
                {
                    return(ProcessTaskName(
                               range.LineText,
                               range.LineNumber + 1,
                               range.Column,
                               text,
                               text.Trim(),
                               isRootProject,
                               isUsage: true));
                }
            }

            return(text);
        }
        private string ProcessExpressions(ClassifiedRange range, string text, bool isRootProject, Func<ClassifiedRange, string, bool, int, string> customStringProcessor = null)
        {
            var parts = MSBuildExpressionParser.SplitStringByPropertiesAndItems(text);
            if (parts.Count() == 1 && !text.StartsWith("$(") && !text.StartsWith("@("))
            {
                var processed = text;
                if (customStringProcessor != null)
                {
                    processed = customStringProcessor(range, processed, isRootProject, range.Start);
                }
                else
                {
                    processed = Markup.HtmlEscape(processed);
                }

                return processed;
            }

            var sb = new StringBuilder();
            int lengthSoFar = 0;
            foreach (var part in parts)
            {
                if (part.StartsWith("$(") && part.EndsWith(")") && part.Length > 3)
                {
                    var propertyName = part.Substring(2, part.Length - 3);
                    string suffix = "";
                    int dot = propertyName.IndexOf('.');
                    if (dot > -1)
                    {
                        suffix = propertyName.Substring(dot);
                        propertyName = propertyName.Substring(0, dot);
                    }

                    var currentPosition = range.Start + lengthSoFar;
                    var line = TextUtilities.GetLineFromPosition(currentPosition, sourceText);
                    var lineNumber = TextUtilities.GetLineNumber(currentPosition, this.lineLengths);
                    var lineText = sourceText.Substring(line.Item1, line.Item2);
                    var url = ProcessPropertyName(
                        lineText,
                        lineNumber + 1,
                        currentPosition - line.Item1 + 2,
                        propertyName,
                        isRootProject,
                        isUsage: true);

                    sb.Append("$(" + url + Markup.HtmlEscape(suffix) + ")");
                }
                else if (
                    part.StartsWith("@(") &&
                    (part.EndsWith(")") || part.EndsWith("-") || part.EndsWith(",")) &&
                    !part.Contains("%") &&
                    part.Length > 3)
                {
                    int suffixLength = 1;
                    var itemName = part.Substring(2, part.Length - 2 - suffixLength);
                    string suffix = part.Substring(part.Length - suffixLength, suffixLength);

                    var currentPosition = range.Start + lengthSoFar;
                    var line = TextUtilities.GetLineFromPosition(currentPosition, sourceText);
                    var lineNumber = TextUtilities.GetLineNumber(currentPosition, this.lineLengths);
                    var lineText = sourceText.Substring(line.Item1, line.Item2);
                    var url = ProcessItemName(
                        lineText,
                        lineNumber + 1,
                        currentPosition - line.Item1 + 2,
                        itemName,
                        isRootProject,
                        isUsage: true);

                    sb.Append("@(" + url + Markup.HtmlEscape(suffix));
                }
                else
                {
                    var processed = part;
                    if (customStringProcessor != null)
                    {
                        var currentPosition = range.Start + lengthSoFar;
                        processed = customStringProcessor(range, processed, isRootProject, currentPosition);
                    }
                    else
                    {
                        processed = Markup.HtmlEscape(processed);
                    }

                    sb.Append(processed);
                }

                lengthSoFar += part.Length;
            }

            return sb.ToString();
        }
        public static ClassifiedRange[] RemoveIntersectingRanges(
            string text,
            ClassifiedRange[] rangesSortedByStart,
            int[] midpoints)
        {
            var result = new List<ClassifiedRange>();

            int currentEndpoint = 0;
            int currentRangeIndex = 0;
            for (; currentEndpoint < midpoints.Length && currentRangeIndex < rangesSortedByStart.Length;)
            {
                while (
                    currentRangeIndex < rangesSortedByStart.Length &&
                    rangesSortedByStart[currentRangeIndex].start == midpoints[currentEndpoint])
                {
                    var currentRange = rangesSortedByStart[currentRangeIndex];
                    if (currentRange.end == midpoints[currentEndpoint + 1])
                    {
                        result.Add(currentRange);
                    }
                    else
                    {
                        int endpoint = currentEndpoint;
                        do
                        {
                            result.Add(
                                new ClassifiedRange(
                                    text,
                                    midpoints[endpoint],
                                    midpoints[endpoint + 1] - midpoints[endpoint],
                                    currentRange));
                            endpoint++;
                        }
                        while (endpoint < midpoints.Length && midpoints[endpoint] < currentRange.end);
                    }

                    currentRangeIndex++;
                }

                currentEndpoint++;
            }

            return result.ToArray();
        }
        private string ProcessAttributeValue(ClassifiedRange range, string text, bool isRootProject)
        {
            var node = range.Node;
            var attributeSyntax = node.GetParent(2) as XmlAttributeSyntax;
            if (attributeSyntax != null)
            {
                var parentElement = attributeSyntax.ParentElement;

                if (parentElement != null &&
                    parentElement.Name == "Output" &&
                    (attributeSyntax.Name == "ItemName" || attributeSyntax.Name == "PropertyName") &&
                    !text.Contains("%"))
                {
                    if (attributeSyntax.Name == "ItemName")
                    {
                        return ProcessItemName(
                            range.LineText,
                            range.LineNumber + 1,
                            range.Column,
                            text,
                            isRootProject,
                            isUsage: false);
                    }
                    else
                    {
                        return ProcessPropertyName(
                            range.LineText,
                            range.LineNumber + 1,
                            range.Column,
                            text,
                            isRootProject,
                            isUsage: false);
                    }
                }

                if (parentElement != null && parentElement.Name == "Target")
                {
                    if (attributeSyntax.Name == "Name")
                    {
                        return ProcessTargetName(
                            range.LineText,
                            range.LineNumber + 1,
                            range.Column,
                            text,
                            isRootProject,
                            isUsage: false);
                    }

                    if (attributeSyntax.Name == "DependsOnTargets" ||
                        attributeSyntax.Name == "BeforeTargets" ||
                        attributeSyntax.Name == "AfterTargets")
                    {
                        return ProcessExpressions(range, text, isRootProject, ProcessSemicolonSeparatedList);
                    }
                }

                if (parentElement != null && parentElement.Name == "CallTarget" && attributeSyntax.Name == "Targets")
                {
                    return ProcessExpressions(range, text, isRootProject, ProcessSemicolonSeparatedList);
                }

                if (parentElement != null && parentElement.Name == "UsingTask" && attributeSyntax.Name == "TaskName")
                {
                    var taskName = attributeSyntax.Value;
                    var assemblyFileAttribute = parentElement.Attributes.FirstOrDefault(a => a.Key == "AssemblyFile");
                    var assemblyNameAttribute = parentElement.Attributes.FirstOrDefault(a => a.Key == "AssemblyName");
                    string assemblyName = null;
                    if (!string.IsNullOrWhiteSpace(assemblyFileAttribute.Value))
                    {
                        var assemblyFilePath = assemblyFileAttribute.Value;
                        assemblyFilePath = project.ExpandString(assemblyFilePath);
                        assemblyName = Path.GetFileNameWithoutExtension(assemblyFilePath);
                    }
                    else if (!string.IsNullOrWhiteSpace(assemblyNameAttribute.Value))
                    {
                        assemblyName = assemblyNameAttribute.Value;
                        assemblyName = project.ExpandString(assemblyName);
                        int comma = assemblyName.IndexOf(',');
                        if (comma > -1)
                        {
                            assemblyName = assemblyName.Substring(0, comma);
                        }
                    }

                    if (assemblyName != null)
                    {
                        var symbolId = SymbolIdService.GetId("T:" + taskName);
                        projectGenerator.AddReference(
                            destinationHtmlFilePath,
                            range.LineText,
                            range.Column,
                            taskName.Length,
                            range.LineNumber,
                            isRootProject ? this.projectGenerator.AssemblyName : Constants.MSBuildFiles,
                            assemblyName,
                            null,
                            symbolId,
                            ReferenceKind.Instantiation);

                        var url = string.Format("/{0}/A.html#{1}", assemblyName, symbolId);
                        var result = string.Format("<a href=\"{0}\" class=\"msbuildlink\">{1}</a>", url, text);
                        return result;
                    }
                }
            }

            return ProcessExpressions(range, text, isRootProject);
        }
        private string ProcessImportAttributeName(ClassifiedRange range, string text, string importedProjectString)
        {
            foreach (var import in project.Imports)
            {
                if (import.ImportingElement.Project == importedProjectString && Path.GetFullPath(import.ImportingElement.ProjectLocation.File) == this.sourceXmlFilePath)
                {
                    var path = import.ImportedProject.FullPath;
                    var url = EnsureFileGeneratedAndGetUrl(path, project);
                    text = string.Format("<a href=\"{0}\" class=\"msbuildlink\">{1}</a>", url, text);
                    return text;
                }
            }

            return text;
        }
Beispiel #18
0
        private void GenerateRange(
            StringBuilder sb,
            ClassifiedRange range,
            string destinationFilePath,
            Dictionary <string, int> localSymbolIdMap)
        {
            var html = range.text;

            html = Markup.HtmlEscape(html);

            var localRelativePath = destinationFilePath.Substring(
                Path.Combine(
                    Paths.SolutionDestinationFolder,
                    Constants.TypeScriptFiles).Length + 1);

            localRelativePath = localRelativePath.Substring(0, localRelativePath.Length - ".html".Length);

            string          classAttributeValue = GetSpanClass(range.classification);
            HtmlElementInfo hyperlinkInfo       = GenerateLinks(range, destinationFilePath, localSymbolIdMap);

            if (hyperlinkInfo == null)
            {
                if (classAttributeValue == null)
                {
                    sb.Append(html);
                    return;
                }

                if (classAttributeValue == "k")
                {
                    sb.Append("<b>").Append(html).Append("</b>");
                    return;
                }
            }

            var elementName = "span";

            if (hyperlinkInfo != null)
            {
                elementName = hyperlinkInfo.Name;
            }

            sb.Append("<").Append(elementName);
            bool overridingClassAttributeSpecified = false;

            if (hyperlinkInfo != null)
            {
                foreach (var attribute in hyperlinkInfo.Attributes)
                {
                    const string typeScriptFilesR = "/TypeScriptFiles/R/";
                    if (attribute.Key == "href" && attribute.Value.StartsWith(typeScriptFilesR, StringComparison.Ordinal))
                    {
                        var streamPosition = sb.Length + 7 + typeScriptFilesR.Length; // exact offset into <a href="HERE
                        ProjectGenerator.AddDeclaredSymbolToRedirectMap(
                            SymbolIDToListOfLocationsMap,
                            attribute.Value.Substring(typeScriptFilesR.Length, 16),
                            localRelativePath,
                            streamPosition);
                    }

                    AddAttribute(sb, attribute.Key, attribute.Value);
                    if (attribute.Key == "class")
                    {
                        overridingClassAttributeSpecified = true;
                    }
                }
            }

            if (!overridingClassAttributeSpecified)
            {
                AddAttribute(sb, "class", classAttributeValue);
            }

            sb.Append('>');

            sb.Append(html);
            sb.Append("</").Append(elementName).Append(">");
        }
        private HtmlElementInfo GenerateLinks(ClassifiedRange range, string destinationHtmlFilePath, Dictionary<string, int> localSymbolIdMap)
        {
            HtmlElementInfo result = null;

            var localRelativePath = destinationHtmlFilePath.Substring(
                Path.Combine(
                    Paths.SolutionDestinationFolder,
                    Constants.TypeScriptFiles).Length);

            if (!string.IsNullOrEmpty(range.definitionSymbolId))
            {
                var definitionSymbolId = SymbolIdService.GetId(range.definitionSymbolId);

                if (range.IsSymbolLocalOnly())
                {
                    var localId = GetLocalId(definitionSymbolId, localSymbolIdMap);
                    result = new HtmlElementInfo
                    {
                        Name = "span",
                        Attributes =
                        {
                            { "id", "r" + localId + " rd" },
                            { "class", "r" + localId + " r" }
                        }
                    };
                    return result;
                }

                result = new HtmlElementInfo
                {
                    Name = "a",
                    Attributes =
                    {
                        { "id", definitionSymbolId },
                        { "href", "/TypeScriptFiles/" + Constants.ReferencesFileName + "/" + definitionSymbolId + ".html" },
                        { "target", "n" }
                    }
                };

                var searchString = range.searchString;
                if (!string.IsNullOrEmpty(searchString) && searchString.Length > 2)
                {
                    lock (declarations)
                    {
                        searchString = searchString.StripQuotes();
                        if (IsWellFormed(searchString))
                        {
                            var declaration = string.Join(";",
                                searchString, // symbol name
                                definitionSymbolId, // 8-byte symbol ID
                                range.definitionKind, // kind (e.g. "class")
                                Markup.EscapeSemicolons(range.fullName), // symbol full name and signature
                                GetGlyph(range.definitionKind) // glyph number
                            );
                            declarations.Add(declaration);
                        }
                    }
                }
            }

            if (range.hyperlinks == null || range.hyperlinks.Length == 0)
            {
                return result;
            }

            var hyperlink = range.hyperlinks[0];
            var symbolId = SymbolIdService.GetId(hyperlink.symbolId);

            if (range.IsSymbolLocalOnly() || localSymbolIdMap.ContainsKey(symbolId))
            {
                var localId = GetLocalId(symbolId, localSymbolIdMap);
                result = new HtmlElementInfo
                {
                    Name = "span",
                    Attributes =
                    {
                        { "class", "r" + localId + " r" }
                    }
                };
                return result;
            }

            var hyperlinkDestinationFile = Path.GetFullPath(hyperlink.sourceFile);
            hyperlinkDestinationFile = GetDestinationFilePath(hyperlinkDestinationFile);

            string href = "";
            if (!string.Equals(hyperlinkDestinationFile, destinationHtmlFilePath, StringComparison.OrdinalIgnoreCase))
            {
                href = Paths.MakeRelativeToFile(hyperlinkDestinationFile, destinationHtmlFilePath);
                href = href.Replace('\\', '/');
            }

            href = href + "#" + symbolId;

            if (result == null)
            {
                result = new HtmlElementInfo
                {
                    Name = "a",
                    Attributes =
                    {
                        { "href", href },
                        { "target", "s" },
                    }
                };
            }
            else if (!result.Attributes.ContainsKey("href"))
            {
                result.Attributes.Add("href", href);
                result.Attributes.Add("target", "s");
            }

            lock (this.references)
            {
                var lineNumber = range.lineNumber + 1;
                var linkToReference = ".." + localRelativePath + "#" + lineNumber.ToString();
                var start = range.column;
                var end = range.column + range.text.Length;
                var lineText = Markup.HtmlEscape(range.lineText, ref start, ref end);
                var reference = new Reference
                {
                    FromAssemblyId = Constants.TypeScriptFiles,
                    ToAssemblyId = Constants.TypeScriptFiles,
                    FromLocalPath = localRelativePath.Substring(0, localRelativePath.Length - ".html".Length).Replace('\\', '/'),
                    Kind = ReferenceKind.Reference,
                    ToSymbolId = symbolId,
                    ToSymbolName = range.text,
                    ReferenceLineNumber = lineNumber,
                    ReferenceLineText = lineText,
                    ReferenceColumnStart = start,
                    ReferenceColumnEnd = end,
                    Url = linkToReference.Replace('\\', '/')
                };

                List<Reference> bucket = null;
                if (!references.TryGetValue(symbolId, out bucket))
                {
                    bucket = new List<Reference>();
                    references.Add(symbolId, bucket);
                }

                bucket.Add(reference);
            }

            return result;
        }
        private void Generate(
            string sourceFilePath,
            string destinationHtmlFilePath,
            ClassifiedRange[] syntacticRanges,
            ClassifiedRange[] semanticRanges)
        {
            Log.Write(destinationHtmlFilePath);
            var sb = new StringBuilder();

            var lines = File.ReadAllLines(sourceFilePath);
            var text = File.ReadAllText(sourceFilePath);
            var lineCount = lines.Length;
            var lineLengths = TextUtilities.GetLineLengths(text);

            var ranges = PrepareRanges(syntacticRanges, semanticRanges, text);

            var relativePathToRoot = Paths.CalculateRelativePathToRoot(destinationHtmlFilePath, Paths.SolutionDestinationFolder);

            var prefix = Markup.GetDocumentPrefix(Path.GetFileName(sourceFilePath), relativePathToRoot, lineCount, "ix");
            sb.Append(prefix);

            var displayName = GetDisplayName(destinationHtmlFilePath);
            var assemblyName = "TypeScriptFiles";

            var url = "/#" + assemblyName + "/" + displayName.Replace('\\', '/');
            displayName = @"\\" + displayName;

            var file = string.Format("File: <a id=\"filePath\" class=\"blueLink\" href=\"{0}\" target=\"_top\">{1}</a><br/>", url, displayName);
            var row = string.Format("<tr><td>{0}</td></tr>", file);
            Markup.WriteLinkPanel(s => sb.AppendLine(s), row);

            // pass a value larger than 0 to generate line numbers statically at HTML generation time
            var table = Markup.GetTablePrefix();
            sb.AppendLine(table);

            var localSymbolIdMap = new Dictionary<string, int>();

            foreach (var range in ranges)
            {
                range.lineNumber = TextUtilities.GetLineNumber(range.start, lineLengths);
                var line = TextUtilities.GetLineFromPosition(range.start, text);
                range.column = range.start - line.Item1;
                range.lineText = text.Substring(line.Item1, line.Item2);

                GenerateRange(sb, range, destinationHtmlFilePath, localSymbolIdMap);
            }

            var suffix = Markup.GetDocumentSuffix();
            sb.AppendLine(suffix);

            var folder = Path.GetDirectoryName(destinationHtmlFilePath);
            Directory.CreateDirectory(folder);
            File.WriteAllText(destinationHtmlFilePath, sb.ToString());
        }
        private static ClassifiedRange ChooseBetterRange(ClassifiedRange left, ClassifiedRange right)
        {
            if (left == null)
            {
                return right;
            }

            if (right == null)
            {
                return left;
            }

            if (left.IsSemantic != right.IsSemantic)
            {
                if (left.IsSemantic)
                {
                    right.classification = left.classification;
                    return right;
                }
                else
                {
                    left.classification = right.classification;
                    return left;
                }
            }

            ClassifiedRange victim = left;
            ClassifiedRange winner = right;

            if (left.classification == "comment")
            {
                victim = left;
                winner = right;
            }

            if (right.classification == "comment")
            {
                victim = right;
                winner = left;
            }

            if (winner.hyperlinks == null && victim.hyperlinks != null)
            {
                winner.hyperlinks = victim.hyperlinks;
            }

            if (winner.classification == "text")
            {
                winner.classification = victim.classification;
            }

            return winner;
        }
        public static ClassifiedRange[] RemoveOverlappingRanges(string text, ClassifiedRange[] ranges)
        {
            var output = new List<ClassifiedRange>(ranges.Length);

            for (int i = 0; i < ranges.Length; i++)
            {
                ClassifiedRange best = ranges[i];
                while (i < ranges.Length - 1 && ranges[i].start == ranges[i + 1].start)
                {
                    best = ChooseBetterRange(best, ranges[i + 1]);
                    i++;
                }

                output.Add(best);
            }

            return output.ToArray();
        }
Beispiel #23
0
        private string ProcessAttributeValue(ClassifiedRange range, string text, bool isRootProject)
        {
            var node            = range.Node;
            var attributeSyntax = node.GetParent(2) as XmlAttributeSyntax;

            if (attributeSyntax != null)
            {
                var parentElement = attributeSyntax.ParentElement;

                if (parentElement?.Name == "Output" &&
                    (attributeSyntax.Name == "ItemName" || attributeSyntax.Name == "PropertyName") &&
                    !text.Contains("%"))
                {
                    if (attributeSyntax.Name == "ItemName")
                    {
                        return(ProcessItemName(
                                   range.LineText,
                                   range.LineNumber + 1,
                                   range.Column,
                                   text,
                                   isRootProject,
                                   isUsage: false));
                    }
                    else
                    {
                        return(ProcessPropertyName(
                                   range.LineText,
                                   range.LineNumber + 1,
                                   range.Column,
                                   text,
                                   isRootProject,
                                   isUsage: false));
                    }
                }

                if (parentElement?.Name == "Target")
                {
                    if (attributeSyntax.Name == "Name")
                    {
                        return(ProcessTargetName(
                                   range.LineText,
                                   range.LineNumber + 1,
                                   range.Column,
                                   text,
                                   isRootProject,
                                   isUsage: false));
                    }

                    if (attributeSyntax.Name == "DependsOnTargets" ||
                        attributeSyntax.Name == "BeforeTargets" ||
                        attributeSyntax.Name == "AfterTargets")
                    {
                        return(ProcessExpressions(range, text, isRootProject, ProcessSemicolonSeparatedList));
                    }
                }

                if (parentElement?.Name == "CallTarget" && attributeSyntax.Name == "Targets")
                {
                    return(ProcessExpressions(range, text, isRootProject, ProcessSemicolonSeparatedList));
                }

                if (parentElement?.Name == "UsingTask" && attributeSyntax.Name == "TaskName")
                {
                    var    taskName = attributeSyntax.Value;
                    var    assemblyFileAttribute = parentElement.Attributes.FirstOrDefault(a => a.Name == "AssemblyFile");
                    var    assemblyNameAttribute = parentElement.Attributes.FirstOrDefault(a => a.Name == "AssemblyName");
                    string assemblyName          = null;
                    if (assemblyFileAttribute != null && !string.IsNullOrWhiteSpace(assemblyFileAttribute.Value))
                    {
                        var assemblyFilePath = assemblyFileAttribute.Value;
                        assemblyFilePath = project.ExpandString(assemblyFilePath);
                        assemblyName     = Path.GetFileNameWithoutExtension(assemblyFilePath);
                    }
                    else if (assemblyNameAttribute != null && !string.IsNullOrWhiteSpace(assemblyNameAttribute.Value))
                    {
                        assemblyName = assemblyNameAttribute.Value;
                        assemblyName = project.ExpandString(assemblyName);
                        int comma = assemblyName.IndexOf(',');
                        if (comma > -1)
                        {
                            assemblyName = assemblyName.Substring(0, comma);
                        }
                    }

                    if (assemblyName != null)
                    {
                        var symbolId = SymbolIdService.GetId("T:" + taskName);
                        ProjectGenerator.AddReference(
                            destinationHtmlFilePath,
                            range.LineText,
                            range.Column,
                            taskName.Length,
                            range.LineNumber,
                            isRootProject ? ProjectGenerator.AssemblyName : Constants.MSBuildFiles,
                            assemblyName,
                            null,
                            symbolId,
                            ReferenceKind.Instantiation);

                        var url    = string.Format("/{0}/A.html#{1}", assemblyName, symbolId);
                        var result = string.Format("<a href=\"{0}\" class=\"msbuildlink\">{1}</a>", url, text);
                        return(result);
                    }
                }
            }

            return(ProcessExpressions(range, text, isRootProject));
        }
Beispiel #24
0
        private string ProcessExpressions(ClassifiedRange range, string text, bool isRootProject, Func <ClassifiedRange, string, bool, int, string> customStringProcessor = null)
        {
            var parts = MSBuildExpressionParser.SplitStringByPropertiesAndItems(text);

            if (parts.Count() == 1 && !text.StartsWith("$(", StringComparison.Ordinal) && !text.StartsWith("@(", StringComparison.Ordinal))
            {
                var processed = text;
                if (customStringProcessor != null)
                {
                    return(customStringProcessor(range, processed, isRootProject, range.Start));
                }
                else
                {
                    return(Markup.HtmlEscape(processed));
                }
            }

            var sb          = new StringBuilder();
            int lengthSoFar = 0;

            foreach (var part in parts)
            {
                if (part.StartsWith("$(", StringComparison.Ordinal) && part.EndsWith(")", StringComparison.Ordinal) && part.Length > 3)
                {
                    var    propertyName = part.Substring(2, part.Length - 3);
                    string suffix       = "";
                    int    dot          = propertyName.IndexOf('.');
                    if (dot > -1)
                    {
                        suffix       = propertyName.Substring(dot);
                        propertyName = propertyName.Substring(0, dot);
                    }

                    var currentPosition = range.Start + lengthSoFar;
                    var line            = TextUtilities.GetLineFromPosition(currentPosition, sourceText);
                    var lineNumber      = TextUtilities.GetLineNumber(currentPosition, this.lineLengths);
                    var lineText        = sourceText.Substring(line.Item1, line.Item2);
                    var url             = ProcessPropertyName(
                        lineText,
                        lineNumber + 1,
                        currentPosition - line.Item1 + 2,
                        propertyName,
                        isRootProject,
                        isUsage: true);

                    sb.Append("$(" + url + Markup.HtmlEscape(suffix) + ")");
                }
                else if (
                    part.StartsWith("@(", StringComparison.Ordinal) &&
                    (part.EndsWith(")", StringComparison.Ordinal) || part.EndsWith("-", StringComparison.Ordinal) || part.EndsWith(",", StringComparison.Ordinal)) &&
                    !part.Contains("%") &&
                    part.Length > 3)
                {
                    const int suffixLength = 1;
                    var       itemName     = part.Substring(2, part.Length - 2 - suffixLength);
                    string    suffix       = part.Substring(part.Length - suffixLength, suffixLength);

                    var currentPosition = range.Start + lengthSoFar;
                    var line            = TextUtilities.GetLineFromPosition(currentPosition, sourceText);
                    var lineNumber      = TextUtilities.GetLineNumber(currentPosition, this.lineLengths);
                    var lineText        = sourceText.Substring(line.Item1, line.Item2);
                    var url             = ProcessItemName(
                        lineText,
                        lineNumber + 1,
                        currentPosition - line.Item1 + 2,
                        itemName,
                        isRootProject,
                        isUsage: true);

                    sb.Append("@(").Append(url).Append(Markup.HtmlEscape(suffix));
                }
                else
                {
                    var processed = part;
                    if (customStringProcessor != null)
                    {
                        var currentPosition = range.Start + lengthSoFar;
                        processed = customStringProcessor(range, processed, isRootProject, currentPosition);
                    }
                    else
                    {
                        processed = Markup.HtmlEscape(processed);
                    }

                    sb.Append(processed);
                }

                lengthSoFar += part.Length;
            }

            return(sb.ToString());
        }
        private string ProcessXmlElementName(ClassifiedRange range, string text, bool isRootProject, IXmlElement element)
        {
            if (element.Name == "UsingTask")
            {
                var taskName = element.Attributes.FirstOrDefault(a => a.Key == "TaskName").Value;
                if (taskName != null)
                {
                    int lastDot = taskName.LastIndexOf(".");
                    if (lastDot > -1)
                    {
                        taskName = taskName.Substring(lastDot + 1);
                    }

                    return ProcessTaskName(
                        range.LineText,
                        range.LineNumber + 1,
                        range.Column,
                        text,
                        taskName,
                        isRootProject,
                        isUsage: false);
                }
            }

            var parentElement = element.Parent;
            if (parentElement != null)
            {
                if (parentElement.Name == "PropertyGroup")
                {
                    return ProcessPropertyName(
                        range.LineText,
                        range.LineNumber + 1,
                        range.Column,
                        text,
                        isRootProject,
                        isUsage: false);
                }
                else if (parentElement.Name == "ItemGroup" && !ExcludeItem(element.Name))
                {
                    return ProcessItemName(
                        range.LineText,
                        range.LineNumber + 1,
                        range.Column,
                        text,
                        isRootProject,
                        isUsage: false);
                }
                else if (parentElement.Name == "Target" && element.Name != "ItemGroup" && element.Name != "PropertyGroup")
                {
                    return ProcessTaskName(
                        range.LineText,
                        range.LineNumber + 1,
                        range.Column,
                        text,
                        text.Trim(),
                        isRootProject,
                        isUsage: true);
                }
            }

            return text;
        }
        private string ProcessAttributeName(ClassifiedRange range, string text, bool isRootProject)
        {
            var node = range.Node;
            if (node is XmlNameTokenSyntax)
            {
                node = node.Parent;
            }

            var element = node.GetParent(2) as IXmlElement ?? node.GetParent(3) as IXmlElement;
            if (element != null)
            {
                if (element.Name == "Import" && text == "Project")
                {
                    return ProcessImportAttributeName(range, text, element["Project"]);
                }
            }

            return text;
        }
        private string ProcessXmlText(ClassifiedRange range, string text, bool isRootProject)
        {
            var element = range.Node == null ? null : range.Node.ParentElement;
            if (element != null &&
                element.Name != null &&
                element.Name.EndsWith("DependsOn") &&
                element.Parent != null &&
                element.Parent.Name == "PropertyGroup")
            {
                return ProcessExpressions(range, text, isRootProject, ProcessSemicolonSeparatedList);
            }

            return ProcessExpressions(range, text, isRootProject);
        }
Beispiel #28
0
 protected virtual string ProcessRange(ClassifiedRange range, string text)
 {
     text = Markup.HtmlEscape(text);
     return text;
 }
        private string ProcessSemicolonSeparatedList(ClassifiedRange range, string text, bool isRootProject, int currentPosition)
        {
            var sb = new StringBuilder();

            var parts = TextUtilities.SplitSemicolonSeparatedList(text);
            foreach (var part in parts)
            {
                if (string.IsNullOrWhiteSpace(part) || part == ";")
                {
                    sb.Append(part);
                }
                else
                {
                    var line = TextUtilities.GetLineFromPosition(currentPosition, sourceText);
                    var lineNumber = TextUtilities.GetLineNumber(currentPosition, this.lineLengths);
                    var lineText = sourceText.Substring(line.Item1, line.Item2);
                    var url = ProcessTargetName(
                        lineText,
                        lineNumber + 1,
                        currentPosition - line.Item1,
                        part,
                        isRootProject,
                        isUsage: true);

                    sb.Append(url);
                }

                currentPosition += part.Length;
            }

            return sb.ToString();
        }
Beispiel #30
0
        private HtmlElementInfo GenerateLinks(ClassifiedRange range, string destinationHtmlFilePath, Dictionary <string, int> localSymbolIdMap)
        {
            HtmlElementInfo result = null;

            var localRelativePath = destinationHtmlFilePath.Substring(
                Path.Combine(
                    Paths.SolutionDestinationFolder,
                    Constants.TypeScriptFiles).Length);

            if (!string.IsNullOrEmpty(range.definitionSymbolId))
            {
                var definitionSymbolId = SymbolIdService.GetId(range.definitionSymbolId);

                if (range.IsSymbolLocalOnly())
                {
                    var localId = GetLocalId(definitionSymbolId, localSymbolIdMap);
                    result = new HtmlElementInfo
                    {
                        Name       = "span",
                        Attributes =
                        {
                            { "id",    "r" + localId + " rd" },
                            { "class", "r" + localId + " r"  }
                        }
                    };
                    return(result);
                }

                result = new HtmlElementInfo
                {
                    Name       = "a",
                    Attributes =
                    {
                        { "id",     definitionSymbolId                                                                      },
                        { "href",   "/TypeScriptFiles/" + Constants.ReferencesFileName + "/" + definitionSymbolId + ".html" },
                        { "target", "n"                                                                                     }
                    }
                };

                var searchString = range.searchString;
                if (!string.IsNullOrEmpty(searchString) && searchString.Length > 2)
                {
                    lock (declarations)
                    {
                        searchString = searchString.StripQuotes();
                        if (IsWellFormed(searchString))
                        {
                            var declaration = string.Join(";",
                                                          searchString,                            // symbol name
                                                          definitionSymbolId,                      // 8-byte symbol ID
                                                          range.definitionKind,                    // kind (e.g. "class")
                                                          Markup.EscapeSemicolons(range.fullName), // symbol full name and signature
                                                          GetGlyph(range.definitionKind)           // glyph number
                                                          );
                            declarations.Add(declaration);
                        }
                    }
                }
            }

            if (range.hyperlinks == null || range.hyperlinks.Length == 0)
            {
                return(result);
            }

            var hyperlink = range.hyperlinks[0];
            var symbolId  = SymbolIdService.GetId(hyperlink.symbolId);

            if (range.IsSymbolLocalOnly() || localSymbolIdMap.ContainsKey(symbolId))
            {
                var localId = GetLocalId(symbolId, localSymbolIdMap);
                result = new HtmlElementInfo
                {
                    Name       = "span",
                    Attributes =
                    {
                        { "class", "r" + localId + " r" }
                    }
                };
                return(result);
            }

            var hyperlinkDestinationFile = Path.GetFullPath(hyperlink.sourceFile);

            hyperlinkDestinationFile = GetDestinationFilePath(hyperlinkDestinationFile);

            string href = "";

            if (!string.Equals(hyperlinkDestinationFile, destinationHtmlFilePath, StringComparison.OrdinalIgnoreCase))
            {
                href = Paths.MakeRelativeToFile(hyperlinkDestinationFile, destinationHtmlFilePath);
                href = href.Replace('\\', '/');
            }

            href = href + "#" + symbolId;

            if (result == null)
            {
                result = new HtmlElementInfo
                {
                    Name       = "a",
                    Attributes =
                    {
                        { "href",   href },
                        { "target", "s"  },
                    }
                };
            }
            else if (!result.Attributes.ContainsKey("href"))
            {
                result.Attributes.Add("href", href);
                result.Attributes.Add("target", "s");
            }

            lock (this.references)
            {
                var lineNumber      = range.lineNumber + 1;
                var linkToReference = ".." + localRelativePath + "#" + lineNumber.ToString();
                var start           = range.column;
                var end             = range.column + range.text.Length;
                var lineText        = Markup.HtmlEscape(range.lineText, ref start, ref end);
                var reference       = new Reference
                {
                    FromAssemblyId       = Constants.TypeScriptFiles,
                    ToAssemblyId         = Constants.TypeScriptFiles,
                    FromLocalPath        = localRelativePath.Substring(0, localRelativePath.Length - ".html".Length).Replace('\\', '/'),
                    Kind                 = ReferenceKind.Reference,
                    ToSymbolId           = symbolId,
                    ToSymbolName         = range.text,
                    ReferenceLineNumber  = lineNumber,
                    ReferenceLineText    = lineText,
                    ReferenceColumnStart = start,
                    ReferenceColumnEnd   = end,
                    Url = linkToReference.Replace('\\', '/')
                };

                if (!references.TryGetValue(symbolId, out List <Reference> bucket))
                {
                    bucket = new List <Reference>();
                    references.Add(symbolId, bucket);
                }

                bucket.Add(reference);
            }

            return(result);
        }
        private void GenerateRange(
            StringBuilder sb,
            ClassifiedRange range,
            string destinationFilePath,
            Dictionary<string, int> localSymbolIdMap)
        {
            var html = range.text;
            html = Markup.HtmlEscape(html);

            var localRelativePath = destinationFilePath.Substring(
                Path.Combine(
                    Paths.SolutionDestinationFolder,
                    Constants.TypeScriptFiles).Length + 1);
            localRelativePath = localRelativePath.Substring(0, localRelativePath.Length - ".html".Length);

            string classAttributeValue = GetSpanClass(range.classification);
            HtmlElementInfo hyperlinkInfo = GenerateLinks(range, destinationFilePath, localSymbolIdMap);

            if (hyperlinkInfo == null)
            {
                if (classAttributeValue == null)
                {
                    sb.Append(html);
                    return;
                }

                if (classAttributeValue == "k")
                {
                    sb.Append("<b>" + html + "</b>");
                    return;
                }
            }

            var elementName = "span";
            if (hyperlinkInfo != null)
            {
                elementName = hyperlinkInfo.Name;
            }

            sb.Append("<" + elementName);
            bool overridingClassAttributeSpecified = false;
            if (hyperlinkInfo != null)
            {
                foreach (var attribute in hyperlinkInfo.Attributes)
                {
                    const string typeScriptFilesR = "/TypeScriptFiles/R/";
                    if (attribute.Key == "href" && attribute.Value.StartsWith(typeScriptFilesR))
                    {
                        var streamPosition = sb.Length + 7 + typeScriptFilesR.Length; // exact offset into <a href="HERE
                        ProjectGenerator.AddDeclaredSymbolToRedirectMap(
                            SymbolIDToListOfLocationsMap,
                            attribute.Value.Substring(typeScriptFilesR.Length, 16),
                            localRelativePath,
                            streamPosition);
                    }

                    AddAttribute(sb, attribute.Key, attribute.Value);
                    if (attribute.Key == "class")
                    {
                        overridingClassAttributeSpecified = true;
                    }
                }
            }

            if (!overridingClassAttributeSpecified)
            {
                AddAttribute(sb, "class", classAttributeValue);
            }

            sb.Append('>');

            sb.Append(html);
            sb.Append("</" + elementName + ">");
        }
 protected virtual string ProcessRange(ClassifiedRange range, string text)
 {
     text = Markup.HtmlEscape(text);
     return(text);
 }
        protected override string ProcessRange(ClassifiedRange range, string text)
        {
            if (range.Classification == XmlClassificationTypes.XmlAttributeName)
            {
                text = ProcessAttributeName(range, text, isRootProject);
            }
            else if (range.Classification == XmlClassificationTypes.XmlAttributeValue)
            {
                text = ProcessAttributeValue(range, text, isRootProject);
            }
            else if (range.Classification == XmlClassificationTypes.XmlText || range.Classification == XmlClassificationTypes.None)
            {
                text = ProcessXmlText(range, text, isRootProject);
            }
            else if (range.Classification == XmlClassificationTypes.XmlName)
            {
                text = ProcessXmlName(range, text, isRootProject);
            }
            else
            {
                text = base.ProcessRange(range, text);
            }

            return text;
        }