This commit is contained in:
Zel
2025-02-23 18:47:21 +08:00
parent eaaffeeccb
commit e46a7ca31c
104 changed files with 2630 additions and 2516 deletions

View File

@@ -5,18 +5,17 @@ namespace ZelWiki.Engine
public class WikiMatchSet
{
/// <summary>
/// The type of match that was found.
/// 找到的匹配类型.
/// </summary>
public Constants.WikiMatchType MatchType { get; set; }
/// <summary>
/// The resulting content of the wiki processing.
/// 内容.
/// </summary>
public string Content { get; set; } = string.Empty;
/// <summary>
/// The content in this segment will be wikified. This is useful to disable on things like error messages
/// and literal blocks where the content may contain valid wiki markup but we want it to display verbatim.
///
/// </summary>
public bool AllowNestedDecode { get; set; }
}

View File

@@ -2,7 +2,17 @@
{
public class WikiOrderedMatch
{
public string Value { get; set; } = string.Empty;
public WikiOrderedMatch()
{
Value = string.Empty;
}
/// <summary>
///
/// </summary>
public string Value { get; set; }
/// <summary>
///
/// </summary>
public int Index { get; set; }
}
}

View File

@@ -2,6 +2,9 @@
namespace ZelWiki.Engine
{
/// <summary>
/// 一些正则
/// </summary>
internal static partial class PrecompiledRegex
{
[GeneratedRegex("\\#\\{([\\S\\s]*?)\\}\\#", RegexOptions.IgnoreCase)]

View File

@@ -6,7 +6,7 @@ namespace ZelWiki.Engine
internal static class WikiUtility
{
/// <summary>
/// Skips the namespace and returns just the page name part of the navigation.
/// 跳过命名空间,只返回导航的页面名称部分.
/// </summary>
/// <param name="navigation"></param>
/// <returns></returns>
@@ -50,7 +50,7 @@ namespace ZelWiki.Engine
}
/// <summary>
/// Gets a list of symbols where the symbol occurs consecutively, more than once. (e.g. "##This##")
/// 获取符号连续出现多次的符号列表. ("##This##")
/// </summary>
/// <param name="input"></param>
/// <returns></returns>

View File

@@ -5,7 +5,7 @@ using ZelWiki.Models;
namespace ZelWiki.Engine
{
/// <summary>
/// Tiny wikifier (reduced feature-set) for things like comments and profile bios.
///
/// </summary>
public class WikifierLite
{
@@ -17,9 +17,9 @@ namespace ZelWiki.Engine
return string.Empty;
}
for (int i = 0; i < 100; i++) //We don't want to process nested wiki forever.
for (var i = 0; i < 100; i++)
{
bool processedMatches = false;
var processedMatches = false;
var matchStore = new Dictionary<string, string>();
var content = new WikiString(unprocessedText);
@@ -75,7 +75,8 @@ namespace ZelWiki.Engine
{
if (scale != 100 && scale > 0 && scale <= 500)
{
var emojiImage = $"<img src=\"/file/Emoji/{key.Trim('%')}?Scale={scale}\" alt=\"{emoji?.Name}\" />";
var emojiImage =
$"<img src=\"/file/Emoji/{key.Trim('%')}?Scale={scale}\" alt=\"{emoji?.Name}\" />";
pageContent.Replace(match.Value, StoreMatch(matchStore, emojiImage));
}
else
@@ -92,7 +93,7 @@ namespace ZelWiki.Engine
}
/// <summary>
/// Transform basic markup such as bold, italics, underline, etc. for single and multi-line.
/// 转换单行和多行的基本标记,如粗体、斜体、下划线等.
/// </summary>
/// <param name="pageContent"></param>
private static void TransformMarkup(WikiString pageContent, Dictionary<string, string> matchStore)
@@ -126,12 +127,12 @@ namespace ZelWiki.Engine
}
/// <summary>
/// Transform links, these can be internal Wiki links or external links.
/// 转换链接这些链接可以是内部Wiki链接或外部链接.
/// </summary>
/// <param name="pageContent"></param>
private static void TransformLinks(WikiString pageContent, Dictionary<string, string> matchStore)
{
//Parse external explicit links. eg. [[http://test.net]].
//解析外部链接 [[http://test.net]].
var rgx = new Regex(@"(\[\[http\:\/\/.+?\]\])", RegexOptions.IgnoreCase);
var matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString()));
foreach (var match in matches)
@@ -149,7 +150,7 @@ namespace ZelWiki.Engine
}
}
//Parse external explicit links. eg. [[https://test.net]].
//解析外部链接. [[https://test.net]].
rgx = new Regex(@"(\[\[https\:\/\/.+?\]\])", RegexOptions.IgnoreCase);
matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString()));
foreach (var match in matches)
@@ -167,7 +168,7 @@ namespace ZelWiki.Engine
}
}
//Parse internal dynamic links. eg [[AboutUs|About Us]].
//解析内部链接 [[AboutUs|About Us]].
rgx = new Regex(@"(\[\[.+?\]\])", RegexOptions.IgnoreCase);
matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString()));
foreach (var match in matches)
@@ -177,13 +178,15 @@ namespace ZelWiki.Engine
if (args.Count == 1)
{
pageContent.Replace(match.Value, StoreMatch(matchStore, $"<a href=\"{GlobalConfiguration.BasePath}/{args[0]}\">{args[0]}</a>"));
pageContent.Replace(match.Value,
StoreMatch(matchStore, $"<a href=\"{GlobalConfiguration.BasePath}/{args[0]}\">{args[0]}</a>"));
}
else if (args.Count > 1)
{
pageContent.Replace(match.Value, StoreMatch(matchStore, $"<a href=\"{GlobalConfiguration.BasePath}/{args[0]}\">{args[1]}</a>"));
pageContent.Replace(match.Value,
StoreMatch(matchStore, $"<a href=\"{GlobalConfiguration.BasePath}/{args[0]}\">{args[1]}</a>"));
}
}
}
}
}
}

