public async Task <Section> GetTextAt(int pos16) { //using var p1 = perf.local(); if (!CodeInfo.GetContextAndDocument(out var cd, pos16)) { return(null); } //don't include <remarks>. Sometimes it takes too much space. Badly formatted if eg contains markdown. var opt1 = QuickInfoOptions.Default with { ShowRemarksInQuickInfo = false, IncludeNavigationHintsInQuickInfo = false }; var opt2 = new Microsoft.CodeAnalysis.LanguageServices.SymbolDescriptionOptions(opt1, Microsoft.CodeAnalysis.Classification.ClassificationOptions.Default); var service = QuickInfoService.GetService(cd.document); var r = await Task.Run(async() => await service.GetQuickInfoAsync(cd.document, pos16, opt2, default)); //p1.Next(); if (r == null) { return(null); } //this oveload is internal, but: // - The public overload does not have an options parameter. Used to set options for workspace, but it stopped working. // - Roslyn in Debug config asserts "don't use this function". //print.it(r.Span, r.RelatedSpans); //print.it(r.Tags); var a = r.Sections; if (a.Length == 0) { return(null); //when cursor is on }. //SHOULDDO: display block start code, like in VS. } //don't show some useless quickinfos, eg for literals if (r.Tags.Length == 2 && a.Length == 2 && a[1].Kind == QuickInfoSectionKinds.DocumentationComments) { //print.it(r.Tags[0], a[1].Kind, a[1].Text); var s = a[1].Text; if (s.Starts("Represents ")) { switch (r.Tags[0]) { case "Class": if (s == "Represents text as a sequence of UTF-16 code units.") { return(null); } break; case "Structure": if (s.RxIsMatch(@"^Represents a (\d+-bit u?n?signed integer|[\w+-]+ floating-point number)\.$")) { return(null); } break; } } } var x = new CiText(); //bool hasDocComm = false; //QuickInfoSection descr = null; for (int i = 0; i < a.Length; i++) { var se = a[i]; //print.it(se.Kind, se.Text); //if (se.Kind == QuickInfoSectionKinds.RemarksDocumentationComments) continue; x.StartParagraph(); //if (se.Kind == QuickInfoSectionKinds.RemarksDocumentationComments) { // x.Append("More info in Remarks (click and press F1)."); //no, because the DB does not contain Au and .NET remarks; would show this info only for others (local, XML files). //} else { if (i == 0) //image { CiUtil.TagsToKindAndAccess(r.Tags, out var kind, out var access); if (kind != CiItemKind.None) { if (access != default) { x.Image(access); } x.Image(kind); x.Append(" "); } } var tp = se.TaggedParts; if (tp[0].Tag == TextTags.LineBreak) //remove/replace some line breaks in returns and exceptions { int lessNewlines = se.Kind switch { QuickInfoSectionKinds.ReturnsDocumentationComments => 1, QuickInfoSectionKinds.Exception => 2, _ => 0 }; var k = new List <TaggedText>(tp.Length - 1); for (int j = 1; j < tp.Length; j++) { var v = tp[j]; if (lessNewlines > 0 && j > 1) { if (v.Tag == TextTags.LineBreak) { if (j == 2) { continue; //remove line break after "Returns:" etc } if (lessNewlines == 2) //in list of exceptions replace "\n " with ", " { if (++j == tp.Length || tp[j].Tag != TextTags.Space) { j--; continue; } v = new(TextTags.Text, ", "); } } } k.Add(v); } x.AppendTaggedParts(k, false); } else { x.AppendTaggedParts(tp); } //} x.EndParagraph(); } return(x.Result); } }
System.Windows.Documents.Section _FormatText(int iSel, bool userSelected) { _data.iSelected = iSel; if (userSelected) { _data.iUserSelected = iSel; } var r = _data.r; ISymbol currentItem = null; SignatureHelpParameter currentParameter = null; var x = new CiText(); //print.clear(); for (int i = 0; i < r.Items.Count; i++) { var sh = r.Items[i]; if (sh is AbstractSignatureHelpProvider.SymbolKeySignatureHelpItem kk) { var sym = kk.Symbol; if (i == iSel) { currentItem = sym; } x.StartOverload(i == iSel, i); #if false x.AppendTaggedParts(sh.PrefixDisplayParts); //works, but formats not as I like (too much garbage). Has bugs with tuples. #else //if(nt != null) { // print.it(1, nt.IsGenericType, nt.IsTupleType, nt.IsUnboundGenericType, nt.Arity, nt.CanBeReferencedByName); // print.it(2, nt.IsAnonymousType, nt.IsDefinition, nt.IsImplicitlyDeclared, nt.Kind, nt.TypeKind); // print.it(3, nt.MemberNames); // print.it(4, nt.Name, nt.MetadataName, nt.OriginalDefinition, nt.TupleUnderlyingType); // print.it("TypeParameters:"); // print.it(nt.TypeParameters); // print.it("TypeArguments:"); // print.it(nt.TypeArguments); // print.it("TupleElements:"); // try { var te = nt.TupleElements; if(!te.IsDefault) print.it(te); } catch(Exception e1) { print.it(e1.ToStringWithoutStack()); } // print.it("---"); //} int isTuple = 0; //1 ValueTuple<...>, 2 (...) var nt = sym as INamedTypeSymbol; if (nt != null && nt.IsTupleType) { isTuple = nt.IsDefinition ? 1 : 2; } if (isTuple == 1) { x.Append("ValueTuple"); //AppendSymbolWithoutParameters formats incorrectly } else if (isTuple == 0) { x.AppendSymbolWithoutParameters(sym); } string b1 = "(", b2 = ")"; if (nt != null) { if (nt.IsGenericType && isTuple != 2) { b1 = "<"; b2 = ">"; } } else if (sym is IPropertySymbol) { b1 = "["; b2 = "]"; } x.Append(b1); #endif int iArg = r.ArgumentIndex, lastParam = sh.Parameters.Length - 1; int selParam = iArg <= lastParam ? iArg : (sh.IsVariadic ? lastParam : -1); if (!r.ArgumentName.NE()) { var pa = sh.Parameters; for (int pi = 0; pi < pa.Length; pi++) { if (pa[pi].Name == r.ArgumentName) { selParam = pi; break; } } } x.AppendParameters(sym, selParam, sh); //x.AppendParameters(sh, selParam); //works, but formats not as I like (too much garbage) #if false x.AppendTaggedParts(sh.SuffixDisplayParts); #else x.Append(b2); #endif if (i == iSel && selParam >= 0) { currentParameter = sh.Parameters[selParam]; } x.EndOverload(i == iSel); } else { Debug_.Print(sh); } } if (currentItem != null) { var tt = r.Items[iSel].DocumentationFactory?.Invoke(default);