public static IEnumerable <T> Format <T>(string text, IStackTraceFormatter <T> formatter) { Debug.Assert(text != null); var frames = StackTraceParser.Parse ( text, (idx, len, txt) => new { Index = idx, End = idx + len, Text = txt, Markup = formatter.Text(txt), }, (t, m) => new { Type = new { t.Index, t.End, Markup = formatter.Type(t.Markup) }, Method = new { m.Index, m.End, Markup = formatter.Method(m.Markup) } }, (t, n) => new { Type = new { t.Index, t.End, Markup = formatter.ParameterType(t.Markup) }, Name = new { n.Index, n.End, Markup = formatter.ParameterName(n.Markup) } }, (p, ps) => new { List = p, Parameters = ps.ToArray() }, (f, l) => new { File = f.Text.Length > 0 ? new { f.Index, f.End, Markup = formatter.File(f.Markup) } : null, Line = l.Text.Length > 0 ? new { l.Index, l.End, Markup = formatter.Line(l.Markup) } : null, }, (f, tm, p, fl) => from tokens in new[] { new[] { new { f.Index, End = f.Index, Markup = formatter.BeforeFrame }, tm.Type, tm.Method, new { p.List.Index, End = p.List.Index, Markup = formatter.BeforeParameters }, }, from pe in p.Parameters from e in new[] { pe.Type, pe.Name } select e, new[] { new { Index = p.List.End, p.List.End, Markup = formatter.AfterParameters }, fl.File, fl.Line, new { Index = f.End, f.End, Markup = formatter.AfterFrame }, }, } from token in tokens where token != null select token ); return (from token in Enumerable.Repeat(new { Index = 0, End = 0, Markup = default(T) }, 1) .Concat(from tokens in frames from token in tokens select token) .Pairwise((prev, curr) => new { Previous = prev, Current = curr }) from m in new[] { formatter.Text(text.Substring(token.Previous.End, token.Current.Index - token.Previous.End)), token.Current.Markup, } select m); }
static HelperResult MarkupStackTrace(string text) { Debug.Assert(text != null); return(new HelperResult(writer => { if (writer == null) { throw new ArgumentNullException("writer"); } var frames = StackTraceParser.Parse ( text, (idx, len, txt) => new { Index = idx, End = idx + len, Html = txt.Length > 0 ? HttpUtility.HtmlEncode(txt) : string.Empty, }, (t, m) => new { Type = new { t.Index, t.End, Html = "<span class='st-type'>" + t.Html + "</span>" }, Method = new { m.Index, m.End, Html = "<span class='st-method'>" + m.Html + "</span>" } }, (t, n) => new { Type = new { t.Index, t.End, Html = "<span class='st-param-type'>" + t.Html + "</span>" }, Name = new { n.Index, n.End, Html = "<span class='st-param-name'>" + n.Html + "</span>" } }, (p, ps) => new { List = p, Parameters = ps.ToArray() }, (f, l) => new { File = f.Html.Length > 0 ? new { f.Index, f.End, Html = "<span class='st-file'>" + f.Html + "</span>" } : null, Line = l.Html.Length > 0 ? new { l.Index, l.End, Html = "<span class='st-line'>" + l.Html + "</span>" } : null, }, (f, tm, p, fl) => from tokens in new[] { new[] { new { f.Index, End = f.Index, Html = "<span class='st-frame'>" }, tm.Type, tm.Method, new { p.List.Index, End = p.List.Index, Html = "<span class='params'>" }, }, from pe in p.Parameters from e in new[] { pe.Type, pe.Name } select e, new[] { new { Index = p.List.End, p.List.End, Html = "</span>" }, fl.File, fl.Line, new { Index = f.End, f.End, Html = "</span>" }, }, } from token in tokens where token != null select token ); var markups = from token in Enumerable.Repeat(new { Index = 0, End = 0, Html = string.Empty }, 1) .Concat(from tokens in frames from token in tokens select token) .Pairwise((prev, curr) => new { Previous = prev, Current = curr }) from m in new[] { HttpUtility.HtmlEncode(text.Substring(token.Previous.End, token.Current.Index - token.Previous.End)), token.Current.Html } where m.Length > 0 select m; writer.Write(markups.ToDelimitedString(string.Empty)); })); }