namespace string; class markdown{ ctor( extensions,maxNesting=16,htmlRenderFlags=0,useCallbacks){ if( extensions === null ){ extensions = 8/*_MD_MKDEXT_AUTOLINK*/ | 4/*_MD_MKDEXT_FENCED_CODE*/ | 2/*_MD_MKDEXT_TABLES*/ | 1/*_MD_MKDEXT_NO_INTRA_EMPHASIS*/ | 0x40/*_MD_MKDEXT_SPACE_HEADERS*/ | 0x10/*_MD_MKDEXT_STRIKETHROUGH*/ | 0x100/*_MD_MKDEXT_LAX_SPACING*/ } this._callbacks = sd_callbacks() ; this._options = html_renderopt(); sdhtml_renderer(this._callbacks, this._options,htmlRenderFlags); if( useCallbacks){ for(name,func in useCallbacks){ this._callbacks[name] = ..raw.tocdecl(func,sd_callbacks_proto[name],useCallbacks); } } this._callback_c = ..raw.buffer(this._callbacks); this._options_c = ..raw.buffer(this._options); var hMarkdown = sd_markdown_new(extensions,maxNesting,this._callback_c ,this._options_c ); if(!hMarkdown)return null,"sd_markdown_new failed!"; ..table.add_gc(this,"free"); }; setRenderFlags = function(flags=0, disabled){ var opt = ..raw.convert(this._options_c,html_renderopt()); if(disabled) opt.flags = opt.flags & ~flags; else opt.flags = opt.flags | flags; ..raw.copy(this._options_c,opt); }; setTaskCheckboxEnabled = function(enabled){ this.setRenderFlags(0x400/*_MD_HTML_TASK_ENABLED*/,!enabled); }; render = function(str){ str = tostring(str); var ob = buffer(64); sd_markdown_render(ob, str, #str, hMarkdown); var str = tostring(ob) ; ob.release(); return str; }; renderCode = function(code,lang){ return this.render( this.codeBlock(code,lang) ); }; codeBlock = function(code,lang){ var tag = "```" while(..string.indexOf(code,tag)){ tag++="```" } return tag ++ (lang||"")+ '\r\n'+code+'\r\n'+tag; }; renderFile = function(path){ var buf = ..string.loadBuffer(path); if(buf){ var ob = buffer(64); sd_markdown_render(ob, buf, #buf, hMarkdown); var str = tostring(ob) ; ob.release(); return str; } }; free = function(){ if( hMarkdown ){ sd_markdown_free( hMarkdown ); hMarkdown = null; } } } namespace markdown{ var dll = ..raw.loadDll($"~/lib/string/markdown/.res/sundown.dll","sundown.dll","cdecl") sd_markdown_new = dll.api("sd_markdown_new","pointer(INT extensions,INT maxNesting,POINTER callbacks,POINTER opaque)" ) sd_markdown_render = dll.api("sd_markdown_render","void(POINTER ob,pointer document,INT doc_size,POINTER md)" ) sd_markdown_free = dll.api("sd_markdown_free","void(POINTER md)" ) sdhtml_renderer = dll.api("sdhtml_renderer","INT(struct &callbacks,struct &options,INT render_flags)" ) sdhtml_smartypants = dll.api("sdhtml_smartypants","INT(POINTER ob,POINTER text,INT size)" ) class buffer{ ctor( size = 1024 ){ var hBuffer; if( type(size) == type.pointer){ hBuffer = size; } else{ hBuffer = bufnew(size) ..table.add_gc(this,"release"); } }; grow = function( size = 64 ){ return bufgrow(hBuffer, size ) == 0; } release = function(){ if(hBuffer){ bufrelease(hBuffer) hBuffer = null; } } put = function(s,len){ if(!len)len=#s; bufput( hBuffer,s,len ); } printf = function(f,...){ var s = ..string.format(f,... ) bufput( hBuffer,s,#s ) } data = function(){ return bufdata(hBuffer); } size = function(){ return bufsize(hBuffer); } totring = function(){ return bufcstr(hBuffer); } topointer = function(){ return hBuffer; } @_meta; } namespace buffer{ _meta = { _topointer = function(){ return owner.topointer(); } _tostring = function(){ return owner.totring(); } } bufnew = dll.api("bufnew","pointer(INT size)" ) bufgrow = dll.api("bufgrow","int(POINTER buf,INT size)" ) bufrelease = dll.api("bufrelease","void(POINTER buf)" ) bufcstr = dll.api("bufcstr","string(POINTER buf)" ) bufsize = dll.api("bufsize","INT(POINTER buf)" ) bufdata = dll.api("bufdata","pointer(POINTER buf)" ) bufput = dll.api("bufput","INT(POINTER buf,pointer,INT size)" ) } class html_renderopt { stuct toc_data = { int header_count; int current_level; int level_offset; }; INT flags; pointer link_attributes; /* extra callbacks */ }; class sd_callbacks { pointer blockcode ; pointer blockquote; pointer blockhtml; pointer header; pointer hrule; pointer list; pointer listitem; pointer paragraph; pointer table; pointer table_row; pointer table_cell; pointer utolink; pointer codespan; pointer double_emphasis; pointer emphasis; pointer image; pointer linebreak; pointer link; pointer raw_html_tag; pointer triple_emphasis; pointer strikethrough; pointer superscript; pointer entity; pointer normal_text; pointer doc_header; pointer doc_footer; }; sd_callbacks_proto = { blockcode = "void(pointer ob, pointer text, pointer lang, pointer opaque)"; blockquote = "void(pointer ob, pointer text, pointer opaque)"; blockhtml = "void(pointer ob,pointer text, pointer opaque)"; header = "void(pointer ob, pointer text, int level, pointer opaque)"; hrule = "void(pointer ob, pointer opaque)"; list = "void(pointer ob, pointer text, int flags, pointer opaque)"; listitem = "void(pointer ob, pointer text, int flags, pointer opaque)"; paragraph = "void(pointer ob, pointer text, pointer opaque)"; table = "void(pointer ob, pointer header, pointer body, pointer opaque)"; table_row = "void(pointer ob, pointer text, pointer opaque)"; table_cell = "void(pointer ob, pointer text, int flags, pointer opaque)"; autolink = "int(pointer ob, pointer link,int type, pointer opaque)"; codespan = "int(pointer ob, pointer text, pointer opaque)"; double_emphasis = "int(pointer ob, pointer text, pointer opaque)"; emphasis = "int(pointer ob, pointer text, pointer opaque)"; image = "int(pointer ob, pointer link, pointer title, pointer alt, pointer opaque)"; linebreak = "int(pointer ob, pointer opaque)"; link = "int(pointer ob, pointer link, pointer title, pointer content, pointer opaque)"; raw_html_tag = "int(pointer ob, pointer tag, pointer opaque)"; triple_emphasis = "int(pointer ob, pointer text, pointer opaque)"; strikethrough = "int(pointer ob, pointer text, pointer opaque)"; superscript = "int(pointer ob, pointer text, pointer opaque)"; entity = "void(pointer ob, pointer entity, pointer opaque)"; normal_text = "void(pointer ob, pointer text, pointer opaque)"; doc_header = "void(pointer ob, pointer opaque)"; doc_footer = "void(pointer ob, pointer opaque)"; } } /**details(说明) string.markdown(Sundown) 解析器默认规则: - 列表解析默认使用宽松规则。 无论一级列表还是二级列表(无论类型是否相同),都不要求前面有或没有空行。 - 标题的开始标记 `#` 号后面必须有空格。 - 强调语法使用严格模式,**星号内则不能有空格**,但前面必须有空格。 - 默认启用删除线扩展,示例: ~~这里显示删除线~~ 。 - 默认启用表格扩展。 - 默认启用围栏代码块(Fenced Code Blocks)扩展。 多行围栏代码块支持嵌套,可使用 3 个以上的反引号,要点: * 首尾反引号数目要配对。 * 首尾反引号都必须是单独一行。 * 开始的反引号标记后面可以写语言名称,尾部反引号标记后面不能有其他非空白字符。 - 默认支持可选列表(checklist)扩展。 可选列表(checklist)除了兼容只读的任务列表格式,也可以设为可选状态,并支持自动识别与转换字符序号。 方便用于 AI 生成试题(答案可用 details,summary 标签折叠显示。 HTML 渲染选项指定 `0x400/*_MD_HTML_TASK_ENABLED*/` 则复选框显示为启用状态。 也可以调用 setTaskCheckboxEnabled 方法设置复选框是否显示为启用状态,默认显示为禁用状态。 - 支持字母排序列表。 * 如果列表项列表项以 `+ `、`- `、`* ` 开始, 而列表内容以“大写字母 + 圆点 + 空格”的大写字母序号开始则转换为字母排序列表。 * 如果同时指定了复选框,复选框标记必须在字母序号之前。 示例: ``` - A. 列表项 1 - B. 列表项 2 - [ ] A. 选项一 - [ ] B. 选项二 ``` - 可识别并跳过 Front Matter 。 end details**/ /**LICENSE() string.markdown 调用的 sundown 由 aardio( https://aardio.com) 基于 https://github.com/vmg/sundown 做了大量改进以支持现代化 Markdown 流行风格,并修正渲染后各种页面错乱的问题。 aardio 用户可在遵循 aardio 用户协议与 aardio 开源许可证相关条款、 以及 sundown 原始开源项目相关条款的基础上将此修改版 sundown 自由使用于 aardio 程序开发, 但是严禁将本组件的任何部分用于非 aardio 开发的程序(不得使用除 aardio 以外的编程语言调用此组件的任何部分)。 禁止基于其他任何目的单独分发由 aardio 提供的 sundown 组件的任何部分。 aardio 保留对 sundown 修改代码的所有权利并保留所有解释权。 END LICENSE**/ /**intellisense() string.markdown(extensions,maxNesting,htmlRenderFlags) = 创建 MARKDOWN 解析器,所有参数可选。\n- 参数 @extensions 用 _MD_MKDEXT_ 前缀常量组合自定义需要启用的扩展。参数 @maxNesting 指定最大嵌套级别,默认为 16,一般不必修改。\n- 参数 @htmlRenderFlags 指定 HTML 渲染选项,如果指定 0x400/*_MD_HTML_TASK_ENABLED*/ 则任务列表中的复选框显示为启用状态。 string.markdown(extensions,maxNesting,htmlRenderFlags,useCallbacks) = @.markdown(8,,,{\n blockcode = function(ob, text, lang, opaque){ \n ob = string.markdown.buffer(ob);\n text = string.markdown.buffer(text);\n ob.put( tostring(text) )\n }; \n} ); string.markdown() = !string_markdown. !string_markdown.render(.(markdownText) = 解析参数 @markdownText 指定的 Markdown 文本并返回 HTML。\n自动调用 tostring 函数将参数 @markdownText 转换为字符串。 !string_markdown.renderFile(.(markdownFilePath) = 解析参数 @markdownFilePath 指定的 Markdown 文件并返回 HTML !string_markdown.codeBlock(.(code,lang) = 将 @code 参数指定的代码首尾加上三连反引号代码块标记。\n如果代码已经包含三连反引号,则会重复首尾三连反引号直到没有冲突。\n可选用 lang 参数指定编程语言名称 !string_markdown.renderCode(.(code,lang) = \n将 @cdode 参数指定的编程代码置入 Markkdown 围栏代码块中,\n然后转换并返回为 HTML 代码,自动处理嵌套的 Markkdown 代码块标记。\n可选用 lang 参数指定编程语言名称 !string_markdown.setTaskCheckboxEnabled(__) = 任务列表中显示的复选项是否显示为启用状态。\n参数 @1 指定是否启用,默认显示为禁用状态。 !string_markdown.setRenderFlags(.(flags,disabled) = 设置 HTML 渲染选项。\n- 参数 @1 指定一个或多个(按位或) _MD_HTML_ 前缀的选项数值。\n- 参数 @2 为 true 则禁用指定的选项,否则启用。 !string_markdown.free() = 释放解析器对象,\n该函数可在对象回收时自动调用 string.markdown.buffer(.(缓冲区初始大小) = 创建缓冲区,参数可选 string.markdown.buffer() = !string_markdown_buf. !string_markdown_buf.grow(.(增加大小) = 增加缓冲区大小 !string_markdown_buf.put(.(写入数据,长度) = 写入数据到缓冲区,长度为可选参数 !string_markdown_buf.printf(.("%s",其他格式化参数) = 写放格式化字符串,\n格式化语法与 string.format相同 !string_markdown_buf.data() = 返回缓冲区指针 !string_markdown_buf.size() = 返回缓冲区数据大小 !string_markdown_buf.totring() = 返回缓冲区文本 _MD_HTML_SKIP_HTML=@1/*_MD_HTML_SKIP_HTML*/ _MD_HTML_SKIP_STYLE=@2/*_MD_HTML_SKIP_STYLE*/ _MD_HTML_SKIP_IMAGES=@4/*_MD_HTML_SKIP_IMAGES*/ _MD_HTML_SKIP_LINKS=@8/*_MD_HTML_SKIP_LINKS*/ _MD_HTML_EXPAND_TABS=@0x10/*_MD_HTML_EXPAND_TABS*/ _MD_HTML_SAFELINK=@0x20/*_MD_HTML_SAFELINK*/ _MD_HTML_TOC=@0x40/*_MD_HTML_TOC*/ _MD_HTML_HARD_WRAP=@0x80/*_MD_HTML_HARD_WRAP*/ _MD_HTML_USE_XHTML=@0x100/*_MD_HTML_USE_XHTML*/ _MD_HTML_ESCAPE=@0x200/*_MD_HTML_ESCAPE*/ _MD_HTML_TAG_NONE=@0/*_MD_HTML_TAG_NONE*/ _MD_HTML_TAG_OPEN=@1/*_MD_HTML_TAG_OPEN*/ _MD_HTML_TAG_CLOSE=@2/*_MD_HTML_TAG_CLOSE*/ _MD_HTML_TASK_ENABLED=@0x400/*_MD_HTML_TASK_ENABLED*/ _MD_MKDA_NOT_AUTOLINK=@0/*_MD_MKDA_NOT_AUTOLINK*/ _MD_MKDA_NORMAL=@1/*_MD_MKDA_NORMAL*/ _MD_MKDA_EMAIL=@2/*_MD_MKDA_EMAIL*/ _MD_MKD_TABLE_ALIGN_L=@1/*_MD_MKD_TABLE_ALIGN_L*/ _MD_MKD_TABLE_ALIGN_R=@2/*_MD_MKD_TABLE_ALIGN_R*/ _MD_MKD_TABLE_ALIGN_CENTER=@3/*_MD_MKD_TABLE_ALIGN_CENTER*/ _MD_MKD_TABLE_ALIGNMASK=@3/*_MD_MKD_TABLE_ALIGNMASK*/ _MD_MKD_TABLE_HEADER=@4/*_MD_MKD_TABLE_HEADER*/ _MD_MKDEXT_NO_INTRA_EMPHASIS=@1/*_MD_MKDEXT_NO_INTRA_EMPHASIS*/ _MD_MKDEXT_TABLES=@2/*_MD_MKDEXT_TABLES*/ _MD_MKDEXT_FENCED_CODE=@4/*_MD_MKDEXT_FENCED_CODE*/ _MD_MKDEXT_AUTOLINK=@8/*_MD_MKDEXT_AUTOLINK*/ _MD_MKDEXT_STRIKETHROUGH=@0x10/*_MD_MKDEXT_STRIKETHROUGH*/ _MD_MKDEXT_SPACE_HEADERS=@0x40/*_MD_MKDEXT_SPACE_HEADERS*/ _MD_MKDEXT_SUPERSCRIPT=@0x80/*_MD_MKDEXT_SUPERSCRIPT*/ _MD_MKDEXT_LAX_SPACING=@0x100/*_MD_MKDEXT_LAX_SPACING*/ end intellisense**/