WMarkDown/CSharp/WMarkDown.cs

1209 lines
53 KiB
C#
Raw Normal View History

using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace Whalers{
public class WMarkDown{
public class Module{
public int environment;
public Regex pattern;
public Module(int environment, Regex pattern){
this.environment = environment;
this.pattern = pattern;
}
};
public class Item{
public bool exists = true;
public int from = -1;
public int length = -1;
public Match? matches = null;
};
public class ListStructure{
public int separator;
public char type;
public char? subtype;
public ListStructure(int separator, bool unordenered, char? subtype){
this.separator = separator;
this.type = unordenered ? 'u' : 'o';
this.subtype = subtype;
}
}
public class ProcessResults{
public string results;
public Dictionary<string, string> variables;
public ProcessResults(string results, Dictionary<string, string> variables){
this.results = results;
this.variables = variables;
}
};
public class ItemMark{
public string start;
public string end;
public Regex pattern;
public ItemMark(string start, string end, string pattern){
this.start = start;
this.end = end;
this.pattern = new Regex(pattern);
}
};
public class LinkPresententationModel{
public string title;
public List<string> avatars = new List<string>();
public List<string> links = new List<string>();
public LinkPresententationModel(string title)
{
this.title = title;
}
}
// Languages
public const int HTML = 1 << 0;
// Analyse modes
public const int RAW = 0;
public const int SUBITEM = 1 << 0;
public const int LINKED = 1 << 1;
public static Dictionary<string, string> html_special_characters = new Dictionary<string, string>
{
{"<", "lt" },
{">", "gt" },
{"&", "amp" }
};
public static Dictionary<string, string> quote_special = new Dictionary<string, string>
{
{ "?", "ask"},
{"!", "warning" },
{">", "answer" },
{"Q", "comment" },
{"#", "note" }
};
public static WMarkDown.ItemMark item_mark = new WMarkDown.ItemMark("###@&&_", "_&&@###", @"\#{3}\@\&{2}_([0-9]+)_\&{2}\@\#{3}");
public static string re_block_html_pattern = @"^[ \t]*<\!\-{2}[ \t]*\[{2}[\t ]*(wmd|wmarkdown)[ \t]*\]{2}[\t ]*\-{2}>";
public static Regex re_block_html = new Regex(WMarkDown.re_block_html_pattern, RegexOptions.Multiline);
public static Regex re_block_mark = new Regex(@"^[ \t]*(("" ?){3}|(' ?){3}|(` ?){3})[ \t]*(wmd|wmarkdown)|" + WMarkDown.re_block_html_pattern, RegexOptions.Multiline);
public static Regex re_new_lines = new Regex(@"[\r\n]+");
public static Regex re_new_line = new Regex(@"\n|\r\n|\r");
public static Regex re_started_white_spaces = new Regex(@"^[ \t]*");
public static Regex re_lines = new Regex(@"^[^\r\n]+", RegexOptions.Multiline);
public static Regex re_list_line = new Regex(@"^([ \t]*)(([\-\*#\+]+)|([0-9]+|[a-z]+)\.)?(.*)$", RegexOptions.IgnoreCase | RegexOptions.Multiline);
public static Regex re_table_line = new Regex(@"^\|([^\r\n""']+|""([^""\\\\]+|\\\\(.|[\r\n])|[\r\n]+)*""|'([^'\\\\]+|\\\\(.|[\r\n])|[\r\n]+)*')*[\r\n]*", RegexOptions.Multiline);
public static Regex re_table_item = new Regex(@"(\|+)(([^\|'""]+|""([^""\\\\]+|\\\\(.|[\r\n])|[\r\n]+)*""|'([^'\\\\]+|\\\\(.|[\r\n])|[\r\n]+)*')*)");
public static Regex re_options = new Regex(@"`{3}[ \t]*(wmd|wmarkdown)\-options[ \t]*(\n|\r\n|\r)(([^\r\n`]+|[\r\n]+|`{1,2}[^`])*)`{3}");
public static Regex re_option = new Regex(@"^([^=\r\n]+)=([^\r\n]*)$", RegexOptions.Multiline);
public static Regex re_extension = new Regex(@"(([^\.\/\\\\]+)\.)?([^\.\/\\\\]+)$");
public static Regex re_characters_no_id = new Regex(@"[^a-z0-9]+", RegexOptions.Multiline);
public static Regex re_phone_number = new Regex(@"^\+?[0-9 ]{5,22}$");
public static Regex re_email_address = new Regex(@"^[a-z\.0-9_\-]+@[a-z\.0-9_\-]+\.[a-z0-9]+$");
public static Regex re_class_attribute = new Regex(@"(?<![a-z0-9_\-])(class="")([^""]+)("")");
public static Regex re_white_spaces = new Regex(@"[ \t]+");
public static Regex re_line_marks = new Regex(@"[\*#~\-_]+|\[[ \-x]\]|\([ \-x]\)", RegexOptions.IgnoreCase);
public static Regex re_integer = new Regex(@"^[0-9]+$");
public static Regex re_code_doc = new Regex(@"^(\[([^\]]+)\][ \t]+)?([\!\?])?(([^\(\[\]\?\!]+)([\:\.]))?([^\(\.\:\[\]\=]+)(\(((.+|[\r\n]+)*)\)|[ \t]*=[ \t]*((.+|[\r\n]+)*))?");
public static Regex re_code_doc_arguments = new Regex(@"([\!\?]{0,2})([^=]+)[ \t]+([^=]+)(=(.+))?");
public static Regex re_code_doc_subarguments = new Regex(@"<([^<>]+)>|(""[^""]*""|'[^']*')");
public static Regex re_start_with_white_spaces = new Regex(@"^[ \t]", RegexOptions.Multiline);
public static Regex re_domain = new Regex(@"^[^\:]+\:\/{2}[^\/]+");
public static Regex re_protocol = new Regex(@"^([a-z0-9_\-]+)\:", RegexOptions.IgnoreCase);
public Dictionary<string, WMarkDown.Module> modules = new Dictionary<string, WMarkDown.Module>
{
{"special_characters", new WMarkDown.Module(WMarkDown.SUBITEM, new Regex(@"\\([\(\{\[\*\\])"))},
{"title", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"^((#{1,6})[\t ]*([^\r\n]+)|(={1,6})[\t ]*([^\r\n=]+)={1,6})(\n|\r\n|\r){2,}", RegexOptions.Multiline))},
{"list", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"^([\-\*#\+]+|([0-9]+|[a-z]+)\.)[^\r\n]*(\n|\r\n|\r)([\t ]*(([\-\*#\+]+|([0-9]+|[a-z]+)\.)[^\r\n]*)(\n|\r\n|\r)?)*", RegexOptions.IgnoreCase| RegexOptions.Multiline))},
{"code_block", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"^(""{3}([^\r\n]*)(((?!""{3})(.|[\r\n]))+)""{3}|"" "" ""([^\r\n]*)(((?!"" "" "")(.|[\r\n]))+)"" "" ""|'{3}([^\r\n]*)(((?!'{3})(.|[\r\n]))+)'{3}|' ' '([^\r\n]*)(((?!' ' ')(.|[\r\n]))+)' ' '|`{3}([^\r\n]*)(((?!`{3})(.|[\r\n]))+)`{3}|` ` `([^\r\n]*)(((?!` ` `)(.|[\r\n]))+)` ` `)", RegexOptions.Multiline))},
{"table", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"^\[\|([^\r\n]*)[\r\n]+((^\|([^\]]([^\r\n""']|""([^""\\\\]+|\\\\(.|[\r\n])|[\r\n]+)*""|'([^'\\\\]+|\\\\(.|[\r\n])|[\r\n]+)*')*)?[\r\n]+)*)^\|\]", RegexOptions.Multiline))},
{"quote", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"^>[ \t]*(\[\![\t ]*([^\] \t]+)([ \t]+([^\]]+))?\])?(([^\r\n]+(\r\n|[\r\n])?)*)", RegexOptions.Multiline))},
{"include", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"^\[{2}include[ \t]+([^\]]+)\]{2}", RegexOptions.Multiline))},
{"media", new WMarkDown.Module(WMarkDown.SUBITEM | WMarkDown.LINKED, new Regex(@"\({2}\!(image|icon|video|audio|sound|picture)[ \t]+(""(([^""]+|[\r\n]+))""|'(([^']+|[\r\n]+))'|([^ \t\)]+))([ \t]*|[ \t]+(""(([^\\\\""]+|\\\\.|[\r\n]+)*)""|'(([^'\\\\]+|\\\\.|[\r\n]+)*)'|([^\)]+)))\){2}", RegexOptions.IgnoreCase))},
{"code_doc", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"^\[{2}@(([^\]]+|\][^\]])+)\]{2}", RegexOptions.Multiline))},
{"presentation_links", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"^\[{2}""{3}(([^""]+|[\r\n]+|""{1,2}[^""])*)""{3}\]{2}", RegexOptions.Multiline))},
{"paragraph", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"^(([^\r\n]+(\n|\r\n|\r)?)+)", RegexOptions.Multiline))},
{"bold", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"(?<!\\)\*{2}((?:\\\*|\*[^\*]|[^*\r\n]|[\r\n]|(?!\*{2}[^\*])\*)*)\*{2}"))},
{"italic", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"(?<!\\)\*((?:\\\*|[^*\r\n]|[\r\n]|\*{2})*)\*"))},
{"underline", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"_{2}(([^_]+|_[^_])+)_{2}"))},
{"strike", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"~{2}(([^~]+|~[^~])+)~{2}"))},
{"code_item", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"`{2}(([^`]+|`[^`])+)`{2}"))},
{"checkbox", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"\[((\-)|(x)|( ))\]", RegexOptions.IgnoreCase))},
{"radio", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"\(((\-)|(x)|( ))\)", RegexOptions.IgnoreCase))},
{"tick", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"\{((w)|(v)|(x))\}", RegexOptions.IgnoreCase))},
{"color_sample", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"\[{2}((\#[a-f0-9]{3,8})|color[ \t]+([^\[\]\t\r\n]+))\]{2}", RegexOptions.IgnoreCase))},
{"exclude", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"\[{2}\!(([^\]]+|\][^\]]|[\r\n])*)\]{2}"))},
{"link", new WMarkDown.Module(WMarkDown.RAW, new Regex(@"(\[([^\[\]]+)\])?\((([^\(\) \t]+)[ \t]+(""(([^\\\\""]+|\\\\.|[\r\n]+)*)""|\'(([^\\\\\']+|\\\\.|[\r\n]+)*)\'|([^\(\)]+)?))[ \t]*\)|\[(\+?[0-9 ]{5,22}|[^ \]]+)([\t ]+([^\]]*))?\]|([a-z0-9]{3,8}\:\/{2}[^ \(\[\)\]>]+|[a-z\.0-9_\-]+@[a-z\.0-9_\-]+\.[a-z0-9]+)", RegexOptions.IgnoreCase))}
};
private List<string> ids_cache = new List<string>();
public WMarkDown() { }
private string id(string _string)
{
string id = WMarkDown.re_characters_no_id.Replace(_string, "-");
if (id[0] == '-')
id = id.Substring(1);
if (id[id.Length - 1] == '-')
id = id.Substring(0, id.Length - 1);
if (this.ids_cache.Contains(id))
{
int i = 1;
while (this.ids_cache.Contains(id + "-" + ++i)) ;
id += "-" + i;
}
this.ids_cache.Add(id);
return id;
}
public void reset_ids() => this.ids_cache = new List<string>();
public string? module_title(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
{
int level = ("" + (matches.Groups[2] ?? matches.Groups[4])).Length;
string content = ("" + (matches.Groups[3] ?? matches.Groups[5])).Trim();
string id = this.id(content);
return ("<h" + level + " class=\"wmd-title\" id=\"" + id + "\" title=\"" + content + "\">" +
"<span>" + this.analyse(content, language, WMarkDown.SUBITEM, path) + "</span>" +
"<a href=\"#" + id + "\" target=\"_blank\">" +
"<span data-icon=\"link\"></span>" +
"</a>" +
"</h" + level + ">");
}
return null;
}
public string? module_paragraph(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
return "<p>" + this.analyse(("" + matches.Groups[0]).Trim(), language, WMarkDown.SUBITEM, path) + "</p>";
return null;
}
public string? module_bold_italic(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
return "<b><i>" + this.analyse(("" + matches.Groups[1]).Trim(), language, WMarkDown.SUBITEM, path) + "</i></b>";
return null;
}
public string? module_bold(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
return "<b>" + this.analyse(("" + matches.Groups[1]).Trim(), language, WMarkDown.SUBITEM, path) + "</b>";
return null;
}
public string? module_italic(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
return "<i>" + this.analyse(("" + matches.Groups[1]).Trim(), language, WMarkDown.SUBITEM, path) + "</i>";
return null;
}
public string? module_strike(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
return "<del>" + this.analyse(("" + matches.Groups[1]).Trim(), language, WMarkDown.SUBITEM, path) + "</del>";
return null;
}
public string? module_underline(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
return "<u>" + this.analyse(("" + matches.Groups[1]).Trim(), language, WMarkDown.SUBITEM, path) + "</u>";
return null;
}
public string? module_code_item(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
return "<code>" + this.analyse(("" + matches.Groups[1]).Trim(), language, WMarkDown.SUBITEM, path) + "</code>";
return null;
}
private static string check_html_module(string type, Match matches)
{
bool is_radio = type == "radio";
return ("<label class=\"wmd-icon " + (is_radio ? "radio-button" : type) + "\">" +
"<input type=\"" + (type == "tick" ? "checkbox" : type) + "\" readonly onclick=\"return false;\"" + (
matches.Groups[2] != null ? " disabled" :
matches.Groups[3] != null ? " checked" :
"") + " />" +
"<span data-icon=\"" + (is_radio ? "radio_button" : type) + "\"></span>" +
"</label>");
}
public string? module_checkbox(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
return WMarkDown.check_html_module("checkbox", matches);
return null;
}
public string? module_radio(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
return WMarkDown.check_html_module("radio", matches);
return null;
}
public string? module_tick(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
return WMarkDown.check_html_module("tick", matches);
return null;
}
private static string list_deployed(WMarkDown.ListStructure level, string? last_mark, int l)
{
string type = l != 0 && !String.IsNullOrEmpty(last_mark) ? last_mark : "" + level.subtype;
bool deployable = l != 0 && type != "" && "+-".Contains(type);
string deployed = (
!deployable ? "null" :
type == "-" ? "false" :
"true");
return " data-deployed=\"" + deployed + "\"" + (deployable ? " data-list-unprocessed=\"true\"" : "");
}
private static string list_start(bool unordered, string type)
{
if (!unordered)
{
type = type.Substring(0, type.Length - 1);
if (WMarkDown.re_integer.Match(type) != null)
return " start=\"" + type + "\"";
}
return "";
}
public string? module_list(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
{
string html = "";
List<WMarkDown.ListStructure> levels = new List<ListStructure> { new ListStructure(0, true, null) };
int l = 0;
string? last_mark = null;
char[] roman_number_marks = new char[] { 'a', 'A', 'i', 'I' };
char? subtype = null;
foreach (string line in WMarkDown.re_new_line.Split("" + matches.Groups[0]))
{
Match line_matches = WMarkDown.re_list_line.Match(line);
if (line_matches == null)
continue;
int separator_by_marks = (line_matches.Groups[3] == null ? "" : "" + line_matches.Groups[3]).Length;
int separator = separator_by_marks > 1 ? separator_by_marks : ("" + line_matches.Groups[1]).Length;
string type = "" + line_matches.Groups[2];
string key = "" + line_matches.Groups[4];
string _string = this.analyse("" + line_matches.Groups[5], language, WMarkDown.SUBITEM, path).Trim();
bool has_type = type != "";
bool unordered = has_type && new char[] { '-', '*', '+' }.Contains(type[type.Length - 1]);
subtype = has_type ? type[type.Length - 1] : null;
if (has_type)
{
if (levels[l].separator == separator)
{
levels[l].type = unordered ? 'u' : 'o';
levels[l].subtype = subtype;
html += (html != "" ? "<li>" : "<" + levels[l].type + "l class=\"wmd-list\"" + WMarkDown.list_start(unordered, type) + WMarkDown.list_deployed(levels[l - 1], last_mark, l) + (
key != "" && !unordered && roman_number_marks.Contains<char>(key[0]) ? " type=\"" + key[0] + "\"" :
"") + ">") + "</li>" + _string;
} else if (levels[l].separator < separator)
{
levels.Add(new ListStructure(separator, unordered, subtype));
html += "<" + levels[++l].type + "l class=\"wmd-list\"" + WMarkDown.list_start(unordered, type) + WMarkDown.list_deployed(levels[l - 1], last_mark, l) + (
key != "" && !unordered && roman_number_marks.Contains<char>(key[0]) ? " type=\"" + key[0] + "\"" :
"") + "><li>" + _string;
}
else
{
while (levels[l].separator > separator)
{
html += "</li></" + levels[--l].type + "l>";
levels.Remove(levels[l + 1]);
if (l == 0)
break;
}
html += "</li><li>" + _string;
}
} else
html += " " + _string;
last_mark = subtype == null ? "" : "" + subtype;
}
while (levels.Count != 0)
{
WMarkDown.ListStructure level = levels[levels.Count - 1];
html += "</li></" + level.type + "l>";
levels.Remove(level);
}
return html;
}
return null;
}
public static string set_class(string html, string[] _class)
{
if (!html.Contains("class=\""))
html = (html != "" ? " " : "") + "class=\"" + String.Join<string>(" ", _class) + "\"";
return WMarkDown.re_class_attribute.Replace(html, (Match matches) => {
string attribute = "" + matches.Groups[1];
string classes_str = "" + matches.Groups[2];
string closer = "" + matches.Groups[3];
string[] classes = WMarkDown.re_white_spaces.Split(classes_str);
string subclasses = "";
foreach (string class_key in _class)
if (!classes.Contains(class_key))
subclasses += (subclasses == "" ? "" : " ") + class_key;
return attribute + classes_str + (classes_str != "" ? " " : "") + subclasses + closer;
});
}
public static string set_class(string html, string _class) => WMarkDown.set_class(html, [_class]);
public string? module_table(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
{
Dictionary<string, string> html = new Dictionary<string, string>
{
{"thead", "" },
{"tbody", "" },
{"tfoot", "" }
};
string attributes = matches.Groups[1] == null ? "" : ("" + matches.Groups[1]).Trim();
string data = ("" + matches.Groups[3]).Trim();
char[] header_type_marks = new char[] { '^', '_', '=' };
string[] string_empty = new string[] { "''", "\"\"" };
string table_body = "";
while (true)
{
Match line_matches = WMarkDown.re_table_line.Match(data);
if (line_matches == null)
break;
string line = "" + line_matches.Groups[0];
char cell_type = header_type_marks.Contains<char>(line[1]) ? 'h' : 'd';
string[] tags = (
line[1] == '^' ? ["thead"] :
line[1] == '_' ? ["tfoot"] :
line[1] == '=' ? ["thead", "tfoot"] :
["tbody"]);
string row = "<tr>";
if (cell_type == 'h')
line = line[0] + line.Substring(2);
while (true)
{
Match cell_matches = WMarkDown.re_table_item.Match(line);
if (cell_matches == null)
break;
int column_span_i = ("" + cell_matches.Groups[1]).Length;
string colunm_span = column_span_i > 1 ? " colspan=\"" + column_span_i + "\"" : "";
string content = cell_matches.Groups[2] == null ? "" : ("" + cell_matches.Groups[2]).Trim();
row += "<t" + cell_type + column_span_i + ">" + this.analyse(
content != "" && string_empty.Contains<string>("" + content[0] + content[content.Length - 1]) ? content.Substring(1, content.Length - 2) : content,
WMarkDown.HTML,
WMarkDown.SUBITEM,
path
) + "</t" + cell_type + ">";
line = line.Substring(cell_matches.Index + cell_matches.Length);
}
row += "</tr>";
for (int i = 0, l = tags.Length; i < l; i++)
{
if (i != 0)
html[tags[i]] = row + html[tags[i]];
else
html[tags[i]] += row;
}
data = data.Substring(line_matches.Index + line_matches.Length);
}
foreach (string tag in html.Keys)
if (html[tag] != "")
table_body += "<" + tag + ">" + html[tag] + "</" + tag + ">";
return ("<div class=\"wmd-table\">" +
"<table " + attributes + ">" + table_body + "</table>" +
"</div>");
}
return null;
}
public string? module_exclude(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
return "<span class=\"wmd-excluded\">" + (matches.Groups[1] == null ? "" : "" + matches.Groups[1]) + "</span>";
return null;
}
public string? module_link(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
{
string raw_url = ("" + (matches.Groups[4] ?? matches.Groups[11] ?? matches.Groups[14])).Trim();
string url = (
WMarkDown.re_phone_number.Match(raw_url) != null ? "tel:" + raw_url.Replace(" ", "") :
WMarkDown.re_email_address.Match(raw_url) != null ? "mailto:" + raw_url :
raw_url);
string text = (
matches.Groups[2] != null ? "" + matches.Groups[2] :
matches.Groups[13] != null ? "" + matches.Groups[13] :
raw_url);
Match protocol_matches = WMarkDown.re_protocol.Match(url);
return "<a herf=\"" + url + "\" target=\"_" + (url.Contains("://") ? "blank" : "self") + "\" title=\"" + WMarkDown.re_line_marks.Replace((
matches.Groups[6] != null ? "" + matches.Groups[6] :
matches.Groups[8] != null ? "" + matches.Groups[8] :
matches.Groups[10] != null ? "" + matches.Groups[10] :
text).Trim(), "") + "\" data-protocol=\"" + (
protocol_matches != null ? ("" + protocol_matches.Groups[1]).Trim() : "http"
) + "\">" + this.analyse(text.Trim(), language, WMarkDown.SUBITEM | WMarkDown.LINKED, path) + "</a>";
}
return null;
}
public string? module_quote(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
{
string? type = matches.Groups[2] == null ? null : "" + matches.Groups[2];
string? type_text = matches.Groups[4] == null ? null : "" + matches.Groups[4];
bool has_type = !String.IsNullOrEmpty(type);
if (has_type && WMarkDown.quote_special.ContainsKey(type))
type = WMarkDown.quote_special[type];
return ("<blockquote class=\"wmd-quote\"" + (has_type ? " data-quote-type=\"" + type + "\"" : "") + ">" +
(has_type ? ("<div class=\"qupte-type\">" + (type[0] == '@' ? (
"<span data-avatar=\"" + type.Substring(1).ToLower() + "\"></span>" +
"<spanclass=\"user\">" + type.Substring(1) + "</span>"
) : (
"<span data-icon=\"" + type + "\"></span>" +
(type_text != "" ? "<span class=\"quote-type-name\">" + type_text + "</span>" : "")
)) + "</div>") : "") +
"<div class=\"text\">" + this.analyse("" + matches.Groups[5], language, WMarkDown.SUBITEM, path) + "</div>" +
"</blockquote>");
}
return null;
}
public static string? code_block_data(string key, string value, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
return ("<li data-i18n=\"" + key + "\" data-i18n-without=\"true\" title=\"" + key + "\">" +
"<span data-icon=\"" + key + "\"></span>" +
"<span data-i18n=\"" + key + "\">" + key + "</span>" +
"<span class=\"value\">" + value + "</span>" +
"</li>");
return null;
}
public static string? code_block_data(string key, int value, int language = WMarkDown.HTML, string? path = null) => WMarkDown.code_block_data(key, value, language, path);
public static string filter_html_special_characters(string _string)
{
int l = _string.Length;
int?[] index = Enumerable.Repeat<int?>(-1, l).ToArray<int?>();
string response = "";
string[] characters = WMarkDown.html_special_characters.Keys.ToArray<string>();
int m = characters.Length;
while (true)
{
int? i = null;
for(int j = 0; j < l; j++)
{
if (index[j] == null)
continue;
if (index[j] < 0 && (index[j] = _string.IndexOf(characters[j])) < 0)
index[j] = null;
if(i == null || index[i ?? 0] > index[j])
i = j;
}
if(i == null)
{
response += _string;
break;
}
int length = index[i ?? 0] ?? 0;
response += _string.Substring(0, length) + "&" + WMarkDown.html_special_characters[characters[i ?? 0]] + ";";
_string = _string.Substring(length + 1);
for (int j = 0; j < l; j++)
if (index[j] != null)
index[j] -= length + 1;
}
return response;
}
public static string? module_code_block(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
{
string type = "";
string content = "";
for(int i = 2; i < 6; i += 4)
{
type = "" + matches.Groups[i];
content = "" + matches.Groups[i + 1];
if(type != "" || content != "")
{
type = (type == "" ? "unamed" : type.Trim().ToLower());
break;
}
}
if(type != "")
{
string[] lines = WMarkDown.re_new_line.Split(content).Skip<string>(2).ToArray<string>();
string lines_string = "";
foreach (string line in lines)
lines_string += "<li></li>";
return ("<div class=\"wmd-code-block\" data-type=\"" + type + "\" data-processed=\"false\">" +
"<ul class=\"data\">" +
"<li><span data-icon=\"" + type + "\"></span></li>" +
WMarkDown.code_block_data("type", type, language) +
WMarkDown.code_block_data("characters", content.Length, language) +
WMarkDown.code_block_data("lines", lines.Length, language) +
"</ul>" +
"<div class=\"code\">" +
"<ol class=\"lines\">" + lines_string + "</ol>" +
"<pre class=\"ccontent\">" + WMarkDown.filter_html_special_characters(content) + "</pre>" +
"</div>" +
"</div>");
}
return "UNKNOWN_BLOCK";
}
return null;
}
public string? module_special_characters(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
return "" + matches.Groups[1];
return null;
}
public static string? load_file(string path)
{
if(File.Exists(path))
try
{
return File.ReadAllText(path);
}catch(Exception exception) { };
return null;
}
public string? module_include(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
{
string relative_path = "" + matches.Groups[1];
string new_path = path + relative_path;
string[] extension = Array.ConvertAll<Group, string>(WMarkDown.re_extension.Match(new_path).Groups.Values.Skip<Group>(1).ToArray<Group>(), (Group group) => "" + group);
string? content = WMarkDown.load_file(new_path);
string directory = (Path.GetDirectoryName(new_path) ?? "") + "/";
string? results = (
content == null ? null :
String.Join<string>('.', extension) == "w.md" ? this.process(content, language, directory).results :
extension[extension.Length - 1] == "md" ? this.analyse(content, language, WMarkDown.RAW, directory) :
content);
return ("<section data-path=\"" + relative_path + "\" data-include=\"" + (results == null ? "false" : "true") + "\">" +
"<div class=\"link\"><a href=\"" + relative_path + "\" target=\"_self\" title=\"" + relative_path + "\">" + relative_path + "</a></div>" +
(results ?? "") +
"</section>");
}
return null;
}
public static string build_html_image(List<string> links, string type = "image", string? title = null)
{
bool has_title = !String.IsNullOrEmpty(title);
string attributes = has_title ? " title=\"" + title + "\" alt=\"" + title + "\"" : "";
string links_html = "";
foreach (string link in links)
links_html += "<img src=\"" + link + "\"" + attributes + " />";
return ("<span class=\"wmd-media wmd-image\" data-type=\"" + type + "\" data-status=\"unprocessed\">" +
"<noscript>" + links_html + "</noscript>" +
"<img src=\"/images/WMarkDown.png\"" + attributes + " data-sources=\"" + Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonSerializer.Serialize(links))) + " />" +
"<span class=\"image\"></span>" +
(has_title ? "<span class=\"text\">" + title + "</span>" : "") +
"</span>");
}
public string? module_media(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
{
string type = ("" + matches.Groups[1]).ToLower();
List<string> links = WMarkDown.re_white_spaces.Split("" + (matches.Groups[3] ?? matches.Groups[5] ?? matches.Groups[7])).ToList<string>();
string text = ("" + (matches.Groups[10] ?? matches.Groups[12] ?? matches.Groups[14])).Trim();
switch (type)
{
case "image":
case "picture":
case "icon":
return WMarkDown.build_html_image(links, type, text);
case "video":
switch (links[0])
{
case "youtube.com":
case "youtu.be":
type = "youtube";
break;
case "vimeo.com":
type = "vimeo";
break;
}
return ("<span class=\"wmd-media wmd-video\" data-type=\"" + type + "\" data-status=\"unprocessed\">" +
"<noscript></noscript>" +
(
type == "youtube" ? "<b>YOUTUBE</b>" :
type == "vimeo" ? "<b>VIMEO</b>" :
"<video src=\"" + links[0] + "\"" + (links.Count > 1 ? " poster=\"" + links[1] + "\"" : "") + "></video>") +
"</span>");
case "sound":
case "audio":
switch (links[0])
{
case "soundcloud.com":
type = "soundcloud";
break;
}
return ("<span class=\"wmd-media wmd-video\" data-type=\"" + type + "\" data-status=\"unprocessed\">" +
"<noscript></noscript>" +
(
type == "soundcloud" ? "<b>SOUNDCLOUD</b>" :
"<audio src=\"" + links[0] + "\" controls></audio>") +
"</span>");
}
return null;
}
return null;
}
public static string mark_replace(string _string, Match matches, List<string> fragments)
{
if(matches != null)
{
_string = _string.Substring(0, matches.Index) + WMarkDown.item_mark.start + fragments.Count + WMarkDown.item_mark.end + _string.Substring(matches.Index + matches.Length);
fragments.Add("" + matches.Groups[0]);
}
return _string;
}
public static string restore_marks(string _string, List<string> fragments)
{
while (true)
{
Match matches = WMarkDown.item_mark.pattern.Match(_string);
if (matches == null)
break;
int i = ("" + matches.Groups[1]).Length;
_string = _string.Substring(0, matches.Index) + (i >= 0 && i < fragments.Count ? fragments[i] : "") + _string.Substring(matches.Index + matches.Length);
}
return _string;
}
private static string doc_typed_format(string typed) => WMarkDown.filter_html_special_characters(typed.Replace(" ", "").Replace(",", ", "));
public string? module_code_doc(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if((language & WMarkDown.HTML) != 0)
{
string data = ("" + matches.Groups[1]).Trim();
Match _base = WMarkDown.re_code_doc.Match(data);
string return_type = WMarkDown.doc_typed_format(_base.Groups[2] == null ? "void" : "" + _base.Groups[2]);
string access = _base.Groups[3] == null ? "public" : "" + _base.Groups[3];
string? name_space = _base.Groups[5] == null ? null : "" + _base.Groups[5];
string environment = _base.Groups[6] == null ? "global" : "" + _base.Groups[6];
string method = "" + _base.Groups[7];
string? parameters = _base.Groups[8] == null ? null : "" + _base.Groups;
bool has_parameters = parameters != null;
string? default_value = _base.Groups[11] == null ? null : "" + _base.Groups[11];
string full_method = (String.IsNullOrEmpty(name_space) ? "" : name_space + ".") + method.Trim();
string arguments = "";
string arguments_definition = "";
string header = ("<tr>" +
"<th data-i18n=\"name\" title=\"Name\">Name</th>" +
"<th data-i18n=\"required\" title=\"Required\">Required</th>" +
"<th data-i18n=\"nullable\" title=\"Nullable\">Nullable</th>" +
"<th data-i18n=\"typed\" title=\"Typed\">Typed</th>" +
"<th data-i18n=\"default_value\" title=\"Default Value\">Default Value</th>" +
"</tr>");
List<string> fragments = new List<string>();
int arguments_l = 0;
switch (access)
{
case "?":
access = "protected";
break;
case "!":
access = "protected";
break;
};
switch (environment)
{
case ":":
environment = "static";
break;
case ".":
environment = "object";
break;
};
if (parameters != "")
{
while (true)
{
matches = WMarkDown.re_code_doc_subarguments.Match(parameters);
if (matches != null)
parameters = WMarkDown.mark_replace(parameters, matches, fragments);
else
break;
}
}
else
parameters = "";
foreach(string parameter in parameters.Split(","))
{
matches = WMarkDown.re_code_doc_arguments.Match(parameter.Trim());
if(matches != null)
{
string scopes = "" + matches.Groups[1];
bool required = scopes.Contains("!");
bool nullish = scopes.Contains("?");
string typed = WMarkDown.doc_typed_format(WMarkDown.restore_marks("" + matches.Groups[2], fragments));
string name = ("" + matches.Groups[3]).Trim();
string default_subvalue = WMarkDown.filter_html_special_characters(WMarkDown.restore_marks(("" + matches.Groups[5]).Trim(), fragments));
arguments += ("<span class=\"arguments\">" +
(required ? "<span class=\"required\" data-i18n=\"required\" title=\"Required\">Required</span>" : "") +
(nullish ? "<span class=\"nullish\" data-i18n=\"nullish\" title=\"Nullish\">Nullish</span>" : "") +
"<span class=\"typed\" data-i18n=\"typed\" title=\"Typed\">" + typed + "</span>" +
"<span class=\"name\" data-i18n=\"name\" title=\"Named\">" + name + "</span>" +
(default_subvalue != "" ? "<span class=\"default_value\" data-i18n=\"default_value\" title=\"Default value\">" + default_subvalue + "</span>" : "") +
"</span>");
arguments_definition = ("<tr>" +
"<td class=\"name\" data-i18n=\"name\" title=\"Named\">" + name + "</td>" +
"<td class=\"required\" data-i18n=\"required\" title=\"Required\">" + (required ? "True" : "False") + "</td>" +
"<td class=\"nullish\" data-i18n=\"nullish\" title=\"Nullish\">" + (nullish ? "True" : "False") + "</td>" +
"<td class=\"typed\" data-i18n=\"typed\" title=\"Typed\">" + typed + "</td>" +
"<td class=\"default-value\" data-i18n=\"default_value\" title=\"Default value\">" + default_subvalue + "</td>" +
"</tr>");
arguments_l++;
}
}
return ("<fieldset class=\"wmd-code-doc\" data-arguments-l=\"" + arguments_l + "\">" +
"<legend>" + full_method + "</legend>" +
"<div class=\"description\">" +
"<span class=\"return-type\" data-i18n=\"return\" title=\"Return\">" + return_type + "</span>" +
"<span class=\"environment\" data-i18n=\"environment\" title=\"Environment\">" + environment + "</span>" +
"<span class=\"access\" data-i18n=\"access\" title=\"Access\">" + access + "</span>" +
"<span class=\"full-method\" data-i18n=\"full_method\" title=\"Method\">" + full_method + "</span>" +
(has_parameters ? "<span class=\"arguments\" data-i18n=\"arguments\" title=\"Arguments\">" + arguments + "</span>" : "") +
(default_value != "" ? "<span class=\"default-value\" data-i18n=\"default_value\" title=\"Default value\">" + default_value + "</span>" : "") +
"</div>" +
"<div class=\"wmd-table definition\">" +
"<table>" +
"<thead>" + header + "</thead>" +
"<tbody>" + arguments_definition + "</tbody>" +
"<tfoot>" + header + "</tfoot>" +
"</table>" +
"</div>" +
"</fieldset>");
}
return null;
}
public string? module_color_sample(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
{
string color = "" + (matches.Groups[2] ?? matches.Groups[3]);
return ("<span class=\"wmd-color-sample\" style=\"background-color:" + color + "\" title=\"" + color + "\">" +
"<span data-sample=\"" + color + "\"></span>" +
"<span class=\"color\">" + color + "</span>" +
"</span>");
}
return null;
}
public string? module_presentation_links(Match matches, int language = WMarkDown.HTML, string? path = null)
{
if ((language & WMarkDown.HTML) != 0)
{
List<WMarkDown.LinkPresententationModel> items = new List<LinkPresententationModel>();
int j = -1;
string html_avatars = "";
string html_list = "";
foreach (string line in WMarkDown.re_new_lines.Split("" + matches.Groups[1]))
{
bool has_spaces = WMarkDown.re_start_with_white_spaces.Match(line) != null;
string data = line.Trim();
if (data == "")
continue;
if (has_spaces)
{
if (j == -1)
continue;
if (data[0] == '*')
{
items[j].avatars.Add(data.Substring(1));
if (data.Contains(".k3y.pw/"))
items[j].avatars.Add(data.Substring(1).Replace(".k3y.pw/", ".local/"));
}
else
items[j].links.Add(data);
}
else
{
j++;
items.Add(new LinkPresententationModel(line));
}
}
for(int i = 0, l = items.Count; i < l; i++)
{
string avatars_html = "";
string links_html = "";
foreach (string avatar in items[i].avatars)
avatars_html += "<a href=\"" + avatar + "\" target=\"_blank\" class=\"wmd-favicon\" style=\"background-image:" + (
"url('" + WMarkDown.re_domain.Match(avatar).Groups[0] + "/favicon.ico')" +
(avatar.Contains(".k3y.pw/") ? ",url('" + WMarkDown.re_domain.Match(avatar.Replace(".k3y.pw/", ".local/")).Groups[0] + "/favicon.ico')" : "")
) + ";\"></a>";
foreach (string link in items[i].links)
links_html += "<li class=\"link\"><<a href=\"" + link + "\" target=\"_blank\" title=\"" + link + "\">" + link + "</a></li>";
html_avatars += ("<li title=\"" + items[i].title + "\" data-i=\"" + i + "\" data-links=\"" + items[i].links.Count + "\">" +
(items[i].links.Count != 0 ? "<a href=\"" + items[i].links[0] + "\" target=\"_blank\">" +
WMarkDown.build_html_image(items[i].avatars) +
"</a>" : WMarkDown.build_html_image(items[i].avatars)) +
avatars_html +
"</li>");
html_list += ("<li class=\"name\">" +
"<span>" + items[i].title + "</span>" +
"<ul class=\"links\">" + links_html + "</ul>" +
"</li>");
}
return ("<div class=\"wmd-presentation-links\">" +
"<ul class=\"wmd-avatars\">" + html_avatars + "</ul>" +
"<ul class=\"wmd-list\">" + html_list + "</ul>" +
"</div>");
}
return null;
}
public static string remove_default_tabulations(string data)
{
int spaces = data.Length;
foreach(string line in WMarkDown.re_new_lines.Split(data))
{
if (line == "")
continue;
int white_spaces = ("" + WMarkDown.re_started_white_spaces.Match(line).Groups[0]).Length;
if (white_spaces < spaces)
spaces = white_spaces;
}
return WMarkDown.re_lines.Replace(data, (Match matches) => ("" + matches.Groups[0]).Substring(spaces));
}
private string build(string data, int language, string? path)
{
return ("<div class=\"wmd wmarkdown\" data-dictionary-processed=\"false\" data-menu-processed=\"false\">" +
this.analyse(WMarkDown.remove_default_tabulations(data), language, WMarkDown.RAW, path) +
"<div class=\"wmd-process-and-loaded\"></div>" +
"</div>");
}
public WMarkDown.ProcessResults process(string data, int language = WMarkDown.HTML, string? path = null)
{
string results = "";
Dictionary<string, string> variables = new Dictionary<string, string>();
Match options = WMarkDown.re_options.Match(data);
if(options != null)
{
string options_data = "" + options.Groups[3];
while (true)
{
Match option = WMarkDown.re_option.Match(options_data);
if (option == null)
break;
variables[("" + option.Groups[1]).Trim()] = ("" + option.Groups[2]).Trim();
options_data = options_data.Substring(option.Index);
}
data = data.Substring(0, options.Index) + data.Substring(options.Index + options.Length);
}
while (true)
{
Match matches = WMarkDown.re_block_mark.Match(data);
if(matches == null)
{
results += data;
break;
}
string mark = "" + matches.Groups[1];
Regex re_close = mark != "" ? new Regex(@"^\s*" + mark, RegexOptions.Multiline) : WMarkDown.re_block_html;
results += data.Substring(0, matches.Index);
data = data.Substring(matches.Index + matches.Length);
Match close_matches = re_close.Match(data);
if(close_matches != null)
{
results += this.build(data.Substring(0, close_matches.Index), language, path);
data = data.Substring(close_matches.Index + close_matches.Length);
}
else
{
results += this.build(data, language, path);
break;
}
}
return new WMarkDown.ProcessResults(results, variables);
}
public string analyse(string data, int language = WMarkDown.HTML, int mode = WMarkDown.RAW, string? path = null)
{
string response = "";
string[] keys = this.modules.Keys.ToArray<string>();
int l = keys.Length;
Dictionary<string, WMarkDown.Item> items = new Dictionary<string, WMarkDown.Item>();
for (int i = 0; i < l; i++)
items[keys[i]] = new WMarkDown.Item();
while (true)
{
string? selected = null;
l = data.Length;
foreach(KeyValuePair<string, WMarkDown.Item> block in items)
{
string key = block.Key;
WMarkDown.Item item = block.Value;
if (!item.exists)
continue;
if(item.from < 0)
{
if((item.matches = this.modules[key].pattern.Match(data)) != null)
item.length = (item.from = item.matches.Index) + item.matches.Length;
else
{
item.exists = false;
continue;
}
}
if (item.from < l)
{
l = item.from;
selected = key;
}
}
if(selected == null)
{
response += data;
break;
}
MethodInfo? method = this.GetType().GetMethod("module_" + (selected ?? ""));
int to = items[selected].from + items[selected].length;
if (method != null)
{
string fragment = data.Substring(items[selected].from, items[selected].length);
response += data.Substring(0, items[selected].from) + method.Invoke(this, [items[selected].matches, language, path]);
}
else
response += data.Substring(0, to);
foreach (WMarkDown.Item item in items.Values)
if (item.exists)
item.from -= to;
}
return response;
}
}
}