using System.Text.RegularExpressions; using ZelWiki.Engine.Function; using ZelWiki.Models; namespace ZelWiki.Engine { /// /// Tiny wikifier (reduced feature-set) for things like comments and profile bios. /// public class WikifierLite { public static string Process(string? unprocessedText) { unprocessedText = unprocessedText?.Trim() ?? string.Empty; if (string.IsNullOrWhiteSpace(unprocessedText)) { return string.Empty; } for (int i = 0; i < 100; i++) //We don't want to process nested wiki forever. { bool processedMatches = false; var matchStore = new Dictionary(); var content = new WikiString(unprocessedText); TransformEmoji(content, matchStore); TransformLinks(content, matchStore); TransformMarkup(content, matchStore); foreach (var match in matchStore) { processedMatches = true; content.Replace(match.Key, match.Value); } if (!processedMatches) { break; } unprocessedText = content.ToString(); } return unprocessedText; } private static string StoreMatch(Dictionary matchStore, string value) { var guid = Guid.NewGuid().ToString(); matchStore.Add(guid, value); return guid; } private static void TransformEmoji(WikiString pageContent, Dictionary matchStore) { var rgx = new Regex(@"(%%.+?%%)", RegexOptions.IgnoreCase); var matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString())); foreach (var match in matches) { string key = match.Value.Trim().ToLower().Trim('%'); int scale = 100; var parts = key.Split(','); if (parts.Length > 1) { key = parts[0]; //Image key; scale = int.Parse(parts[1]); //Image scale. } key = $"%%{key}%%"; var emoji = GlobalConfiguration.Emojis.FirstOrDefault(o => o.Shortcut == key); if (GlobalConfiguration.Emojis.Exists(o => o.Shortcut == key)) { if (scale != 100 && scale > 0 && scale <= 500) { var emojiImage = $"\"{emoji?.Name}\""; pageContent.Replace(match.Value, StoreMatch(matchStore, emojiImage)); } else { var emojiImage = $"\"{emoji?.Name}\""; pageContent.Replace(match.Value, StoreMatch(matchStore, emojiImage)); } } else { pageContent.Replace(match.Value, StoreMatch(matchStore, string.Empty)); } } } /// /// Transform basic markup such as bold, italics, underline, etc. for single and multi-line. /// /// private static void TransformMarkup(WikiString pageContent, Dictionary matchStore) { var symbols = WikiUtility.GetApplicableSymbols(pageContent.Value); foreach (var symbol in symbols) { var sequence = new string(symbol, 2); var escapedSequence = Regex.Escape(sequence); var rgx = new Regex(@$"{escapedSequence}(.*?){escapedSequence}", RegexOptions.IgnoreCase); var orderedMatches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString())); foreach (var match in orderedMatches) { string body = match.Value.Substring(sequence.Length, match.Value.Length - sequence.Length * 2); var markup = symbol switch { '~' => $"{body}", '*' => $"{body}", '_' => $"{body}", '/' => $"{body}", '!' => $"{body}", _ => body, }; pageContent.Replace(match.Value, StoreMatch(matchStore, markup)); } } } /// /// Transform links, these can be internal Wiki links or external links. /// /// private static void TransformLinks(WikiString pageContent, Dictionary matchStore) { //Parse external explicit links. eg. [[http://test.net]]. var rgx = new Regex(@"(\[\[http\:\/\/.+?\]\])", RegexOptions.IgnoreCase); var matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString())); foreach (var match in matches) { string keyword = match.Value.Substring(2, match.Value.Length - 4).Trim(); var args = FunctionParser.ParseRawArgumentsAddParenthesis(keyword); if (args.Count > 1) { pageContent.Replace(match.Value, StoreMatch(matchStore, $"{args[1]}")); } else { pageContent.Replace(match.Value, StoreMatch(matchStore, $"{args[0]}")); } } //Parse external explicit links. eg. [[https://test.net]]. rgx = new Regex(@"(\[\[https\:\/\/.+?\]\])", RegexOptions.IgnoreCase); matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString())); foreach (var match in matches) { string keyword = match.Value.Substring(2, match.Value.Length - 4).Trim(); var args = FunctionParser.ParseRawArgumentsAddParenthesis(keyword); if (args.Count == 1) { pageContent.Replace(match.Value, StoreMatch(matchStore, $"{args[1]}")); } else if (args.Count > 1) { pageContent.Replace(match.Value, StoreMatch(matchStore, $"{args[0]}")); } } //Parse internal dynamic links. eg [[AboutUs|About Us]]. rgx = new Regex(@"(\[\[.+?\]\])", RegexOptions.IgnoreCase); matches = WikiUtility.OrderMatchesByLengthDescending(rgx.Matches(pageContent.ToString())); foreach (var match in matches) { string keyword = match.Value.Substring(2, match.Value.Length - 4); var args = FunctionParser.ParseRawArgumentsAddParenthesis(keyword); if (args.Count == 1) { pageContent.Replace(match.Value, StoreMatch(matchStore, $"{args[0]}")); } else if (args.Count > 1) { pageContent.Replace(match.Value, StoreMatch(matchStore, $"{args[1]}")); } } } } }