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>"); } }
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()); }
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); }
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; }
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); }
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()); }
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); }
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; }
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; }
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(); }
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)); }
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); }
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(); }
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; }