bool code_is_space(char ch) { return(ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); } bool code_is_digit(char ch) { return(ch >= '0' && ch <= '9'); } bool code_is_alpha(char ch) { return((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')); } bool code_is_ident_start(char ch) { return(code_is_alpha(ch) || ch == '_'); } bool code_is_ident_char(char ch) { return(code_is_ident_start(ch) || code_is_digit(ch)); } bool markup_name_char(char ch) { return(code_is_ident_char(ch) || ch == '-' || ch == ':' || ch == '@'); } bool code_is_punct(char ch) { return(ch == '{' || ch == '}' || ch == '[' || ch == ']' || ch == '(' || ch == ')' || ch == ',' || ch == ';'); } bool code_is_operator(char ch) { return(ch == '=' || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' || ch == '!' || ch == '<' || ch == '>' || ch == '&' || ch == '|' || ch == '.' || ch == ':' || ch == '?' || ch == '^'); } bool code_has_prefix(String src, u64 i, String prefix) { if(i + prefix.length() > src.length()) return(false); return(substr(src, i, prefix.length()) == prefix); } String code_wrap(String cls, String text) { if(text == "") return(""); return("" + html_escape(text) + ""); } String uce_markup_open_token() { return("<" ">"); } String uce_markup_close_token() { return(""); } String uce_code_open_token() { return("<" "?"); } String uce_code_expr_token() { return("<" "?="); } String uce_code_raw_token() { return("<" "?:"); } String uce_code_close_token() { return("?" ">"); } bool cpp_keyword(String word) { String lower = to_lower(word); return( word == "RENDER" || word == "COMPONENT" || word == "WS" || lower == "if" || lower == "else" || lower == "for" || lower == "while" || lower == "return" || lower == "const" || lower == "auto" || lower == "void" || lower == "bool" || lower == "true" || lower == "false" ); } bool cpp_type(String word) { return( word == "String" || word == "DValue" || word == "Request" || word == "StringList" || word == "StringMap" || word == "u64" || word == "u32" || word == "s64" || word == "f64" ); } bool cpp_builtin_call(String word) { return( word == "component" || word == "component_render" || word == "component_exists" || word == "component_resolve" || word == "markdown_to_ast" || word == "markdown_to_html" || word == "json_decode" || word == "json_encode" || word == "time_format_utc" || word == "first" || word == "contains" || word == "ws_send" || word == "ws_send_to" || word == "ws_message" || word == "ws_connection_id" ); } bool cpp_context_field(String word) { return( word == "get" || word == "post" || word == "session" || word == "call" || word == "connection" || word == "params" || word == "cookies" || word == "header" || word == "cfg" ); } bool nginx_keyword(String word) { return( word == "location" || word == "include" || word == "fastcgi_param" || word == "fastcgi_pass" || word == "proxy_pass" || word == "proxy_set_header" || word == "proxy_http_version" || word == "error_page" || word == "if" || word == "return" || word == "root" || word == "index" || word == "server" || word == "listen" || word == "server_name" || word == "map" ); } String highlight_cpp_fragment(String code) { String out; for(u64 i = 0; i < code.length(); ) { if(code_has_prefix(code, i, "//")) { u64 start = i; while(i < code.length() && code[i] != '\n') i += 1; out += code_wrap("comment", substr(code, start, i - start)); continue; } if(code_has_prefix(code, i, "/*")) { u64 start = i; i += 2; while(i < code.length() && !code_has_prefix(code, i, "*/")) i += 1; if(code_has_prefix(code, i, "*/")) i += 2; out += code_wrap("comment", substr(code, start, i - start)); continue; } char ch = code[i]; if(ch == '"' || ch == '\'' || ch == '`') { char quote = ch; u64 start = i; i += 1; while(i < code.length()) { if(code[i] == '\\' && i + 1 < code.length()) { i += 2; continue; } if(code[i] == quote) { i += 1; break; } i += 1; } out += code_wrap("string", substr(code, start, i - start)); continue; } if(code_is_space(ch)) { out += substr(code, i, 1); i += 1; continue; } if(code_is_digit(ch)) { u64 start = i; i += 1; while(i < code.length()) { char next = code[i]; if(code_is_digit(next) || next == '.' || next == 'x' || next == 'X' || next == '_' || (next >= 'a' && next <= 'f') || (next >= 'A' && next <= 'F')) i += 1; else break; } out += code_wrap("number", substr(code, start, i - start)); continue; } if(code_is_ident_start(ch)) { u64 start = i; i += 1; while(i < code.length() && code_is_ident_char(code[i])) i += 1; String word = substr(code, start, i - start); u64 j = i; while(j < code.length() && (code[j] == ' ' || code[j] == '\t')) j += 1; if(cpp_keyword(word)) out += code_wrap("keyword", word); else if(cpp_type(word)) out += code_wrap("type", word); else if(cpp_context_field(word)) out += code_wrap("field", word); else if(word == "context" || word == "props" || word == "payload" || word == "ws") out += code_wrap("variable", word); else if(cpp_builtin_call(word)) out += code_wrap("builtin", word); else if(j < code.length() && code[j] == '(') out += code_wrap("call", word); else out += code_wrap("ident", word); continue; } if(code_is_punct(ch)) { out += code_wrap("punct", substr(code, i, 1)); i += 1; continue; } if(code_is_operator(ch)) { out += code_wrap("operator", substr(code, i, 1)); i += 1; continue; } out += html_escape(substr(code, i, 1)); i += 1; } return(out); } String highlight_markup_tag(String tag) { String out; u64 i = 0; if(code_has_prefix(tag, i, " name_start) out += code_wrap("markup-tag", substr(tag, name_start, i - name_start)); while(i < tag.length()) { if(code_is_space(tag[i])) { out += substr(tag, i, 1); i += 1; continue; } if(code_has_prefix(tag, i, "/>")) { out += code_wrap("delimiter", "/>" ); i += 2; break; } if(code_has_prefix(tag, i, ">")) { out += code_wrap("delimiter", ">" ); i += 1; break; } u64 attr_start = i; while(i < tag.length() && markup_name_char(tag[i])) i += 1; if(i > attr_start) out += code_wrap("markup-attr", substr(tag, attr_start, i - attr_start)); while(i < tag.length() && code_is_space(tag[i])) { out += substr(tag, i, 1); i += 1; } if(i < tag.length() && tag[i] == '=') { out += code_wrap("operator", "="); i += 1; while(i < tag.length() && code_is_space(tag[i])) { out += substr(tag, i, 1); i += 1; } if(i < tag.length() && (tag[i] == '"' || tag[i] == '\'')) { char quote = tag[i]; u64 value_start = i; i += 1; while(i < tag.length() && tag[i] != quote) i += 1; if(i < tag.length()) i += 1; out += code_wrap("string", substr(tag, value_start, i - value_start)); } else { u64 value_start = i; while(i < tag.length() && !code_is_space(tag[i]) && tag[i] != '>') i += 1; out += code_wrap("string", substr(tag, value_start, i - value_start)); } } } return(out); } String highlight_uce_code(String code) { String out; bool in_markup = false; String markup_open = uce_markup_open_token(); String markup_close = uce_markup_close_token(); String code_open = uce_code_open_token(); String code_expr = uce_code_expr_token(); String code_raw = uce_code_raw_token(); String code_close = uce_code_close_token(); for(u64 i = 0; i < code.length(); ) { if(!in_markup) { s64 next_markup = strpos(code, markup_open, i); if(next_markup < 0) { out += highlight_cpp_fragment(substr(code, i)); break; } if((u64)next_markup > i) out += highlight_cpp_fragment(substr(code, i, (u64)next_markup - i)); out += code_wrap("delimiter", markup_open); i = (u64)next_markup + 2; in_markup = true; continue; } if(code_has_prefix(code, i, markup_close)) { out += code_wrap("delimiter", markup_close); i += 3; in_markup = false; continue; } if(code_has_prefix(code, i, code_expr) || code_has_prefix(code, i, code_raw) || code_has_prefix(code, i, code_open)) { String opener = code_has_prefix(code, i, code_expr) ? code_expr : (code_has_prefix(code, i, code_raw) ? code_raw : code_open); out += code_wrap("delimiter", opener); i += opener.length(); u64 island_start = i; while(i < code.length() && !code_has_prefix(code, i, code_close)) i += 1; out += highlight_cpp_fragment(substr(code, island_start, i - island_start)); if(code_has_prefix(code, i, code_close)) { out += code_wrap("delimiter", code_close); i += 2; } continue; } if(code_has_prefix(code, i, "<")) { u64 tag_start = i; char quote = 0; i += 1; while(i < code.length()) { if(quote != 0) { if(code[i] == quote) quote = 0; i += 1; continue; } if(code[i] == '"' || code[i] == '\'') { quote = code[i]; i += 1; continue; } if(code[i] == '>') { i += 1; break; } i += 1; } out += highlight_markup_tag(substr(code, tag_start, i - tag_start)); continue; } u64 text_start = i; while(i < code.length() && code[i] != '<') i += 1; out += code_wrap("markup-text", substr(code, text_start, i - text_start)); } return(out); } String highlight_nginx_code(String code) { String out; for(u64 i = 0; i < code.length(); ) { if(code[i] == '#') { u64 start = i; while(i < code.length() && code[i] != '\n') i += 1; out += code_wrap("comment", substr(code, start, i - start)); continue; } if(code[i] == '"' || code[i] == '\'') { char quote = code[i]; u64 start = i; i += 1; while(i < code.length() && code[i] != quote) i += 1; if(i < code.length()) i += 1; out += code_wrap("string", substr(code, start, i - start)); continue; } if(code_is_space(code[i])) { out += substr(code, i, 1); i += 1; continue; } if(code[i] == '$' || code[i] == '@') { u64 start = i; i += 1; while(i < code.length() && markup_name_char(code[i])) i += 1; out += code_wrap("variable", substr(code, start, i - start)); continue; } if(code_is_digit(code[i])) { u64 start = i; i += 1; while(i < code.length() && (code_is_digit(code[i]) || code[i] == '.')) i += 1; out += code_wrap("number", substr(code, start, i - start)); continue; } if(markup_name_char(code[i])) { u64 start = i; i += 1; while(i < code.length() && markup_name_char(code[i])) i += 1; String word = substr(code, start, i - start); if(nginx_keyword(word)) out += code_wrap("keyword", word); else out += code_wrap("ident", word); continue; } if(code_is_punct(code[i])) { out += code_wrap("punct", substr(code, i, 1)); i += 1; continue; } if(code_is_operator(code[i])) { out += code_wrap("operator", substr(code, i, 1)); i += 1; continue; } out += html_escape(substr(code, i, 1)); i += 1; } return(out); } String highlight_code(String code) { if(contains(code, "fastcgi_pass") || contains(code, "proxy_pass")) return(highlight_nginx_code(code)); return(highlight_uce_code(code)); } String highlight_code(String code, String language) { if(language == "nginx") return(highlight_nginx_code(code)); if(language == "uce") return(highlight_uce_code(code)); return(highlight_code(code)); } String code_language_label(String language) { if(language == "nginx") return("nginx"); return("uce"); } COMPONENT(Request& props) { String eyebrow = props.props["eyebrow"].to_string(); String title = props.props["title"].to_string(); String summary = props.props["summary"].to_string(); String code = props.props["code"].to_string(); String note = props.props["note"].to_string(); String language = first(props.props["language"].to_string(), "uce"); <>

}