/// <summary> /// Answer the formatted text for a given topic, formatted using a given OutputFormat and possibly showing diffs /// with a specified revision /// </summary> /// <param name="topic">The topic</param> /// <param name="format">What format</param> /// <param name="showDiffs">true to show diffs</param> /// <param name="accumulator">composite cache rule in which to accumulate cache rules (ignored for diffs)</param> /// <returns></returns> public static string FormattedTopicWithSpecificDiffs(QualifiedTopicRevision topic, OutputFormat format, QualifiedTopicRevision diffWithThisVersion, Federation aFederation, LinkMaker lm) { // Setup a special link maker that knows what to make the edit links return to LinkMaker linker = lm.Clone(); linker.ReturnToTopicForEditLinks = topic; NamespaceManager relativeToBase = aFederation.NamespaceManagerForNamespace(topic.Namespace); WikiOutput output = WikiOutput.ForFormat(format, null); if (diffWithThisVersion != null) { ArrayList styledLines = new ArrayList(); IList leftLines; IList rightLines; using (TextReader srLeft = relativeToBase.TextReaderForTopic(topic.AsUnqualifiedTopicRevision())) { leftLines = MergeBehaviorLines(srLeft.ReadToEnd().Replace("\r", "").Split('\n')); } using (TextReader srRight = relativeToBase.TextReaderForTopic(diffWithThisVersion.AsUnqualifiedTopicRevision())) { rightLines = MergeBehaviorLines(srRight.ReadToEnd().Replace("\r", "").Split('\n')); } IEnumerable diffs = Diff.Compare(leftLines, rightLines); foreach (LineData ld in diffs) { LineStyle style = LineStyle.Unchanged; switch (ld.Type) { case LineType.Common: style = LineStyle.Unchanged; break; case LineType.LeftOnly: style = LineStyle.Add; break; case LineType.RightOnly: style = LineStyle.Delete; break; } styledLines.Add(new StyledLine(ld.Text, style)); } Format(topic, styledLines, output, relativeToBase, linker, relativeToBase.ExternalReferences, 0); } else { using (TextReader sr = relativeToBase.TextReaderForTopic(topic.AsUnqualifiedTopicRevision())) { Format(topic, sr.ReadToEnd(), output, relativeToBase, linker, relativeToBase.ExternalReferences, 0); } } return output.ToString(); }
private string wikiIncludedTopic(Match match) { string replacement = match.ToString(); string linestart = match.Groups["LineStart"].Value; if (!preBehavior.IsMatch(linestart)) { string topic = match.Groups["IncludedTopic"].Value; TopicRevision topicRevision = new TopicRevision(topic); int size = 0; if (_mgr.TopicExists(topicRevision, ImportPolicy.IncludeImports)) { string ns = _mgr.UnambiguousTopicNameFor(topicRevision.LocalName).Namespace; NamespaceManager containingNamespaceManager = _fed.NamespaceManagerForNamespace(ns); QualifiedTopicRevision abs = new QualifiedTopicRevision(topicRevision.LocalName, ns); if (containingNamespaceManager.HasPermission(new UnqualifiedTopicName(abs.LocalName), TopicPermission.Read)) { replacement = containingNamespaceManager.Read(abs.LocalName.TrimEnd()); } _behaviorTopic = abs; string tempsize = _mgr.GetTopicProperty(_behaviorTopic.AsUnqualifiedTopicRevision(), "_ProcessTextSize").LastValue; Int32.TryParse(tempsize, out size); if (size == 0) { size = _chunk; } replacement = findWikiBehavior.Replace(replacement, new MatchEvaluator(wikiBehaviorMatch)); replacement = replacement.Replace(" ", "\t"); replacement = escape(replacement); if (_processBehaviorToText) { WomDocument xmldoc = ProcessText(replacement, abs, _mgr, true, size); replacement = xmldoc.ParsedDocument; } else { _processBehaviorToText = true; } _behaviorTopic = null; } } return replacement + "\r\n"; }
//this is where fragments are prepped for parsing public WomDocument FormatTextFragment(string wikiInput, QualifiedTopicRevision topic, NamespaceManager mgr, bool fragment, int sizeIn) { WomDocument xmldoc = new WomDocument(null); string wikitext = ""; _mgr = mgr; _topic = topic; WomDocument.ResetTableOfContents(); WomDocument.anchors = new string[25]; _processBehaviorToText = true; _behaviorTopic = topic; wikitext = escape(wikiInput); int size = 0; bool done = false; while (!done) { try { string tempsize = _mgr.GetTopicProperty(topic.AsUnqualifiedTopicRevision(), "_ProcessTextSize").LastValue; Int32.TryParse(tempsize, out size); if (size == 0) { size = sizeIn; } xmldoc = ProcessText(wikitext, topic, _mgr, fragment, size); //string womdoc = xmldoc.ParsedDocument; //string firstPass = findWikiBehavior.Replace(womdoc, new MatchEvaluator(wikiBehaviorMatch)); //xmldoc.ParsedDocument = findWikiBehavior.Replace(firstPass, new MatchEvaluator(wikiBehaviorMatch)); while (findWikiBehavior.IsMatch(xmldoc.ParsedDocument)) { xmldoc.ParsedDocument = findWikiBehavior.Replace(xmldoc.ParsedDocument, new MatchEvaluator(wikiBehaviorMatch)); } _behaviorTopic = null; if (findIncludedTopic.IsMatch(xmldoc.ParsedDocument)) { string included = xmldoc.ParsedDocument; included = findIncludedTopic.Replace(included, new MatchEvaluator(wikiIncludedTopic)); xmldoc.ParsedDocument = included; } done = true; //interpreted = xmldoc.ParsedDocument; //xmldoc = null; } catch (XmlException ex) { _mgr.SetProcessTextSize(topic.AsUnqualifiedTopicRevision(), size * (chunkcnt + 1)); string error = "<Error>" + ex.ToString() + "</Error>"; xmldoc.ParsedDocument = error; } } return xmldoc; }
//this is the main body where the real parsing work is done < 30 lines of code public WomDocument ProcessText(string wikiInput, QualifiedTopicRevision topic, NamespaceManager mgr, bool fragment, int size) { //_stopwatch = Stopwatch.StartNew(); ParserContext savedcontext; bool redo = false; wikiInput = wikiInput.Replace("\r\n\r\n", "\r\n"); if (!fragment) { wikiInput = "\r\n" + wikiInput; } else { while (wikiInput.EndsWith("\r\n")) { wikiInput = wikiInput.Remove(wikiInput.LastIndexOf("\r\n")); } } _womDocument = new WomDocument(null); _womDocument.Fed = _fed; _womDocument.Mgr = mgr; _womDocument.FragmentOnly = fragment; _womDocument.Begin(); int chunk = _chunk; //set the initial chunk size (for cache use) if (size > 0) { chunk = size; } chunkcnt = 1; while (_context.ParentRule != null) { if (_context.ParentRule.ParentContext != null) { _context = _context.ParentRule.ParentContext; } } if (!String.IsNullOrEmpty(wikiInput)) { StringBuilder source = new StringBuilder(); StringBuilder temp = new StringBuilder(); source.AppendLine(externalWikiRef.Replace(wikiInput, new MatchEvaluator(externalWikiRefMatch))); temp.Append(multilinePre.Replace(source.ToString(), new MatchEvaluator(multilinePreMatch))); source = temp; string savedtemp = temp.ToString(); MatchCollection matches; while (source.Length > 0) { string womElement = _context.WomElement; //optimize here by passing in less than the full string when source is very long //this gives a 5 times performance improvement int matchcnt = 0; if (source.Length > chunk * chunkcnt) { matches = _context.RegExp.Matches(source.ToString(0, chunk * chunkcnt)); matchcnt = matches.Count; } else { matches = _context.RegExp.Matches(source.ToString()); matchcnt = matches.Count; } if (matchcnt > 0) { if (matches[0].Index > 0) { _womDocument.SimpleAdd(source.ToString(0, matches[0].Index), womElement, "", _context.RuleList[0]); } int x = 1; if (_context.RegExpStr.StartsWith("(?:") && !matches[0].Value.StartsWith("%")) { x = 0; } int cnt = matches[0].Groups.Count; for (int i = x; i < cnt; i++) { if (matches[0].Groups[i].Success) { if (womElement != "WikiText") { //we are in a child rule set with an end condition //whereas WikiText ends by running out of source or matches if (i == 1) { i = 0; } } if (_womDocument.InTable && _womDocument.InItem && matches[0].Value.StartsWith("%")) { i++; //add one to the index here as we are in womText rules twice for this condition } ParserRule rule = _context.RuleList[i]; savedcontext = _context; string addElement; if (!String.IsNullOrEmpty(rule.WomElement)) { addElement = rule.WomElement; } else { addElement = womElement; } _womDocument.SimpleAdd(matches[0].Value, addElement, rule.Jump, rule); if (_womDocument.ParsedDocument.Contains("<<")) //an error occurred { chunkcnt++; //increase the chunk size and redo redo = true; } else { if (addElement != "WikiStylingEnd") { _context = rule.Context; } //still in a line - only pop one context item else if (matches[0].Value == "%%" || matches[0].Value == "%" || matches[0].Value.Contains("{||")) { _context = _context.ParentRule.ParentContext; } else //done with that line - pop all context back to start { while (_context.ParentRule != null) { if (_context.ParentRule.ParentContext != null) { _context = _context.ParentRule.ParentContext; } } } } break; } } if (!redo) //an error occurred { bool modifyRemove = false; if (womElement == "womListText" && matches[0].Value.Contains("{||")) //need to leave this bit in source { modifyRemove = true; } else if (womElement == "womWikiStyledText" && matches[0].Value == "%") { modifyRemove = true; } if (modifyRemove) { source.Remove(0, matches[0].Index); } else { source.Remove(0, matches[0].Index + matches[0].Length); } } else { //reset and start over with larger chunk source = new StringBuilder(); source.Append(savedtemp); _womDocument = new WomDocument(null); _womDocument.Fed = _fed; _womDocument.Mgr = mgr; _womDocument.FragmentOnly = fragment; _womDocument.Begin(); redo = false; while (_context.ParentRule != null) { if (_context.ParentRule.ParentContext != null) { _context = _context.ParentRule.ParentContext; } } } } else { if (source.Length > chunk * chunkcnt) //no match in that chunk, increase size and retry { source = new StringBuilder(); source.Append(savedtemp); _womDocument = new WomDocument(null); _womDocument.Fed = _fed; _womDocument.Mgr = mgr; _womDocument.FragmentOnly = fragment; _womDocument.Begin(); chunkcnt++; while (_context.ParentRule != null) { if (_context.ParentRule.ParentContext != null) { _context = _context.ParentRule.ParentContext; } } } else { _womDocument.SimpleAdd(source.ToString(), womElement, "", _context.RuleList[0]); source.Length = 0; } } } source = null; temp = null; } _womDocument.End(); if (((bool)_fed.Application["DisableWikiEmoticons"] == false)) //&& (_mgr.DisableNamespaceEmoticons == false)) { MatchCollection emoticonMatches = findEmoticon.Matches(_womDocument.ParsedDocument); if (emoticonMatches.Count > 0) { _womDocument.ConvertEmoticons(emoticonMatches); } } //_stopwatch.Stop(); if (chunkcnt > 1) { mgr.SetProcessTextSize(topic.AsUnqualifiedTopicRevision(), chunk * chunkcnt); } return _womDocument; }
public string FormattedTopic(QualifiedTopicRevision topic, OutputFormat fmt) { //initial version does not handle diffs string wikitext = ""; string interpreted = ""; _mgr = _fed.NamespaceManagerForNamespace(topic.Namespace); _topic = topic; WomDocument.ResetTableOfContents(); WomDocument.anchors = new string[25]; _processBehaviorToText = true; _behaviorTopic = topic; //Normally get data from the cache, but when debugging Womdocument need to avoid using cached data string wom = _mgr.GetTopicProperty(topic.AsUnqualifiedTopicRevision(), "_Wom").LastValue; //string wom = ""; if (!String.IsNullOrEmpty(wom)) { WomDocument xmldoc = new WomDocument(null); wom = findWikiBehavior.Replace(wom, new MatchEvaluator(wikiBehaviorMatch)); xmldoc.ParsedDocument = findWikiBehavior.Replace(wom, new MatchEvaluator(wikiBehaviorMatch)); if (findIncludedTopic.IsMatch(xmldoc.ParsedDocument)) { string included = xmldoc.ParsedDocument; included = findIncludedTopic.Replace(included, new MatchEvaluator(wikiIncludedTopic)); xmldoc.ParsedDocument = included; } interpreted = xmldoc.ParsedDocument; xmldoc = null; } else { using (TextReader sr = _mgr.TextReaderForTopic(topic.AsUnqualifiedTopicRevision())) { wikitext = sr.ReadToEnd() + "\r\n"; } wikitext = escape(wikitext); int size = 0; while (String.IsNullOrEmpty(interpreted)) { try { string tempsize = _mgr.GetTopicProperty(topic.AsUnqualifiedTopicRevision(), "_ProcessTextSize").LastValue; Int32.TryParse(tempsize, out size); if (size == 0) { size = _chunk; } WomDocument xmldoc = ProcessText(wikitext, topic, _mgr, false, size); //string womdoc = xmldoc.ParsedDocument; _mgr.SetWomCache(topic.AsUnqualifiedTopicRevision(), xmldoc.ParsedDocument); //string firstPass = findWikiBehavior.Replace(womdoc, new MatchEvaluator(wikiBehaviorMatch)); //xmldoc.ParsedDocument = findWikiBehavior.Replace(firstPass, new MatchEvaluator(wikiBehaviorMatch)); while (findWikiBehavior.IsMatch(xmldoc.ParsedDocument)) { xmldoc.ParsedDocument = findWikiBehavior.Replace(xmldoc.ParsedDocument, new MatchEvaluator(wikiBehaviorMatch)); } _behaviorTopic = null; if (findIncludedTopic.IsMatch(xmldoc.ParsedDocument)) { string included = xmldoc.ParsedDocument; included = findIncludedTopic.Replace(included, new MatchEvaluator(wikiIncludedTopic)); xmldoc.ParsedDocument = included; } interpreted = xmldoc.ParsedDocument; xmldoc = null; } catch (XmlException ex) { _mgr.SetProcessTextSize(topic.AsUnqualifiedTopicRevision(), size * (chunkcnt + 1)); string error = ex.ToString(); } } } _processBehaviorToText = false; return interpreted; }