View File

@@ -50,7 +50,7 @@ namespace ZelWiki.Engine
}
/// <summary>
/// Transforms the content for the given page.
/// 转换给定页面的内容.
/// </summary>
/// <param name="session">The users current state, used for localization.</param>
/// <param name="page">The page that is being processed.</param>

View File

@@ -23,12 +23,13 @@ namespace ZelWiki.Engine
private readonly string _tocName = "TOC_" + new Random().Next(0, 1000000).ToString();
private readonly Dictionary<string, object> _handlerState = new();
#region Public properties.
#region .
/// <summary>
/// Custom page title set by a call to @@Title("...")
/// 通过调用设置自定义页面标题 @@Title("...")
/// </summary>
public string? PageTitle { get; set; }
public int ErrorCount { get; private set; }
public int MatchCount { get; private set; }
public int TransformIterations { get; private set; }
@@ -45,19 +46,19 @@ namespace ZelWiki.Engine
#endregion
#region Input parameters.
#region .
public IPage Page { get; }
public int? Revision { get; }
public IQueryCollection QueryString { get; }
public ISessionState? Session { get; }
public HashSet<Constants.WikiMatchType> OmitMatches { get; private set; } = new();
public int NestDepth { get; private set; } //Used for recursion.
public int NestDepth { get; private set; } //用于递归
#endregion
/// <summary>
/// Used to store values for handlers that needs to survive only a single wiki processing session.
/// 存储只需要在单个wiki处理会话中生存的处理程序的值.
/// </summary>
public void SetStateValue<T>(string key, T value)
{
@@ -65,11 +66,12 @@ namespace ZelWiki.Engine
{
return;
}
_handlerState[key] = value;
}
/// <summary>
/// Used to get values for handlers that needs to survive only a single wiki processing session.
/// 获取只需要在单个处理会话中生存的处理程序的值.
/// </summary>
public T GetStateValue<T>(string key, T defaultValue)
{
@@ -77,12 +79,13 @@ namespace ZelWiki.Engine
{
return (T)value;
}
SetStateValue(key, defaultValue);
return defaultValue;
}
/// <summary>
/// Used to get values for handlers that needs to survive only a single wiki processing session.
/// 尝试获取只需要在单个处理会话中生存的处理程序的值..
/// </summary>
public bool TryGetStateValue<T>(string key, [MaybeNullWhen(false)] out T? outValue)
{
@@ -97,13 +100,14 @@ namespace ZelWiki.Engine
}
/// <summary>
/// Creates a new instance of the ZelEngineState class. Typically created by a call to ZelEngine.Transform().
/// 创建一个实例
/// </summary>
/// <param name="session">The users current state, used for localization.</param>
/// <param name="page">The page that is being processed.</param>
/// <param name="revision">The revision of the page that is being processed.</param>
/// <param name="omitMatches">The type of matches that we want to omit from processing.</param>
/// <param name="nestDepth">The current depth of recursion.</param>
/// <param name="engine"></param>
/// <param name="session"></param>
/// <param name="page"></param>
/// <param name="revision"></param>
/// <param name="omitMatches"></param>
/// <param name="nestDepth"></param>
internal ZelEngineState(IZelEngine engine, ISessionState? session,
IPage page, int? revision = null, Constants.WikiMatchType[]? omitMatches = null, int nestDepth = 0)
{
@@ -123,15 +127,15 @@ namespace ZelWiki.Engine
}
/// <summary>
/// Transforms "included" wiki pages, for example if a wiki function
/// injected additional wiki markup, this 'could' be processed separately.
///
/// </summary>
/// <param name="page">The child page to process</param>
/// <param name="revision">The optional revision of the child page to process</param>
/// <param name="page"></param>
/// <param name="revision"></param>
/// <returns></returns>
public IZelEngineState TransformChild(IPage page, int? revision = null)
{
return new ZelEngineState(Engine, Session, page, revision, OmitMatches.ToArray(), NestDepth + 1).Transform();
return new ZelEngineState(Engine, Session, page, revision, OmitMatches.ToArray(), NestDepth + 1)
.Transform();
}
internal IZelEngineState Transform()
@@ -169,21 +173,15 @@ namespace ZelWiki.Engine
foreach (var v in Matches)
{
if (OmitMatches.Contains(v.Value.MatchType))
{
/// When matches are omitted, the entire match will be removed from the resulting wiki text.
pageContent.Replace(v.Key, string.Empty);
}
else
{
pageContent.Replace(v.Key, v.Value.Content);
}
}
} while (length != pageContent.Length);
pageContent.Replace(SoftBreak, "\r\n");
pageContent.Replace(HardBreak, "<br />");
//Prepend any headers that were added by wiki handlers.
foreach (var header in Headers)
{
pageContent.Insert(0, header);
@@ -223,7 +221,6 @@ namespace ZelWiki.Engine
TransformStandardFunctions(pageContent, false);
TransformProcessingInstructionFunctions(pageContent);
//We have to replace a few times because we could have replace tags (guids) nested inside others.
int length;
do
{
@@ -233,15 +230,10 @@ namespace ZelWiki.Engine
if (v.Value.AllowNestedDecode)
{
if (OmitMatches.Contains(v.Value.MatchType))
{
/// When matches are omitted, the entire match will be removed from the resulting wiki text.
pageContent.Replace(v.Key, string.Empty);
}
else
{
pageContent.Replace(v.Key, v.Value.Content);
}
else
pageContent.Replace(v.Key, v.Value.Content);
}
}
} while (length != pageContent.Length);
@@ -250,7 +242,7 @@ namespace ZelWiki.Engine
}
/// <summary>
/// Transform basic markup such as bold, italics, underline, etc. for single and multi-line.
/// 转换单行和多行的基本标记,如粗体、斜体、下划线等.
/// </summary>
/// <param name="pageContent"></param>
private void TransformMarkup(WikiString pageContent)
@@ -270,7 +262,8 @@ namespace ZelWiki.Engine
var result = Engine.MarkupHandler.Handle(this, symbol, body);
StoreHandlerResult(result, Constants.WikiMatchType.Markup, pageContent, match.Value, result.Content);
StoreHandlerResult(result, WikiMatchType.Markup, pageContent, match.Value,
result.Content);
}
}
@@ -279,15 +272,17 @@ namespace ZelWiki.Engine
foreach (var match in sizeUpOrderedMatches)
{
int headingMarkers = 0;
var headingMarkers = 0;
foreach (char c in match.Value)
{
if (c != '^')
{
break;
}
headingMarkers++;
}
if (headingMarkers >= 2 && headingMarkers <= 6)
{
string value = match.Value.Substring(headingMarkers, match.Value.Length - headingMarkers).Trim();
@@ -295,44 +290,43 @@ namespace ZelWiki.Engine
int fontSize = 1 + headingMarkers;
if (fontSize < 1) fontSize = 1;
string markup = "<font size=\"" + fontSize + "\">" + value + "</font>\r\n";
StoreMatch(Constants.WikiMatchType.Markup, pageContent, match.Value, markup);
var markup = "<font size=\"" + fontSize + "\">" + value + "</font>\r\n";
StoreMatch(WikiMatchType.Markup, pageContent, match.Value, markup);
}
}
}
/// <summary>
/// Transform inline and multi-line literal blocks. These are blocks where the content will not be wikified and contain code that is encoded to display verbatim on the page.
/// 转换内联和多行文字块
/// </summary>
/// <param name="pageContent"></param>
private void TransformLiterals(WikiString pageContent)
{
//TODO: May need to do the same thing we did with TransformBlocks() to match all these if they need to be nested.
//Transform literal strings, even encodes HTML so that it displays verbatim.
var orderedMatches = WikiUtility.OrderMatchesByLengthDescending(
PrecompiledRegex.TransformLiterals().Matches(pageContent.ToString()));
foreach (var match in orderedMatches)
{
string value = match.Value.Substring(2, match.Value.Length - 4);
var value = match.Value.Substring(2, match.Value.Length - 4);
value = HttpUtility.HtmlEncode(value);
StoreMatch(Constants.WikiMatchType.Literal, pageContent, match.Value, value.Replace("\r", "").Trim().Replace("\n", "<br />\r\n"), false);
StoreMatch(WikiMatchType.Literal, pageContent, match.Value,
value.Replace("\r", "").Trim().Replace("\n", "<br />\r\n"), false);
}
}
/// <summary>
/// Matching nested blocks with regex was hell, I escaped with a loop. ¯\_(ツ)_/¯
///
/// </summary>
/// <param name="pageContent"></param>
private void TransformScopeFunctions(WikiString pageContent)
{
var content = pageContent.ToString();
string rawBlock = string.Empty;
var rawBlock = string.Empty;
int startPos = content.Length - 1;
var startPos = content.Length - 1;
while (true)
{
@@ -341,18 +335,24 @@ namespace ZelWiki.Engine
{
break;
}
int endPos = content.IndexOf("}}", startPos);
if (endPos < 0 || endPos < startPos)
{
var exception = new StringBuilder();
exception.AppendLine($"<strong>A parsing error occurred after position {startPos}:<br /></strong> Unable to locate closing tag.<br /><br />");
exception.AppendLine(
$"<strong>定位后发生解析错误 {startPos}:<br /></strong> 无法找到结束标记.<br /><br />");
if (rawBlock?.Length > 0)
{
exception.AppendLine($"<strong>The last successfully parsed block was:</strong><br /> {rawBlock}");
exception.AppendLine(
$"<strong>最后一个成功解析的块是:</strong><br /> {rawBlock}");
}
exception.AppendLine($"<strong>The problem occurred after:</strong><br /> {pageContent.ToString().Substring(startPos)}<br /><br />");
exception.AppendLine($"<strong>The content the parser was working on is:</strong><br /> {pageContent}<br /><br />");
exception.AppendLine(
$"<strong>问题发生在:</strong><br /> {pageContent.ToString().Substring(startPos)}<br /><br />");
exception.AppendLine(
$"<strong>解析器正在处理的内容是:</strong><br /> {pageContent}<br /><br />");
throw new Exception(exception.ToString());
}
@@ -369,10 +369,10 @@ namespace ZelWiki.Engine
}
/// <summary>
/// Transform blocks or sections of code, these are thinks like panels and alerts.
///
/// </summary>
/// <param name="pageContent"></param>
/// <param name="isFirstChance">Only process early functions (like code blocks)</param>
/// <param name="isFirstChance"></param>
private void TransformScopeFunctions(WikiString pageContent, bool isFirstChance)
{
// {{([\\S\\s]*)}}
@@ -387,14 +387,14 @@ namespace ZelWiki.Engine
FunctionCall function;
//We are going to mock up a function call:
string mockFunctionCall = "##" + match.Value.Trim([' ', '\t', '{', '}']);
try
{
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, mockFunctionCall, out paramEndIndex);
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, mockFunctionCall,
out paramEndIndex);
var firstChanceFunctions = new string[] { "code" }; //Process these the first time through.
var firstChanceFunctions = new [] { "code" };
if (isFirstChance && firstChanceFunctions.Contains(function.Name.ToLower()) == false)
{
continue;
@@ -411,7 +411,8 @@ namespace ZelWiki.Engine
try
{
var result = functionHandler.Handle(this, function, scopeBody);
StoreHandlerResult(result, Constants.WikiMatchType.ScopeFunction, pageContent, match.Value, scopeBody);
StoreHandlerResult(result, WikiMatchType.ScopeFunction, pageContent, match.Value,
scopeBody);
}
catch (Exception ex)
{
@@ -421,7 +422,7 @@ namespace ZelWiki.Engine
}
/// <summary>
/// Transform headings. These are the basic HTML H1-H6 headings but they are saved for the building of the table of contents.
///
/// </summary>
/// <param name="pageContent"></param>
private void TransformHeadings(WikiString pageContent)
@@ -431,28 +432,32 @@ namespace ZelWiki.Engine
foreach (var match in orderedMatches)
{
int headingMarkers = 0;
foreach (char c in match.Value)
var headingMarkers = 0;
foreach (var c in match.Value)
{
if (c != '=')
{
break;
}
headingMarkers++;
}
if (headingMarkers >= 2)
{
string link = _tocName + "_" + TableOfContents.Count.ToString();
string text = match.Value.Substring(headingMarkers, match.Value.Length - headingMarkers).Trim().Trim(['=']).Trim();
var link = _tocName + "_" + TableOfContents.Count.ToString();
var text = match.Value.Substring(headingMarkers, match.Value.Length - headingMarkers).Trim()
.Trim(['=']).Trim();
var result = Engine.HeadingHandler.Handle(this, headingMarkers, link, text);
if (!result.Instructions.Contains(Constants.HandlerResultInstruction.Skip))
if (!result.Instructions.Contains(HandlerResultInstruction.Skip))
{
TableOfContents.Add(new TableOfContentsTag(headingMarkers - 1, match.Index, link, text));
}
StoreHandlerResult(result, Constants.WikiMatchType.Heading, pageContent, match.Value, result.Content);
StoreHandlerResult(result, WikiMatchType.Heading, pageContent, match.Value,
result.Content);
}
}
}
@@ -465,7 +470,7 @@ namespace ZelWiki.Engine
foreach (var match in orderedMatches)
{
var result = Engine.CommentHandler.Handle(this, match.Value);
StoreHandlerResult(result, Constants.WikiMatchType.Comment, pageContent, match.Value, result.Content);
StoreHandlerResult(result, WikiMatchType.Comment, pageContent, match.Value, result.Content);
}
}
@@ -476,23 +481,23 @@ namespace ZelWiki.Engine
foreach (var match in orderedMatches)
{
string key = match.Value.Trim().ToLower().Trim('%');
int scale = 100;
var key = match.Value.Trim().ToLower().Trim('%');
var scale = 100;
var parts = key.Split(',');
if (parts.Length > 1)
{
key = parts[0]; //Image key;
scale = int.Parse(parts[1]); //Image scale.
key = parts[0];
scale = int.Parse(parts[1]);
}
var result = Engine.EmojiHandler.Handle(this, $"%%{key}%%", scale);
StoreHandlerResult(result, Constants.WikiMatchType.Emoji, pageContent, match.Value, result.Content);
StoreHandlerResult(result, WikiMatchType.Emoji, pageContent, match.Value, result.Content);
}
}
/// <summary>
/// Transform variables.
///
/// </summary>
/// <param name="pageContent"></param>
private void TransformVariables(WikiString pageContent)
@@ -502,7 +507,7 @@ namespace ZelWiki.Engine
foreach (var match in orderedMatches)
{
string key = match.Value.Trim(['{', '}', ' ', '\t', '$']);
var key = match.Value.Trim(['{', '}', ' ', '\t', '$']);
if (key.Contains("="))
{
var sections = key.Split('=');
@@ -514,27 +519,27 @@ namespace ZelWiki.Engine
Variables[key] = value;
}
var identifier = StoreMatch(Constants.WikiMatchType.Variable, pageContent, match.Value, "");
var identifier = StoreMatch(WikiMatchType.Variable, pageContent, match.Value, "");
pageContent.Replace($"{identifier}\n", $"{identifier}"); //Kill trailing newline.
}
else
{
if (Variables.TryGetValue(key, out string? value))
{
var identifier = StoreMatch(Constants.WikiMatchType.Variable, pageContent, match.Value, value);
var identifier = StoreMatch(WikiMatchType.Variable, pageContent, match.Value, value);
pageContent.Replace($"{identifier}\n", $"{identifier}"); //Kill trailing newline.
}
else
{
throw new Exception($"The wiki variable {key} is not defined. It should be set with ##Set() before calling Get().");
throw new Exception(
$"未定义的变量 {key} . 在再用Get()应该先使用##Set().");
}
}
}
}
/// <summary>
/// Transform links, these can be internal Wiki links or external links.
///
/// </summary>
/// <param name="pageContent"></param>
private void TransformLinks(WikiString pageContent)
@@ -572,7 +577,6 @@ namespace ZelWiki.Engine
}
}
//Parse external explicit links. eg. [[https://test.net]].
orderedMatches = WikiUtility.OrderMatchesByLengthDescending(
PrecompiledRegex.TransformExplicitHTTPsLinks().Matches(pageContent.ToString()));
@@ -605,7 +609,6 @@ namespace ZelWiki.Engine
}
}
//Parse internal links. eg [[About Us]], [[About Us, Learn about us]], etc..
orderedMatches = WikiUtility.OrderMatchesByLengthDescending(
PrecompiledRegex.TransformInternalDynamicLinks().Matches(pageContent.ToString()));
@@ -622,29 +625,26 @@ namespace ZelWiki.Engine
if (args.Count == 1)
{
//Page navigation only.
text = WikiUtility.GetPageNamePart(args[0]); //Text will be page name since we have an image.
text = WikiUtility.GetPageNamePart(args[0]);
pageName = args[0];
}
else if (args.Count >= 2)
{
//Page navigation and explicit text (possibly image).
pageName = args[0];
string imageTag = "image:";
if (args[1].StartsWith(imageTag, StringComparison.CurrentCultureIgnoreCase))
{
image = args[1].Substring(imageTag.Length).Trim();
text = WikiUtility.GetPageNamePart(args[0]); //Text will be page name since we have an image.
text = WikiUtility.GetPageNamePart(args[0]);
}
else
{
text = args[1]; //Explicit text.
text = args[1];
}
if (args.Count >= 3)
{
//Get the specified image scale.
if (int.TryParse(args[2], out imageScale) == false)
{
imageScale = 100;
@@ -659,32 +659,24 @@ namespace ZelWiki.Engine
var pageNavigation = new NamespaceNavigation(pageName);
if (pageName.Trim().StartsWith("::"))
{
//The user explicitly specified the root (unnamed) namespace.
}
else if (string.IsNullOrEmpty(pageNavigation.Namespace))
{
//No namespace was specified, use the current page namespace.
pageNavigation.Namespace = Page.Namespace;
}
else
{
//Use the namespace that the user explicitly specified.
}
var result = Engine.InternalLinkHandler.Handle(this, pageNavigation, pageName.Trim(':'), text, image, imageScale);
if (!result.Instructions.Contains(Constants.HandlerResultInstruction.Skip))
if (string.IsNullOrEmpty(pageNavigation.Namespace) || pageName.Trim().StartsWith("::"))
pageNavigation.Namespace = Page.Namespace;
var result = Engine.InternalLinkHandler.Handle(this, pageNavigation, pageName.Trim(':'), text, image,
imageScale);
if (!result.Instructions.Contains(HandlerResultInstruction.Skip))
{
OutgoingLinks.Add(new PageReference(pageName, pageNavigation.Canonical));
}
StoreHandlerResult(result, Constants.WikiMatchType.Link, pageContent, match.Value, string.Empty);
StoreHandlerResult(result, WikiMatchType.Link, pageContent, match.Value, string.Empty);
}
}
/// <summary>
/// Transform processing instructions are used to flag pages for specific needs such as deletion, review, draft, etc.
///
/// </summary>
/// <param name="pageContent"></param>
private void TransformProcessingInstructionFunctions(WikiString pageContent)
@@ -701,7 +693,8 @@ namespace ZelWiki.Engine
try
{
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, match.Value, out int matchEndIndex);
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, match.Value,
out int matchEndIndex);
}
catch (Exception ex)
{
@@ -712,7 +705,8 @@ namespace ZelWiki.Engine
try
{
var result = functionHandler.Handle(this, function, string.Empty);
StoreHandlerResult(result, Constants.WikiMatchType.Instruction, pageContent, match.Value, string.Empty);
StoreHandlerResult(result, Constants.WikiMatchType.Instruction, pageContent, match.Value,
string.Empty);
}
catch (Exception ex)
{
@@ -722,9 +716,10 @@ namespace ZelWiki.Engine
}
/// <summary>
/// Transform functions is used to call wiki functions such as including template pages, setting tags and displaying images.
///
/// </summary>
/// <param name="pageContent"></param>
/// <param name="isFirstChance"></param>
private void TransformStandardFunctions(WikiString pageContent, bool isFirstChance)
{
//Remove the last "(\#\#[\w-]+)" if you start to have matching problems:
@@ -739,7 +734,8 @@ namespace ZelWiki.Engine
try
{
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, match.Value, out int matchEndIndex);
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, match.Value,
out int matchEndIndex);
}
catch (WikiFunctionPrototypeNotDefinedException ex)
{
@@ -753,6 +749,7 @@ namespace ZelWiki.Engine
continue; //This IS a function, but it is meant to be parsed at the end of processing.
}
}
StoreError(pageContent, match.Value, ex.Message);
continue;
}
@@ -771,7 +768,8 @@ namespace ZelWiki.Engine
try
{
var result = functionHandler.Handle(this, function, string.Empty);
StoreHandlerResult(result, Constants.WikiMatchType.StandardFunction, pageContent, match.Value, string.Empty);
StoreHandlerResult(result, Constants.WikiMatchType.StandardFunction, pageContent, match.Value,
string.Empty);
}
catch (Exception ex)
{
@@ -781,8 +779,9 @@ namespace ZelWiki.Engine
}
/// <summary>
/// Transform post-process are functions that must be called after all other transformations. For example, we can't build a table-of-contents until we have parsed the entire page.
///
/// </summary>
/// <param name="pageContent"></param>
private void TransformPostProcessingFunctions(WikiString pageContent)
{
//Remove the last "(\#\#[\w-]+)" if you start to have matching problems:
@@ -797,7 +796,8 @@ namespace ZelWiki.Engine
try
{
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, match.Value, out int matchEndIndex);
function = FunctionParser.ParseAndGetFunctionCall(functionHandler.Prototypes, match.Value,
out int matchEndIndex);
}
catch (Exception ex)
{
@@ -808,7 +808,8 @@ namespace ZelWiki.Engine
try
{
var result = functionHandler.Handle(this, function, string.Empty);
StoreHandlerResult(result, Constants.WikiMatchType.StandardFunction, pageContent, match.Value, string.Empty);
StoreHandlerResult(result, Constants.WikiMatchType.StandardFunction, pageContent, match.Value,
string.Empty);
}
catch (Exception ex)
{
@@ -821,33 +822,31 @@ namespace ZelWiki.Engine
{
string identifier = $"<!--{Guid.NewGuid()}-->";
//Replace new-lines with single character new line:
pageContent.Replace("\r\n", "\n");
//Replace new-lines with an identifier so we can identify the places we are going to introduce line-breaks:
pageContent.Replace("\n", identifier);
//Replace any consecutive to-be-line-breaks that we are introducing with single line-break identifiers.
pageContent.Replace($"{identifier}{identifier}", identifier);
//Swap in the real line-breaks.
pageContent.Replace(identifier, "<br />");
}
#region Utility.
private void StoreHandlerResult(HandlerResult result, Constants.WikiMatchType matchType, WikiString pageContent, string matchValue, string scopeBody)
private void StoreHandlerResult(HandlerResult result, WikiMatchType matchType, WikiString pageContent,
string matchValue, string scopeBody)
{
if (result.Instructions.Contains(Constants.HandlerResultInstruction.Skip))
if (result.Instructions.Contains(HandlerResultInstruction.Skip))
{
return;
}
bool allowNestedDecode = !result.Instructions.Contains(Constants.HandlerResultInstruction.DisallowNestedProcessing);
bool allowNestedDecode =
!result.Instructions.Contains(HandlerResultInstruction.DisallowNestedProcessing);
string identifier;
if (result.Instructions.Contains(Constants.HandlerResultInstruction.OnlyReplaceFirstMatch))
if (result.Instructions.Contains(HandlerResultInstruction.OnlyReplaceFirstMatch))
{
identifier = StoreFirstMatch(matchType, pageContent, matchValue, result.Content, allowNestedDecode);
}
@@ -860,7 +859,7 @@ namespace ZelWiki.Engine
{
switch (instruction)
{
case Constants.HandlerResultInstruction.TruncateTrailingLine:
case HandlerResultInstruction.TruncateTrailingLine:
pageContent.Replace($"{identifier}\n", $"{identifier}"); //Kill trailing newline.
break;
}
@@ -888,7 +887,7 @@ namespace ZelWiki.Engine
{
Content = $"<i><font size=\"3\" color=\"#BB0000\">{{{value}}}</font></a>",
AllowNestedDecode = false,
MatchType = Constants.WikiMatchType.Error
MatchType = WikiMatchType.Error
};
Matches.Add(identifier, matchSet);
@@ -897,7 +896,8 @@ namespace ZelWiki.Engine
return identifier;
}
private string StoreMatch(Constants.WikiMatchType matchType, WikiString pageContent, string match, string value, bool allowNestedDecode = true)
private string StoreMatch(WikiMatchType matchType, WikiString pageContent, string match, string value,
bool allowNestedDecode = true)
{
MatchCount++;
_matchesStoredPerIteration++;
@@ -917,7 +917,8 @@ namespace ZelWiki.Engine
return identifier;
}
private string StoreFirstMatch(Constants.WikiMatchType matchType, WikiString pageContent, string match, string value, bool allowNestedDecode = true)
private string StoreFirstMatch(WikiMatchType matchType, WikiString pageContent, string match,
string value, bool allowNestedDecode = true)
{
MatchCount++;
_matchesStoredPerIteration++;
@@ -940,17 +941,16 @@ namespace ZelWiki.Engine
}
/// <summary>
/// Used to generate unique and regenerable tokens so different wikification process can identify
/// their own query strings. For instance, we can have more than one pager on a wiki page, this
/// allows each pager to track its own current page in the query string.
///
/// </summary>
/// <returns></returns>
public string GetNextQueryToken()
{
_queryTokenHash = ZelWiki.Security.Helpers.Sha256(ZelWiki.Security.Helpers.EncryptString(ZelWiki.Security.Helpers.MachineKey, _queryTokenHash));
return $"H{ZelWiki.Security.Helpers.Crc32(_queryTokenHash)}";
_queryTokenHash = Security.Helpers.Sha256(
Security.Helpers.EncryptString(Security.Helpers.MachineKey, _queryTokenHash));
return $"H{Security.Helpers.Crc32(_queryTokenHash)}";
}
#endregion
}
}
}