private void AddAdditionalReferenceSymbols(ISymbol symbol, ReferenceSpan symbolSpan, SyntaxToken token) { //var bindableParent = GetBindableParent(token); if (symbol.Kind == SymbolKind.Method) { // Case: Constructor IMethodSymbol methodSymbol = symbol as IMethodSymbol; if (methodSymbol != null) { if (methodSymbol.MethodKind == MethodKind.Constructor) { // Add special reference kind for instantiation references.Add(symbolSpan.CreateReference(GetReferenceSymbol(methodSymbol.ContainingType, ReferenceKind.Instantiation))); } } } else if (symbol.Kind == SymbolKind.Property) { } else if (symbol.Kind == SymbolKind.Field) { } else if (symbol.Kind == SymbolKind.NamedType) { // Case: Derived class // Case: Partial class } }
private void GetBestReference(ref int referenceIndex, ref ReferenceSpan currentReference, IReadOnlyList <ReferenceSpan> referenceSpans) { for (int i = referenceIndex; i < referenceSpans.Count; i++) { var reference = referenceSpans[i]; if (reference.Start != currentReference.Start) { break; } if (currentReference.Reference.IsImplicitlyDeclared || reference.Reference.ReferenceKind == nameof(ReferenceKind.Definition)) { currentReference = reference; referenceIndex = i; } } }
/// <summary> /// Gets the contents of the source file with <span> tags added around /// all the spans specified for this BoundSourceFile that have a /// class of the Classification for the Symbol /// </summary> /// <returns></returns> public async Task <EditorModel> RenderAsync() { var filePath = _sourceFile.SourceFile?.Info?.Path; var model = new EditorModel() { ProjectId = projectId, FilePath = filePath, WebLink = _sourceFile.SourceFile?.Info?.WebAddress, RepoRelativePath = _sourceFile.SourceFile?.Info?.RepoRelativePath }; string sourceText = await _sourceFile.SourceFile.GetContentsAsync(); int lineCount = GetLineCount(sourceText); var url = $"/?rightProject={HttpUtility.UrlEncode(projectId)}&file={HttpUtility.UrlEncode(filePath)}"; model.LineNumberText = GenerateLineNumberText(lineCount, url); var ret = new StringBuilder(); int textIndex = 0; Span prevSpan = null; using (StringWriter sw = new StringWriter(ret)) { int referenceIndex = -1; ReferenceSpan referenceSpan = null; foreach (ClassificationSpan span in _sourceFile.ClassificationSpans.OrderBy(s => s.Start)) { if (span.Start > sourceText.Length) { //Not sure how this happened but a span is off the end of our text Debug.WriteLine( $"Span had Start of {span.Start}, which is greater than text length for file '{_sourceFile.SourceFile.Info.Path}'", "BoundSourceFileMarkup"); break; } if (prevSpan != null && span.Start == prevSpan.Start) { // Overlapping spans? continue; } if (span.Start > textIndex) { //Span is ahead of our current index, just write the normal text between the two to the buffer ret.Append(HttpUtility.HtmlEncode(sourceText.Substring(textIndex, span.Start - textIndex))); textIndex = span.Start; } string spanText = sourceText.Substring(span.Start, span.Length); GenerateSpan(sw, span, spanText, ref referenceIndex, ref referenceSpan, _sourceFile.References); textIndex += span.Length; prevSpan = span; } // Append any leftover text ret.Append(HttpUtility.HtmlEncode(sourceText.Substring(textIndex))); model.Text = ret.ToString(); return(model); } }
private void GenerateSpan(TextWriter tw, ClassificationSpan span, string spanText, ref int referenceIndex, ref ReferenceSpan currentReference, IReadOnlyList <ReferenceSpan> referenceSpans) { while ((currentReference == null || currentReference.Start < span.Start) && referenceIndex < referenceSpans.Count) { referenceIndex++; if (referenceIndex < referenceSpans.Count) { currentReference = referenceSpans[referenceIndex]; } else { currentReference = null; } } if (currentReference != null) { GetBestReference(ref referenceIndex, ref currentReference, referenceSpans); } string cssClass = MapClassificationToCssClass(span.Classification); string referenceClass = string.Empty; if (span.LocalGroupId > 0) { referenceClass = $"r{span.LocalGroupId} r"; cssClass = string.IsNullOrEmpty(cssClass) ? referenceClass : $"{referenceClass} {cssClass}"; } HtmlElementInfo htmlElementInfo = null; if (currentReference?.SpanEquals(span) == true) { htmlElementInfo = GenerateHyperlinkForReference(currentReference.Reference); } if (htmlElementInfo == null && !span.Contains(currentReference)) { if (cssClass == null) { tw.Write(HttpUtility.HtmlEncode(spanText)); return; } } string elementName = "span"; bool classAttributeSpecified = false; if (htmlElementInfo != null) { elementName = htmlElementInfo.Name; if (htmlElementInfo.RequiresWrappingSpan) { tw.Write("<span"); AddAttribute(tw, "class", cssClass); tw.Write(">"); classAttributeSpecified = true; } } tw.Write("<" + elementName); if (htmlElementInfo != null) { foreach (var attribute in htmlElementInfo.Attributes) { if (AddAttribute(tw, attribute.Key, attribute.Value)) { if (attribute.Key == "class") { classAttributeSpecified = true; } } } } if (!classAttributeSpecified) { AddAttribute(tw, "class", cssClass); } if (span.LocalGroupId > 0 && (htmlElementInfo?.Attributes?.ContainsKey("onclick") != true)) { AddAttribute(tw, "onclick", "t(this);"); } tw.Write(">"); if (htmlElementInfo != null || !span.Contains(currentReference)) { tw.Write(HttpUtility.HtmlEncode(spanText)); } else { WriteReferenceText(tw, span, spanText, ref referenceIndex, ref currentReference, referenceSpans); } tw.Write("</" + elementName + ">"); if (htmlElementInfo?.RequiresWrappingSpan == true) { tw.Write("</span>"); } }
private void WriteReferenceText(TextWriter tw, ClassificationSpan span, string spanText, ref int referenceIndex, ref ReferenceSpan currentReference, IReadOnlyList <ReferenceSpan> referenceSpans) { int startPosition = span.Start; int currentPosition = span.Start; int end = span.End; while (currentReference != null && currentReference.Start >= currentPosition && currentReference.Start < end && currentReference.End <= end) { if (currentReference != null) { GetBestReference(ref referenceIndex, ref currentReference, referenceSpans); } if (currentReference.Start > currentPosition) { HttpUtility.HtmlEncode(spanText.Substring(currentPosition - startPosition, currentReference.Start - currentPosition), tw); currentPosition = currentReference.Start; } if (currentReference.Length > 0) { var htmlElementInfo = GenerateHyperlinkForReference(currentReference.Reference); WriteHtmlElement(tw, htmlElementInfo, spanText.Substring(currentReference.Start - startPosition, currentReference.Length)); currentPosition = currentReference.End; } referenceIndex++; if (referenceIndex < referenceSpans.Count) { currentReference = referenceSpans[referenceIndex]; } else { break; } } if (currentPosition < end) { HttpUtility.HtmlEncode(spanText.Substring(currentPosition - startPosition, end - currentPosition), tw); } }
public BoundSourceFile Build() { if (stringBuilder != null) { SourceFile.Content = stringBuilder.ToString(); stringBuilder = null; } SourceText text = SourceText; var info = BoundSourceFile.SourceFile.Info; var checksumKey = GetChecksumKey(text.ChecksumAlgorithm); if (checksumKey != null) { var checksum = text.GetChecksum().ToHex(); info.Properties[checksumKey] = checksum; AnnotateDefinition(0, 0, new DefinitionSymbol() { Id = SymbolId.CreateFromId($"{checksumKey}|{checksum}"), ShortName = checksum, ContainerQualifiedName = checksumKey, ProjectId = BoundSourceFile.ProjectId, ReferenceKind = nameof(ReferenceKind.Definition), Kind = checksumKey, }); } classifications.Sort((cs1, cs2) => cs1.Start.CompareTo(cs2.Start)); references.Sort((cs1, cs2) => cs1.Start.CompareTo(cs2.Start)); BoundSourceFile.Definitions.Sort((cs1, cs2) => cs1.Start.CompareTo(cs2.Start)); ReferenceSpan lastReference = null; foreach (var reference in references) { if (lastReference?.Start == reference.Start) { reference.LineNumber = lastReference.LineNumber; reference.LineSpanStart = lastReference.LineSpanStart; reference.LineSpanText = lastReference.LineSpanText; continue; } var line = text.Lines.GetLineFromPosition(reference.Start); if (lastReference?.LineNumber == line.LineNumber) { reference.LineNumber = line.LineNumber; reference.LineSpanStart = lastReference.LineSpanStart + (reference.Start - lastReference.Start); reference.LineSpanText = lastReference.LineSpanText; continue; } reference.LineNumber = line.LineNumber; reference.LineSpanStart = reference.Start - line.Start; reference.LineSpanText = line.ToString(); reference.Trim(); } foreach (var definitionSpan in BoundSourceFile.Definitions) { definitionSpan.Definition.ProjectId = definitionSpan.Definition.ProjectId ?? ProjectId; var line = text.Lines.GetLineFromPosition(definitionSpan.Start); definitionSpan.LineNumber = line.LineNumber; definitionSpan.LineSpanStart = definitionSpan.Start - line.Start; } return(BoundSourceFile); }
private void RenderReference(ReferenceSpan referenceSpan) { if (referenceSpan.ResolutionException == null) { Push("reference"); switch (referenceSpan.KindTag) { case "link": SetAttribute("kind", "link"); break; case "image": SetAttribute("kind", "image"); break; } SetAttribute("to", referenceSpan.Reference); if (referenceSpan.ChildSpan != null) { RenderSpan(referenceSpan.ChildSpan); } Pop(); } else { Push("reference-exception"); SetAttribute("to", referenceSpan.Reference); SetAttribute("message", referenceSpan.ResolutionException.Message); if (referenceSpan.ResolutionException is AdornedReferenceResolutionException) { AdornedReferenceResolutionException ex = referenceSpan.ResolutionException as AdornedReferenceResolutionException; if (ex.ConsoleOutput != null) { string consoleText = ex.ConsoleOutput; Push("console-output"); foreach (string line in consoleText.Split('\n')) { Push("console-output-line"); Write(line.TrimEnd()); Pop(); WriteNewLine(); } Pop(); } } Pop(); } }