diff --git a/lib/highlight-github.css b/lib/highlight-github.css deleted file mode 100644 index 275239a..0000000 --- a/lib/highlight-github.css +++ /dev/null @@ -1,10 +0,0 @@ -pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*! - Theme: GitHub - Description: Light theme as seen on github.com - Author: github.com - Maintainer: @Hirse - Updated: 2021-05-15 - - Outdated base version: https://github.com/primer/github-syntax-light - Current colors taken from GitHub's CSS -*/.hljs{color:#24292e;background:#fff}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#005cc5}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-code,.hljs-comment,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{color:#005cc5;font-weight:700}.hljs-bullet{color:#735c0f}.hljs-emphasis{color:#24292e;font-style:italic}.hljs-strong{color:#24292e;font-weight:700}.hljs-addition{color:#22863a;background-color:#f0fff4}.hljs-deletion{color:#b31d28;background-color:#ffeef0} \ No newline at end of file diff --git a/lib/highlight.min.js b/lib/highlight.min.js deleted file mode 100644 index 5d699ae..0000000 --- a/lib/highlight.min.js +++ /dev/null @@ -1,1213 +0,0 @@ -/*! - Highlight.js v11.9.0 (git: f47103d4f1) - (c) 2006-2023 undefined and other contributors - License: BSD-3-Clause - */ -var hljs=function(){"use strict";function e(n){ -return n instanceof Map?n.clear=n.delete=n.set=()=>{ -throw Error("map is read-only")}:n instanceof Set&&(n.add=n.clear=n.delete=()=>{ -throw Error("set is read-only") -}),Object.freeze(n),Object.getOwnPropertyNames(n).forEach((t=>{ -const a=n[t],i=typeof a;"object"!==i&&"function"!==i||Object.isFrozen(a)||e(a) -})),n}class n{constructor(e){ -void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1} -ignoreMatch(){this.isMatchIgnored=!0}}function t(e){ -return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'") -}function a(e,...n){const t=Object.create(null);for(const n in e)t[n]=e[n] -;return n.forEach((e=>{for(const n in e)t[n]=e[n]})),t}const i=e=>!!e.scope -;class r{constructor(e,n){ -this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){ -this.buffer+=t(e)}openNode(e){if(!i(e))return;const n=((e,{prefix:n})=>{ -if(e.startsWith("language:"))return e.replace("language:","language-") -;if(e.includes(".")){const t=e.split(".") -;return[`${n}${t.shift()}`,...t.map(((e,n)=>`${e}${"_".repeat(n+1)}`))].join(" ") -}return`${n}${e}`})(e.scope,{prefix:this.classPrefix});this.span(n)} -closeNode(e){i(e)&&(this.buffer+="")}value(){return this.buffer}span(e){ -this.buffer+=``}}const s=(e={})=>{const n={children:[]} -;return Object.assign(n,e),n};class o{constructor(){ -this.rootNode=s(),this.stack=[this.rootNode]}get top(){ -return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){ -this.top.children.push(e)}openNode(e){const n=s({scope:e}) -;this.add(n),this.stack.push(n)}closeNode(){ -if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){ -for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)} -walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){ -return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n), -n.children.forEach((n=>this._walk(e,n))),e.closeNode(n)),e}static _collapse(e){ -"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{ -o._collapse(e)})))}}class l extends o{constructor(e){super(),this.options=e} -addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){ -this.closeNode()}__addSublanguage(e,n){const t=e.root -;n&&(t.scope="language:"+n),this.add(t)}toHTML(){ -return new r(this,this.options).value()}finalize(){ -return this.closeAllNodes(),!0}}function c(e){ -return e?"string"==typeof e?e:e.source:null}function d(e){return b("(?=",e,")")} -function g(e){return b("(?:",e,")*")}function u(e){return b("(?:",e,")?")} -function b(...e){return e.map((e=>c(e))).join("")}function m(...e){const n=(e=>{ -const n=e[e.length-1] -;return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{} -})(e);return"("+(n.capture?"":"?:")+e.map((e=>c(e))).join("|")+")"} -function p(e){return RegExp(e.toString()+"|").exec("").length-1} -const _=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./ -;function h(e,{joinWith:n}){let t=0;return e.map((e=>{t+=1;const n=t -;let a=c(e),i="";for(;a.length>0;){const e=_.exec(a);if(!e){i+=a;break} -i+=a.substring(0,e.index), -a=a.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?i+="\\"+(Number(e[1])+n):(i+=e[0], -"("===e[0]&&t++)}return i})).map((e=>`(${e})`)).join(n)} -const f="[a-zA-Z]\\w*",E="[a-zA-Z_]\\w*",y="\\b\\d+(\\.\\d+)?",N="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",w="\\b(0b[01]+)",v={ -begin:"\\\\[\\s\\S]",relevance:0},O={scope:"string",begin:"'",end:"'", -illegal:"\\n",contains:[v]},k={scope:"string",begin:'"',end:'"',illegal:"\\n", -contains:[v]},x=(e,n,t={})=>{const i=a({scope:"comment",begin:e,end:n, -contains:[]},t);i.contains.push({scope:"doctag", -begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)", -end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0}) -;const r=m("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/) -;return i.contains.push({begin:b(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),i -},M=x("//","$"),S=x("/\\*","\\*/"),A=x("#","$");var C=Object.freeze({ -__proto__:null,APOS_STRING_MODE:O,BACKSLASH_ESCAPE:v,BINARY_NUMBER_MODE:{ -scope:"number",begin:w,relevance:0},BINARY_NUMBER_RE:w,COMMENT:x, -C_BLOCK_COMMENT_MODE:S,C_LINE_COMMENT_MODE:M,C_NUMBER_MODE:{scope:"number", -begin:N,relevance:0},C_NUMBER_RE:N,END_SAME_AS_BEGIN:e=>Object.assign(e,{ -"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{ -n.data._beginMatch!==e[1]&&n.ignoreMatch()}}),HASH_COMMENT_MODE:A,IDENT_RE:f, -MATCH_NOTHING_RE:/\b\B/,METHOD_GUARD:{begin:"\\.\\s*"+E,relevance:0}, -NUMBER_MODE:{scope:"number",begin:y,relevance:0},NUMBER_RE:y, -PHRASAL_WORDS_MODE:{ -begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ -},QUOTE_STRING_MODE:k,REGEXP_MODE:{scope:"regexp",begin:/\/(?=[^/\n]*\/)/, -end:/\/[gimuy]*/,contains:[v,{begin:/\[/,end:/\]/,relevance:0,contains:[v]}]}, -RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~", -SHEBANG:(e={})=>{const n=/^#![ ]*\// -;return e.binary&&(e.begin=b(n,/.*\b/,e.binary,/\b.*/)),a({scope:"meta",begin:n, -end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)}, -TITLE_MODE:{scope:"title",begin:f,relevance:0},UNDERSCORE_IDENT_RE:E, -UNDERSCORE_TITLE_MODE:{scope:"title",begin:E,relevance:0}});function T(e,n){ -"."===e.input[e.index-1]&&n.ignoreMatch()}function R(e,n){ -void 0!==e.className&&(e.scope=e.className,delete e.className)}function D(e,n){ -n&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)", -e.__beforeBegin=T,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords, -void 0===e.relevance&&(e.relevance=0))}function I(e,n){ -Array.isArray(e.illegal)&&(e.illegal=m(...e.illegal))}function L(e,n){ -if(e.match){ -if(e.begin||e.end)throw Error("begin & end are not supported with match") -;e.begin=e.match,delete e.match}}function B(e,n){ -void 0===e.relevance&&(e.relevance=1)}const $=(e,n)=>{if(!e.beforeMatch)return -;if(e.starts)throw Error("beforeMatch cannot be used with starts") -;const t=Object.assign({},e);Object.keys(e).forEach((n=>{delete e[n] -})),e.keywords=t.keywords,e.begin=b(t.beforeMatch,d(t.begin)),e.starts={ -relevance:0,contains:[Object.assign(t,{endsParent:!0})] -},e.relevance=0,delete t.beforeMatch -},z=["of","and","for","in","not","or","if","then","parent","list","value"],F="keyword" -;function U(e,n,t=F){const a=Object.create(null) -;return"string"==typeof e?i(t,e.split(" ")):Array.isArray(e)?i(t,e):Object.keys(e).forEach((t=>{ -Object.assign(a,U(e[t],n,t))})),a;function i(e,t){ -n&&(t=t.map((e=>e.toLowerCase()))),t.forEach((n=>{const t=n.split("|") -;a[t[0]]=[e,j(t[0],t[1])]}))}}function j(e,n){ -return n?Number(n):(e=>z.includes(e.toLowerCase()))(e)?0:1}const P={},K=e=>{ -console.error(e)},H=(e,...n)=>{console.log("WARN: "+e,...n)},q=(e,n)=>{ -P[`${e}/${n}`]||(console.log(`Deprecated as of ${e}. ${n}`),P[`${e}/${n}`]=!0) -},G=Error();function Z(e,n,{key:t}){let a=0;const i=e[t],r={},s={} -;for(let e=1;e<=n.length;e++)s[e+a]=i[e],r[e+a]=!0,a+=p(n[e-1]) -;e[t]=s,e[t]._emit=r,e[t]._multi=!0}function W(e){(e=>{ -e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope, -delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={ -_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope -}),(e=>{if(Array.isArray(e.begin)){ -if(e.skip||e.excludeBegin||e.returnBegin)throw K("skip, excludeBegin, returnBegin not compatible with beginScope: {}"), -G -;if("object"!=typeof e.beginScope||null===e.beginScope)throw K("beginScope must be object"), -G;Z(e,e.begin,{key:"beginScope"}),e.begin=h(e.begin,{joinWith:""})}})(e),(e=>{ -if(Array.isArray(e.end)){ -if(e.skip||e.excludeEnd||e.returnEnd)throw K("skip, excludeEnd, returnEnd not compatible with endScope: {}"), -G -;if("object"!=typeof e.endScope||null===e.endScope)throw K("endScope must be object"), -G;Z(e,e.end,{key:"endScope"}),e.end=h(e.end,{joinWith:""})}})(e)}function Q(e){ -function n(n,t){ -return RegExp(c(n),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(t?"g":"")) -}class t{constructor(){ -this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0} -addRule(e,n){ -n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]), -this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null) -;const e=this.regexes.map((e=>e[1]));this.matcherRe=n(h(e,{joinWith:"|" -}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex -;const n=this.matcherRe.exec(e);if(!n)return null -;const t=n.findIndex(((e,n)=>n>0&&void 0!==e)),a=this.matchIndexes[t] -;return n.splice(0,t),Object.assign(n,a)}}class i{constructor(){ -this.rules=[],this.multiRegexes=[], -this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){ -if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t -;return this.rules.slice(e).forEach((([e,t])=>n.addRule(e,t))), -n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){ -return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){ -this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){ -const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex -;let t=n.exec(e) -;if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{ -const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)} -return t&&(this.regexIndex+=t.position+1, -this.regexIndex===this.count&&this.considerAll()),t}} -if(e.compilerExtensions||(e.compilerExtensions=[]), -e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.") -;return e.classNameAliases=a(e.classNameAliases||{}),function t(r,s){const o=r -;if(r.isCompiled)return o -;[R,L,W,$].forEach((e=>e(r,s))),e.compilerExtensions.forEach((e=>e(r,s))), -r.__beforeBegin=null,[D,I,B].forEach((e=>e(r,s))),r.isCompiled=!0;let l=null -;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords), -l=r.keywords.$pattern, -delete r.keywords.$pattern),l=l||/\w+/,r.keywords&&(r.keywords=U(r.keywords,e.case_insensitive)), -o.keywordPatternRe=n(l,!0), -s&&(r.begin||(r.begin=/\B|\b/),o.beginRe=n(o.begin),r.end||r.endsWithParent||(r.end=/\B|\b/), -r.end&&(o.endRe=n(o.end)), -o.terminatorEnd=c(o.end)||"",r.endsWithParent&&s.terminatorEnd&&(o.terminatorEnd+=(r.end?"|":"")+s.terminatorEnd)), -r.illegal&&(o.illegalRe=n(r.illegal)), -r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((n=>a(e,{ -variants:null},n)))),e.cachedVariants?e.cachedVariants:X(e)?a(e,{ -starts:e.starts?a(e.starts):null -}):Object.isFrozen(e)?a(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{t(e,o) -})),r.starts&&t(r.starts,s),o.matcher=(e=>{const n=new i -;return e.contains.forEach((e=>n.addRule(e.begin,{rule:e,type:"begin" -}))),e.terminatorEnd&&n.addRule(e.terminatorEnd,{type:"end" -}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n})(o),o}(e)}function X(e){ -return!!e&&(e.endsWithParent||X(e.starts))}class V extends Error{ -constructor(e,n){super(e),this.name="HTMLInjectionError",this.html=n}} -const J=t,Y=a,ee=Symbol("nomatch"),ne=t=>{ -const a=Object.create(null),i=Object.create(null),r=[];let s=!0 -;const o="Could not find the language '{}', did you forget to load/include a language module?",c={ -disableAutodetect:!0,name:"Plain text",contains:[]};let p={ -ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i, -languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-", -cssSelector:"pre code",languages:null,__emitter:l};function _(e){ -return p.noHighlightRe.test(e)}function h(e,n,t){let a="",i="" -;"object"==typeof n?(a=e, -t=n.ignoreIllegals,i=n.language):(q("10.7.0","highlight(lang, code, ...args) has been deprecated."), -q("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"), -i=e,a=n),void 0===t&&(t=!0);const r={code:a,language:i};x("before:highlight",r) -;const s=r.result?r.result:f(r.language,r.code,t) -;return s.code=r.code,x("after:highlight",s),s}function f(e,t,i,r){ -const l=Object.create(null);function c(){if(!x.keywords)return void S.addText(A) -;let e=0;x.keywordPatternRe.lastIndex=0;let n=x.keywordPatternRe.exec(A),t="" -;for(;n;){t+=A.substring(e,n.index) -;const i=w.case_insensitive?n[0].toLowerCase():n[0],r=(a=i,x.keywords[a]);if(r){ -const[e,a]=r -;if(S.addText(t),t="",l[i]=(l[i]||0)+1,l[i]<=7&&(C+=a),e.startsWith("_"))t+=n[0];else{ -const t=w.classNameAliases[e]||e;g(n[0],t)}}else t+=n[0] -;e=x.keywordPatternRe.lastIndex,n=x.keywordPatternRe.exec(A)}var a -;t+=A.substring(e),S.addText(t)}function d(){null!=x.subLanguage?(()=>{ -if(""===A)return;let e=null;if("string"==typeof x.subLanguage){ -if(!a[x.subLanguage])return void S.addText(A) -;e=f(x.subLanguage,A,!0,M[x.subLanguage]),M[x.subLanguage]=e._top -}else e=E(A,x.subLanguage.length?x.subLanguage:null) -;x.relevance>0&&(C+=e.relevance),S.__addSublanguage(e._emitter,e.language) -})():c(),A=""}function g(e,n){ -""!==e&&(S.startScope(n),S.addText(e),S.endScope())}function u(e,n){let t=1 -;const a=n.length-1;for(;t<=a;){if(!e._emit[t]){t++;continue} -const a=w.classNameAliases[e[t]]||e[t],i=n[t];a?g(i,a):(A=i,c(),A=""),t++}} -function b(e,n){ -return e.scope&&"string"==typeof e.scope&&S.openNode(w.classNameAliases[e.scope]||e.scope), -e.beginScope&&(e.beginScope._wrap?(g(A,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap), -A=""):e.beginScope._multi&&(u(e.beginScope,n),A="")),x=Object.create(e,{parent:{ -value:x}}),x}function m(e,t,a){let i=((e,n)=>{const t=e&&e.exec(n) -;return t&&0===t.index})(e.endRe,a);if(i){if(e["on:end"]){const a=new n(e) -;e["on:end"](t,a),a.isMatchIgnored&&(i=!1)}if(i){ -for(;e.endsParent&&e.parent;)e=e.parent;return e}} -if(e.endsWithParent)return m(e.parent,t,a)}function _(e){ -return 0===x.matcher.regexIndex?(A+=e[0],1):(D=!0,0)}function h(e){ -const n=e[0],a=t.substring(e.index),i=m(x,e,a);if(!i)return ee;const r=x -;x.endScope&&x.endScope._wrap?(d(), -g(n,x.endScope._wrap)):x.endScope&&x.endScope._multi?(d(), -u(x.endScope,e)):r.skip?A+=n:(r.returnEnd||r.excludeEnd||(A+=n), -d(),r.excludeEnd&&(A=n));do{ -x.scope&&S.closeNode(),x.skip||x.subLanguage||(C+=x.relevance),x=x.parent -}while(x!==i.parent);return i.starts&&b(i.starts,e),r.returnEnd?0:n.length} -let y={};function N(a,r){const o=r&&r[0];if(A+=a,null==o)return d(),0 -;if("begin"===y.type&&"end"===r.type&&y.index===r.index&&""===o){ -if(A+=t.slice(r.index,r.index+1),!s){const n=Error(`0 width match regex (${e})`) -;throw n.languageName=e,n.badRule=y.rule,n}return 1} -if(y=r,"begin"===r.type)return(e=>{ -const t=e[0],a=e.rule,i=new n(a),r=[a.__beforeBegin,a["on:begin"]] -;for(const n of r)if(n&&(n(e,i),i.isMatchIgnored))return _(t) -;return a.skip?A+=t:(a.excludeBegin&&(A+=t), -d(),a.returnBegin||a.excludeBegin||(A=t)),b(a,e),a.returnBegin?0:t.length})(r) -;if("illegal"===r.type&&!i){ -const e=Error('Illegal lexeme "'+o+'" for mode "'+(x.scope||"")+'"') -;throw e.mode=x,e}if("end"===r.type){const e=h(r);if(e!==ee)return e} -if("illegal"===r.type&&""===o)return 1 -;if(R>1e5&&R>3*r.index)throw Error("potential infinite loop, way more iterations than matches") -;return A+=o,o.length}const w=v(e) -;if(!w)throw K(o.replace("{}",e)),Error('Unknown language: "'+e+'"') -;const O=Q(w);let k="",x=r||O;const M={},S=new p.__emitter(p);(()=>{const e=[] -;for(let n=x;n!==w;n=n.parent)n.scope&&e.unshift(n.scope) -;e.forEach((e=>S.openNode(e)))})();let A="",C=0,T=0,R=0,D=!1;try{ -if(w.__emitTokens)w.__emitTokens(t,S);else{for(x.matcher.considerAll();;){ -R++,D?D=!1:x.matcher.considerAll(),x.matcher.lastIndex=T -;const e=x.matcher.exec(t);if(!e)break;const n=N(t.substring(T,e.index),e) -;T=e.index+n}N(t.substring(T))}return S.finalize(),k=S.toHTML(),{language:e, -value:k,relevance:C,illegal:!1,_emitter:S,_top:x}}catch(n){ -if(n.message&&n.message.includes("Illegal"))return{language:e,value:J(t), -illegal:!0,relevance:0,_illegalBy:{message:n.message,index:T, -context:t.slice(T-100,T+100),mode:n.mode,resultSoFar:k},_emitter:S};if(s)return{ -language:e,value:J(t),illegal:!1,relevance:0,errorRaised:n,_emitter:S,_top:x} -;throw n}}function E(e,n){n=n||p.languages||Object.keys(a);const t=(e=>{ -const n={value:J(e),illegal:!1,relevance:0,_top:c,_emitter:new p.__emitter(p)} -;return n._emitter.addText(e),n})(e),i=n.filter(v).filter(k).map((n=>f(n,e,!1))) -;i.unshift(t);const r=i.sort(((e,n)=>{ -if(e.relevance!==n.relevance)return n.relevance-e.relevance -;if(e.language&&n.language){if(v(e.language).supersetOf===n.language)return 1 -;if(v(n.language).supersetOf===e.language)return-1}return 0})),[s,o]=r,l=s -;return l.secondBest=o,l}function y(e){let n=null;const t=(e=>{ -let n=e.className+" ";n+=e.parentNode?e.parentNode.className:"" -;const t=p.languageDetectRe.exec(n);if(t){const n=v(t[1]) -;return n||(H(o.replace("{}",t[1])), -H("Falling back to no-highlight mode for this block.",e)),n?t[1]:"no-highlight"} -return n.split(/\s+/).find((e=>_(e)||v(e)))})(e);if(_(t))return -;if(x("before:highlightElement",{el:e,language:t -}),e.dataset.highlighted)return void console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",e) -;if(e.children.length>0&&(p.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."), -console.warn("https://github.com/highlightjs/highlight.js/wiki/security"), -console.warn("The element with unescaped HTML:"), -console.warn(e)),p.throwUnescapedHTML))throw new V("One of your code blocks includes unescaped HTML.",e.innerHTML) -;n=e;const a=n.textContent,r=t?h(a,{language:t,ignoreIllegals:!0}):E(a) -;e.innerHTML=r.value,e.dataset.highlighted="yes",((e,n,t)=>{const a=n&&i[n]||t -;e.classList.add("hljs"),e.classList.add("language-"+a) -})(e,t,r.language),e.result={language:r.language,re:r.relevance, -relevance:r.relevance},r.secondBest&&(e.secondBest={ -language:r.secondBest.language,relevance:r.secondBest.relevance -}),x("after:highlightElement",{el:e,result:r,text:a})}let N=!1;function w(){ -"loading"!==document.readyState?document.querySelectorAll(p.cssSelector).forEach(y):N=!0 -}function v(e){return e=(e||"").toLowerCase(),a[e]||a[i[e]]} -function O(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach((e=>{ -i[e.toLowerCase()]=n}))}function k(e){const n=v(e) -;return n&&!n.disableAutodetect}function x(e,n){const t=e;r.forEach((e=>{ -e[t]&&e[t](n)}))} -"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{ -N&&w()}),!1),Object.assign(t,{highlight:h,highlightAuto:E,highlightAll:w, -highlightElement:y, -highlightBlock:e=>(q("10.7.0","highlightBlock will be removed entirely in v12.0"), -q("10.7.0","Please use highlightElement now."),y(e)),configure:e=>{p=Y(p,e)}, -initHighlighting:()=>{ -w(),q("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")}, -initHighlightingOnLoad:()=>{ -w(),q("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.") -},registerLanguage:(e,n)=>{let i=null;try{i=n(t)}catch(n){ -if(K("Language definition for '{}' could not be registered.".replace("{}",e)), -!s)throw n;K(n),i=c} -i.name||(i.name=e),a[e]=i,i.rawDefinition=n.bind(null,t),i.aliases&&O(i.aliases,{ -languageName:e})},unregisterLanguage:e=>{delete a[e] -;for(const n of Object.keys(i))i[n]===e&&delete i[n]}, -listLanguages:()=>Object.keys(a),getLanguage:v,registerAliases:O, -autoDetection:k,inherit:Y,addPlugin:e=>{(e=>{ -e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=n=>{ -e["before:highlightBlock"](Object.assign({block:n.el},n)) -}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=n=>{ -e["after:highlightBlock"](Object.assign({block:n.el},n))})})(e),r.push(e)}, -removePlugin:e=>{const n=r.indexOf(e);-1!==n&&r.splice(n,1)}}),t.debugMode=()=>{ -s=!1},t.safeMode=()=>{s=!0},t.versionString="11.9.0",t.regex={concat:b, -lookahead:d,either:m,optional:u,anyNumberOfTimes:g} -;for(const n in C)"object"==typeof C[n]&&e(C[n]);return Object.assign(t,C),t -},te=ne({});te.newInstance=()=>ne({});var ae=te;const ie=e=>({IMPORTANT:{ -scope:"meta",begin:"!important"},BLOCK_COMMENT:e.C_BLOCK_COMMENT_MODE,HEXCOLOR:{ -scope:"number",begin:/#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/}, -FUNCTION_DISPATCH:{className:"built_in",begin:/[\w-]+(?=\()/}, -ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$", -contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{ -scope:"number", -begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?", -relevance:0},CSS_VARIABLE:{className:"attr",begin:/--[A-Za-z_][A-Za-z0-9_-]*/} -}),re=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],se=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],oe=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],le=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],ce=["align-content","align-items","align-self","all","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","block-size","border","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","clip-path","clip-rule","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","content","content-visibility","counter-increment","counter-reset","cue","cue-after","cue-before","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","flow","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-synthesis","font-variant","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","gap","glyph-orientation-vertical","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inline-size","isolation","justify-content","left","letter-spacing","line-break","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-block","margin-block-end","margin-block-start","margin-bottom","margin-inline","margin-inline-end","margin-inline-start","margin-left","margin-right","margin-top","marks","mask","mask-border","mask-border-mode","mask-border-outset","mask-border-repeat","mask-border-slice","mask-border-source","mask-border-width","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-block","padding-block-end","padding-block-start","padding-bottom","padding-inline","padding-inline-end","padding-inline-start","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","pause","pause-after","pause-before","perspective","perspective-origin","pointer-events","position","quotes","resize","rest","rest-after","rest-before","right","row-gap","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-stop","scroll-snap-type","scrollbar-color","scrollbar-gutter","scrollbar-width","shape-image-threshold","shape-margin","shape-outside","speak","speak-as","src","tab-size","table-layout","text-align","text-align-all","text-align-last","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-indent","text-justify","text-orientation","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-box","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","z-index"].reverse(),de=oe.concat(le) -;var ge="[0-9](_*[0-9])*",ue=`\\.(${ge})`,be="[0-9a-fA-F](_*[0-9a-fA-F])*",me={ -className:"number",variants:[{ -begin:`(\\b(${ge})((${ue})|\\.)?|(${ue}))[eE][+-]?(${ge})[fFdD]?\\b`},{ -begin:`\\b(${ge})((${ue})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{ -begin:`(${ue})[fFdD]?\\b`},{begin:`\\b(${ge})[fFdD]\\b`},{ -begin:`\\b0[xX]((${be})\\.?|(${be})?\\.(${be}))[pP][+-]?(${ge})[fFdD]?\\b`},{ -begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${be})[lL]?\\b`},{ -begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}], -relevance:0};function pe(e,n,t){return-1===t?"":e.replace(n,(a=>pe(e,n,t-1)))} -const _e="[A-Za-z$_][0-9A-Za-z$_]*",he=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],fe=["true","false","null","undefined","NaN","Infinity"],Ee=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],ye=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],Ne=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],we=["arguments","this","super","console","window","document","localStorage","sessionStorage","module","global"],ve=[].concat(Ne,Ee,ye) -;function Oe(e){const n=e.regex,t=_e,a={begin:/<[A-Za-z0-9\\._:-]+/, -end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{ -const t=e[0].length+e.index,a=e.input[t] -;if("<"===a||","===a)return void n.ignoreMatch();let i -;">"===a&&(((e,{after:n})=>{const t="",M={ -match:[/const|var|let/,/\s+/,t,/\s*/,/=\s*/,/(async\s*)?/,n.lookahead(x)], -keywords:"async",className:{1:"keyword",3:"title.function"},contains:[f]} -;return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:i,exports:{ -PARAMS_CONTAINS:h,CLASS_REFERENCE:y},illegal:/#(?![$_A-z])/, -contains:[e.SHEBANG({label:"shebang",binary:"node",relevance:5}),{ -label:"use_strict",className:"meta",relevance:10, -begin:/^\s*['"]use (strict|asm)['"]/ -},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,d,g,u,b,m,{match:/\$\d+/},l,y,{ -className:"attr",begin:t+n.lookahead(":"),relevance:0},M,{ -begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", -keywords:"return throw case",relevance:0,contains:[m,e.REGEXP_MODE,{ -className:"function",begin:x,returnBegin:!0,end:"\\s*=>",contains:[{ -className:"params",variants:[{begin:e.UNDERSCORE_IDENT_RE,relevance:0},{ -className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0, -excludeEnd:!0,keywords:i,contains:h}]}]},{begin:/,/,relevance:0},{match:/\s+/, -relevance:0},{variants:[{begin:"<>",end:""},{ -match:/<[A-Za-z0-9\\._:-]+\s*\/>/},{begin:a.begin, -"on:begin":a.isTrulyOpeningTag,end:a.end}],subLanguage:"xml",contains:[{ -begin:a.begin,end:a.end,skip:!0,contains:["self"]}]}]},N,{ -beginKeywords:"while if switch catch for"},{ -begin:"\\b(?!function)"+e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{", -returnBegin:!0,label:"func.def",contains:[f,e.inherit(e.TITLE_MODE,{begin:t, -className:"title.function"})]},{match:/\.\.\./,relevance:0},O,{match:"\\$"+t, -relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"}, -contains:[f]},w,{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, -className:"variable.constant"},E,k,{match:/\$[(.]/}]}} -const ke=e=>b(/\b/,e,/\w$/.test(e)?/\b/:/\B/),xe=["Protocol","Type"].map(ke),Me=["init","self"].map(ke),Se=["Any","Self"],Ae=["actor","any","associatedtype","async","await",/as\?/,/as!/,"as","borrowing","break","case","catch","class","consume","consuming","continue","convenience","copy","default","defer","deinit","didSet","distributed","do","dynamic","each","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","isolated","nonisolated","lazy","let","macro","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","switch","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],Ce=["false","nil","true"],Te=["assignment","associativity","higherThan","left","lowerThan","none","right"],Re=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warning"],De=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],Ie=m(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),Le=m(Ie,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),Be=b(Ie,Le,"*"),$e=m(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),ze=m($e,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),Fe=b($e,ze,"*"),Ue=b(/[A-Z]/,ze,"*"),je=["attached","autoclosure",b(/convention\(/,m("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","freestanding","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",b(/objc\(/,Fe,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","Sendable","testable","UIApplicationMain","unchecked","unknown","usableFromInline","warn_unqualified_access"],Pe=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"] -;var Ke=Object.freeze({__proto__:null,grmr_bash:e=>{const n=e.regex,t={},a={ -begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]} -;Object.assign(t,{className:"variable",variants:[{ -begin:n.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},a]});const i={ -className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},r={ -begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/, -end:/(\w+)/,className:"string"})]}},s={className:"string",begin:/"/,end:/"/, -contains:[e.BACKSLASH_ESCAPE,t,i]};i.contains.push(s);const o={begin:/\$?\(\(/, -end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t] -},l=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10 -}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0, -contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{ -name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z][a-z0-9._-]+\b/, -keyword:["if","then","else","elif","fi","for","while","until","in","do","done","case","esac","function","select"], -literal:["true","false"], -built_in:["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset","alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","type","typeset","ulimit","unalias","set","shopt","autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp","chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"] -},contains:[l,e.SHEBANG(),c,o,e.HASH_COMMENT_MODE,r,{match:/(\/[a-z._-]+)+/},s,{ -match:/\\"/},{className:"string",begin:/'/,end:/'/},{match:/\\'/},t]}}, -grmr_c:e=>{const n=e.regex,t=e.COMMENT("//","$",{contains:[{begin:/\\\n/}] -}),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={ -className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{ -match:/\batomic_[a-z]{3,6}\b/}]},o={className:"string",variants:[{ -begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ -begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", -end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ -begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ -className:"number",variants:[{begin:"\\b(0b[01']+)"},{ -begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" -},{ -begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" -}],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ -keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" -},contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{ -className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={ -className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0 -},g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={ -keyword:["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"], -type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal128","const","static","complex","bool","imaginary"], -literal:"true false NULL", -built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr" -},b=[c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],m={variants:[{begin:/=/,end:/;/},{ -begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], -keywords:u,contains:b.concat([{begin:/\(/,end:/\)/,keywords:u, -contains:b.concat(["self"]),relevance:0}]),relevance:0},p={ -begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, -keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{ -begin:g,returnBegin:!0,contains:[e.inherit(d,{className:"title.function"})], -relevance:0},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/, -keywords:u,relevance:0,contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/, -end:/\)/,keywords:u,relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s] -}]},s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C",aliases:["h"],keywords:u, -disableAutodetect:!0,illegal:"=]/,contains:[{ -beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:c, -strings:o,keywords:u}}},grmr_cpp:e=>{const n=e.regex,t=e.COMMENT("//","$",{ -contains:[{begin:/\\\n/}] -}),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="(?!struct)("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={ -className:"type",begin:"\\b[a-z\\d_]*_t\\b"},o={className:"string",variants:[{ -begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ -begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", -end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ -begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ -className:"number",variants:[{begin:"\\b(0b[01']+)"},{ -begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" -},{ -begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" -}],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ -keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" -},contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{ -className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={ -className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0 -},g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={ -type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"], -keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"], -literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"], -_type_hints:["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"] -},b={className:"function.dispatch",relevance:0,keywords:{ -_hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"] -}, -begin:n.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!switch)/,/(?!while)/,e.IDENT_RE,n.lookahead(/(<[^<>]+>|)\s*\(/)) -},m=[b,c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],p={variants:[{begin:/=/,end:/;/},{ -begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], -keywords:u,contains:m.concat([{begin:/\(/,end:/\)/,keywords:u, -contains:m.concat(["self"]),relevance:0}]),relevance:0},_={className:"function", -begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, -keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{ -begin:g,returnBegin:!0,contains:[d],relevance:0},{begin:/::/,relevance:0},{ -begin:/:/,endsWithParent:!0,contains:[o,l]},{relevance:0,match:/,/},{ -className:"params",begin:/\(/,end:/\)/,keywords:u,relevance:0, -contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/,end:/\)/,keywords:u, -relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s]}] -},s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C++", -aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:u,illegal:"",keywords:u,contains:["self",s]},{begin:e.IDENT_RE+"::",keywords:u},{ -match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/], -className:{1:"keyword",3:"title.class"}}])}},grmr_csharp:e=>{const n={ -keyword:["abstract","as","base","break","case","catch","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","scoped","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value|0","var","when","where","with","yield"]), -built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"], -literal:["default","false","null","true"]},t=e.inherit(e.TITLE_MODE,{ -begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{ -begin:"\\b(0b[01']+)"},{ -begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{ -begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" -}],relevance:0},i={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}] -},r=e.inherit(i,{illegal:/\n/}),s={className:"subst",begin:/\{/,end:/\}/, -keywords:n},o=e.inherit(s,{illegal:/\n/}),l={className:"string",begin:/\$"/, -end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/ -},e.BACKSLASH_ESCAPE,o]},c={className:"string",begin:/\$@"/,end:'"',contains:[{ -begin:/\{\{/},{begin:/\}\}/},{begin:'""'},s]},d=e.inherit(c,{illegal:/\n/, -contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},o]}) -;s.contains=[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE], -o.contains=[d,l,r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{ -illegal:/\n/})];const g={variants:[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] -},u={begin:"<",end:">",contains:[{beginKeywords:"in out"},t] -},b=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",m={ -begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"], -keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0, -contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{ -begin:"\x3c!--|--\x3e"},{begin:""}]}] -}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#", -end:"$",keywords:{ -keyword:"if else elif endif define undef warning error line region endregion pragma checksum" -}},g,a,{beginKeywords:"class interface",relevance:0,end:/[{;=]/, -illegal:/[^\s:,]/,contains:[{beginKeywords:"where class" -},t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace", -relevance:0,end:/[{;=]/,illegal:/[^\s:]/, -contains:[t,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ -beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/, -contains:[t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta", -begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{ -className:"string",begin:/"/,end:/"/}]},{ -beginKeywords:"new return throw await else",relevance:0},{className:"function", -begin:"("+b+"\\s+)+"+e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, -end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{ -beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial", -relevance:0},{begin:e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, -contains:[e.TITLE_MODE,u],relevance:0},{match:/\(\)/},{className:"params", -begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0, -contains:[g,a,e.C_BLOCK_COMMENT_MODE] -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},m]}},grmr_css:e=>{ -const n=e.regex,t=ie(e),a=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{ -name:"CSS",case_insensitive:!0,illegal:/[=|'\$]/,keywords:{ -keyframePosition:"from to"},classNameAliases:{keyframePosition:"selector-tag"}, -contains:[t.BLOCK_COMMENT,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/ -},t.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0 -},{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0 -},t.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{ -begin:":("+oe.join("|")+")"},{begin:":(:)?("+le.join("|")+")"}] -},t.CSS_VARIABLE,{className:"attribute",begin:"\\b("+ce.join("|")+")\\b"},{ -begin:/:/,end:/[;}{]/, -contains:[t.BLOCK_COMMENT,t.HEXCOLOR,t.IMPORTANT,t.CSS_NUMBER_MODE,...a,{ -begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri" -},contains:[...a,{className:"string",begin:/[^)]/,endsWithParent:!0, -excludeEnd:!0}]},t.FUNCTION_DISPATCH]},{begin:n.lookahead(/@/),end:"[{;]", -relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/ -},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{ -$pattern:/[a-z-]+/,keyword:"and or not only",attribute:se.join(" ")},contains:[{ -begin:/[a-z-]+(?=:)/,className:"attribute"},...a,t.CSS_NUMBER_MODE]}]},{ -className:"selector-tag",begin:"\\b("+re.join("|")+")\\b"}]}},grmr_diff:e=>{ -const n=e.regex;return{name:"Diff",aliases:["patch"],contains:[{ -className:"meta",relevance:10, -match:n.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/) -},{className:"comment",variants:[{ -begin:n.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/), -end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{ -className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/, -end:/$/}]}},grmr_go:e=>{const n={ -keyword:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","switch","type","var"], -type:["bool","byte","complex64","complex128","error","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"], -literal:["true","false","iota","nil"], -built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"] -};return{name:"Go",aliases:["golang"],keywords:n,illegal:"{const n=e.regex;return{name:"GraphQL",aliases:["gql"], -case_insensitive:!0,disableAutodetect:!1,keywords:{ -keyword:["query","mutation","subscription","type","input","schema","directive","interface","union","scalar","fragment","enum","on"], -literal:["true","false","null"]}, -contains:[e.HASH_COMMENT_MODE,e.QUOTE_STRING_MODE,e.NUMBER_MODE,{ -scope:"punctuation",match:/[.]{3}/,relevance:0},{scope:"punctuation", -begin:/[\!\(\)\:\=\[\]\{\|\}]{1}/,relevance:0},{scope:"variable",begin:/\$/, -end:/\W/,excludeEnd:!0,relevance:0},{scope:"meta",match:/@\w+/,excludeEnd:!0},{ -scope:"symbol",begin:n.concat(/[_A-Za-z][_0-9A-Za-z]*/,n.lookahead(/\s*:/)), -relevance:0}],illegal:[/[;<']/,/BEGIN/]}},grmr_ini:e=>{const n=e.regex,t={ -className:"number",relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{ -begin:e.NUMBER_RE}]},a=e.COMMENT();a.variants=[{begin:/;/,end:/$/},{begin:/#/, -end:/$/}];const i={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{ -begin:/\$\{(.*?)\}/}]},r={className:"literal", -begin:/\bon|off|true|false|yes|no\b/},s={className:"string", -contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{ -begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}] -},o={begin:/\[/,end:/\]/,contains:[a,r,i,s,t,"self"],relevance:0 -},l=n.either(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{ -name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/, -contains:[a,{className:"section",begin:/\[+/,end:/\]+/},{ -begin:n.concat(l,"(\\s*\\.\\s*",l,")*",n.lookahead(/\s*=\s*[^#\s]/)), -className:"attr",starts:{end:/$/,contains:[a,o,r,i,s,t]}}]}},grmr_java:e=>{ -const n=e.regex,t="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",a=t+pe("(?:<"+t+"~~~(?:\\s*,\\s*"+t+"~~~)*>)?",/~~~/g,2),i={ -keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do","sealed","yield","permits"], -literal:["false","true","null"], -type:["char","boolean","long","float","int","byte","short","double"], -built_in:["super","this"]},r={className:"meta",begin:"@"+t,contains:[{ -begin:/\(/,end:/\)/,contains:["self"]}]},s={className:"params",begin:/\(/, -end:/\)/,keywords:i,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0} -;return{name:"Java",aliases:["jsp"],keywords:i,illegal:/<\/|#/, -contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/, -relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{ -begin:/import java\.[a-z]+\./,keywords:"import",relevance:2 -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/, -className:"string",contains:[e.BACKSLASH_ESCAPE] -},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{ -match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,t],className:{ -1:"keyword",3:"title.class"}},{match:/non-sealed/,scope:"keyword"},{ -begin:[n.concat(/(?!else)/,t),/\s+/,t,/\s+/,/=(?!=)/],className:{1:"type", -3:"variable",5:"operator"}},{begin:[/record/,/\s+/,t],className:{1:"keyword", -3:"title.class"},contains:[s,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ -beginKeywords:"new throw return else",relevance:0},{ -begin:["(?:"+a+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{ -2:"title.function"},keywords:i,contains:[{className:"params",begin:/\(/, -end:/\)/,keywords:i,relevance:0, -contains:[r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,me,e.C_BLOCK_COMMENT_MODE] -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},me,r]}},grmr_javascript:Oe, -grmr_json:e=>{const n=["true","false","null"],t={scope:"literal", -beginKeywords:n.join(" ")};return{name:"JSON",keywords:{literal:n},contains:[{ -className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},{ -match:/[{}[\],:]/,className:"punctuation",relevance:0 -},e.QUOTE_STRING_MODE,t,e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE], -illegal:"\\S"}},grmr_kotlin:e=>{const n={ -keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual", -built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing", -literal:"true false null"},t={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@" -},a={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},i={ -className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string", -variants:[{begin:'"""',end:'"""(?=[^"])',contains:[i,a]},{begin:"'",end:"'", -illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/, -contains:[e.BACKSLASH_ESCAPE,i,a]}]};a.contains.push(r);const s={ -className:"meta", -begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?" -},o={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/, -end:/\)/,contains:[e.inherit(r,{className:"string"}),"self"]}] -},l=me,c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),d={ -variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/, -contains:[]}]},g=d;return g.variants[1].contains=[d],d.variants[1].contains=[g], -{name:"Kotlin",aliases:["kt","kts"],keywords:n, -contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag", -begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword", -begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol", -begin:/@\w+/}]}},t,s,o,{className:"function",beginKeywords:"fun",end:"[(]|$", -returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{ -begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, -contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://, -keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/, -endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/, -endsWithParent:!0,contains:[d,e.C_LINE_COMMENT_MODE,c],relevance:0 -},e.C_LINE_COMMENT_MODE,c,s,o,r,e.C_NUMBER_MODE]},c]},{ -begin:[/class|interface|trait/,/\s+/,e.UNDERSCORE_IDENT_RE],beginScope:{ -3:"title.class"},keywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0, -illegal:"extends implements",contains:[{ -beginKeywords:"public protected internal private constructor" -},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0, -excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,){\s]|$/, -excludeBegin:!0,returnEnd:!0},s,o]},r,{className:"meta",begin:"^#!/usr/bin/env", -end:"$",illegal:"\n"},l]}},grmr_less:e=>{ -const n=ie(e),t=de,a="[\\w-]+",i="("+a+"|@\\{"+a+"\\})",r=[],s=[],o=e=>({ -className:"string",begin:"~?"+e+".*?"+e}),l=(e,n,t)=>({className:e,begin:n, -relevance:t}),c={$pattern:/[a-z-]+/,keyword:"and or not only", -attribute:se.join(" ")},d={begin:"\\(",end:"\\)",contains:s,keywords:c, -relevance:0} -;s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,o("'"),o('"'),n.CSS_NUMBER_MODE,{ -begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]", -excludeEnd:!0} -},n.HEXCOLOR,d,l("variable","@@?"+a,10),l("variable","@\\{"+a+"\\}"),l("built_in","~?`[^`]*?`"),{ -className:"attribute",begin:a+"\\s*:",end:":",returnBegin:!0,excludeEnd:!0 -},n.IMPORTANT,{beginKeywords:"and not"},n.FUNCTION_DISPATCH);const g=s.concat({ -begin:/\{/,end:/\}/,contains:r}),u={beginKeywords:"when",endsWithParent:!0, -contains:[{beginKeywords:"and not"}].concat(s)},b={begin:i+"\\s*:", -returnBegin:!0,end:/[;}]/,relevance:0,contains:[{begin:/-(webkit|moz|ms|o)-/ -},n.CSS_VARIABLE,{className:"attribute",begin:"\\b("+ce.join("|")+")\\b", -end:/(?=:)/,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s}}] -},m={className:"keyword", -begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b", -starts:{end:"[;{}]",keywords:c,returnEnd:!0,contains:s,relevance:0}},p={ -className:"variable",variants:[{begin:"@"+a+"\\s*:",relevance:15},{begin:"@"+a -}],starts:{end:"[;}]",returnEnd:!0,contains:g}},_={variants:[{ -begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:i,end:/\{/}],returnBegin:!0, -returnEnd:!0,illegal:"[<='$\"]",relevance:0, -contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,u,l("keyword","all\\b"),l("variable","@\\{"+a+"\\}"),{ -begin:"\\b("+re.join("|")+")\\b",className:"selector-tag" -},n.CSS_NUMBER_MODE,l("selector-tag",i,0),l("selector-id","#"+i),l("selector-class","\\."+i,0),l("selector-tag","&",0),n.ATTRIBUTE_SELECTOR_MODE,{ -className:"selector-pseudo",begin:":("+oe.join("|")+")"},{ -className:"selector-pseudo",begin:":(:)?("+le.join("|")+")"},{begin:/\(/, -end:/\)/,relevance:0,contains:g},{begin:"!important"},n.FUNCTION_DISPATCH]},h={ -begin:a+":(:)?"+`(${t.join("|")})`,returnBegin:!0,contains:[_]} -;return r.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,m,p,h,b,_,u,n.FUNCTION_DISPATCH), -{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:r}}, -grmr_lua:e=>{const n="\\[=*\\[",t="\\]=*\\]",a={begin:n,end:t,contains:["self"] -},i=[e.COMMENT("--(?!"+n+")","$"),e.COMMENT("--"+n,t,{contains:[a],relevance:10 -})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE, -literal:"true false nil", -keyword:"and break do else elseif end for goto if in local not or repeat return then until while", -built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove" -},contains:i.concat([{className:"function",beginKeywords:"function",end:"\\)", -contains:[e.inherit(e.TITLE_MODE,{ -begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params", -begin:"\\(",endsWithParent:!0,contains:i}].concat(i) -},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string", -begin:n,end:t,contains:[a],relevance:5}])}},grmr_makefile:e=>{const n={ -className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)", -contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%{ -const n={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},t={ -variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{ -begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, -relevance:2},{ -begin:e.regex.concat(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/), -relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{ -begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/ -},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0, -returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)", -excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[", -end:"\\]",excludeBegin:!0,excludeEnd:!0}]},a={className:"strong",contains:[], -variants:[{begin:/_{2}(?!\s)/,end:/_{2}/},{begin:/\*{2}(?!\s)/,end:/\*{2}/}] -},i={className:"emphasis",contains:[],variants:[{begin:/\*(?![*\s])/,end:/\*/},{ -begin:/_(?![_\s])/,end:/_/,relevance:0}]},r=e.inherit(a,{contains:[] -}),s=e.inherit(i,{contains:[]});a.contains.push(s),i.contains.push(r) -;let o=[n,t];return[a,i,r,s].forEach((e=>{e.contains=e.contains.concat(o) -})),o=o.concat(a,i),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{ -className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:o},{ -begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n", -contains:o}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)", -end:"\\s+",excludeEnd:!0},a,i,{className:"quote",begin:"^>\\s+",contains:o, -end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{ -begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{ -begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))", -contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{ -begin:"^[-\\*]{3,}",end:"$"},t,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{ -className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{ -className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}},grmr_objectivec:e=>{ -const n=/[a-zA-Z@][a-zA-Z0-9_]*/,t={$pattern:n, -keyword:["@interface","@class","@protocol","@implementation"]};return{ -name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"], -keywords:{"variable.language":["this","super"],$pattern:n, -keyword:["while","export","sizeof","typedef","const","struct","for","union","volatile","static","mutable","if","do","return","goto","enum","else","break","extern","asm","case","default","register","explicit","typename","switch","continue","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"], -literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"], -built_in:["dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"], -type:["int","float","char","unsigned","signed","short","long","double","wchar_t","unichar","void","bool","BOOL","id|0","_Bool"] -},illegal:"/,end:/$/,illegal:"\\n" -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class", -begin:"("+t.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:t, -contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE, -relevance:0}]}},grmr_perl:e=>{const n=e.regex,t=/[dualxmsipngr]{0,12}/,a={ -$pattern:/[\w.]+/, -keyword:"abs accept alarm and atan2 bind binmode bless break caller chdir chmod chomp chop chown chr chroot close closedir connect continue cos crypt dbmclose dbmopen defined delete die do dump each else elsif endgrent endhostent endnetent endprotoent endpwent endservent eof eval exec exists exit exp fcntl fileno flock for foreach fork format formline getc getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr getnetbyname getnetent getpeername getpgrp getpriority getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid getservbyname getservbyport getservent getsockname getsockopt given glob gmtime goto grep gt hex if index int ioctl join keys kill last lc lcfirst length link listen local localtime log lstat lt ma map mkdir msgctl msgget msgrcv msgsnd my ne next no not oct open opendir or ord our pack package pipe pop pos print printf prototype push q|0 qq quotemeta qw qx rand read readdir readline readlink readpipe recv redo ref rename require reset return reverse rewinddir rindex rmdir say scalar seek seekdir select semctl semget semop send setgrent sethostent setnetent setpgrp setpriority setprotoent setpwent setservent setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep socket socketpair sort splice split sprintf sqrt srand stat state study sub substr symlink syscall sysopen sysread sysseek system syswrite tell telldir tie tied time times tr truncate uc ucfirst umask undef unless unlink unpack unshift untie until use utime values vec wait waitpid wantarray warn when while write x|0 xor y|0" -},i={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:a},r={begin:/->\{/, -end:/\}/},s={variants:[{begin:/\$\d/},{ -begin:n.concat(/[$%@](\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])") -},{begin:/[$%@][^\s\w{]/,relevance:0}] -},o=[e.BACKSLASH_ESCAPE,i,s],l=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],c=(e,a,i="\\1")=>{ -const r="\\1"===i?i:n.concat(i,a) -;return n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,r,/(?:\\.|[^\\\/])*?/,i,t) -},d=(e,a,i)=>n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,i,t),g=[s,e.HASH_COMMENT_MODE,e.COMMENT(/^=\w/,/=cut/,{ -endsWithParent:!0}),r,{className:"string",contains:o,variants:[{ -begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[", -end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{ -begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">", -relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'", -contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`", -contains:[e.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{ -begin:"-?\\w+\\s*=>",relevance:0}]},{className:"number", -begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b", -relevance:0},{ -begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*", -keywords:"split return print reverse grep",relevance:0, -contains:[e.HASH_COMMENT_MODE,{className:"regexp",variants:[{ -begin:c("s|tr|y",n.either(...l,{capture:!0}))},{begin:c("s|tr|y","\\(","\\)")},{ -begin:c("s|tr|y","\\[","\\]")},{begin:c("s|tr|y","\\{","\\}")}],relevance:2},{ -className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{ -begin:d("(?:m|qr)?",/\//,/\//)},{begin:d("m|qr",n.either(...l,{capture:!0 -}),/\1/)},{begin:d("m|qr",/\(/,/\)/)},{begin:d("m|qr",/\[/,/\]/)},{ -begin:d("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub", -end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{ -begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$", -subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}] -}];return i.contains=g,r.contains=g,{name:"Perl",aliases:["pl","pm"],keywords:a, -contains:g}},grmr_php:e=>{ -const n=e.regex,t=/(?![A-Za-z0-9])(?![$])/,a=n.concat(/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/,t),i=n.concat(/(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/,t),r={ -scope:"variable",match:"\\$+"+a},s={scope:"subst",variants:[{begin:/\$\w+/},{ -begin:/\{\$/,end:/\}/}]},o=e.inherit(e.APOS_STRING_MODE,{illegal:null -}),l="[ \t\n]",c={scope:"string",variants:[e.inherit(e.QUOTE_STRING_MODE,{ -illegal:null,contains:e.QUOTE_STRING_MODE.contains.concat(s)}),o,{ -begin:/<<<[ \t]*(?:(\w+)|"(\w+)")\n/,end:/[ \t]*(\w+)\b/, -contains:e.QUOTE_STRING_MODE.contains.concat(s),"on:begin":(e,n)=>{ -n.data._beginMatch=e[1]||e[2]},"on:end":(e,n)=>{ -n.data._beginMatch!==e[1]&&n.ignoreMatch()}},e.END_SAME_AS_BEGIN({ -begin:/<<<[ \t]*'(\w+)'\n/,end:/[ \t]*(\w+)\b/})]},d={scope:"number",variants:[{ -begin:"\\b0[bB][01]+(?:_[01]+)*\\b"},{begin:"\\b0[oO][0-7]+(?:_[0-7]+)*\\b"},{ -begin:"\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b"},{ -begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?" -}],relevance:0 -},g=["false","null","true"],u=["__CLASS__","__DIR__","__FILE__","__FUNCTION__","__COMPILER_HALT_OFFSET__","__LINE__","__METHOD__","__NAMESPACE__","__TRAIT__","die","echo","exit","include","include_once","print","require","require_once","array","abstract","and","as","binary","bool","boolean","break","callable","case","catch","class","clone","const","continue","declare","default","do","double","else","elseif","empty","enddeclare","endfor","endforeach","endif","endswitch","endwhile","enum","eval","extends","final","finally","float","for","foreach","from","global","goto","if","implements","instanceof","insteadof","int","integer","interface","isset","iterable","list","match|0","mixed","new","never","object","or","private","protected","public","readonly","real","return","string","switch","throw","trait","try","unset","use","var","void","while","xor","yield"],b=["Error|0","AppendIterator","ArgumentCountError","ArithmeticError","ArrayIterator","ArrayObject","AssertionError","BadFunctionCallException","BadMethodCallException","CachingIterator","CallbackFilterIterator","CompileError","Countable","DirectoryIterator","DivisionByZeroError","DomainException","EmptyIterator","ErrorException","Exception","FilesystemIterator","FilterIterator","GlobIterator","InfiniteIterator","InvalidArgumentException","IteratorIterator","LengthException","LimitIterator","LogicException","MultipleIterator","NoRewindIterator","OutOfBoundsException","OutOfRangeException","OuterIterator","OverflowException","ParentIterator","ParseError","RangeException","RecursiveArrayIterator","RecursiveCachingIterator","RecursiveCallbackFilterIterator","RecursiveDirectoryIterator","RecursiveFilterIterator","RecursiveIterator","RecursiveIteratorIterator","RecursiveRegexIterator","RecursiveTreeIterator","RegexIterator","RuntimeException","SeekableIterator","SplDoublyLinkedList","SplFileInfo","SplFileObject","SplFixedArray","SplHeap","SplMaxHeap","SplMinHeap","SplObjectStorage","SplObserver","SplPriorityQueue","SplQueue","SplStack","SplSubject","SplTempFileObject","TypeError","UnderflowException","UnexpectedValueException","UnhandledMatchError","ArrayAccess","BackedEnum","Closure","Fiber","Generator","Iterator","IteratorAggregate","Serializable","Stringable","Throwable","Traversable","UnitEnum","WeakReference","WeakMap","Directory","__PHP_Incomplete_Class","parent","php_user_filter","self","static","stdClass"],m={ -keyword:u,literal:(e=>{const n=[];return e.forEach((e=>{ -n.push(e),e.toLowerCase()===e?n.push(e.toUpperCase()):n.push(e.toLowerCase()) -})),n})(g),built_in:b},p=e=>e.map((e=>e.replace(/\|\d+$/,""))),_={variants:[{ -match:[/new/,n.concat(l,"+"),n.concat("(?!",p(b).join("\\b|"),"\\b)"),i],scope:{ -1:"keyword",4:"title.class"}}]},h=n.concat(a,"\\b(?!\\()"),f={variants:[{ -match:[n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{2:"variable.constant" -}},{match:[/::/,/class/],scope:{2:"variable.language"}},{ -match:[i,n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{1:"title.class", -3:"variable.constant"}},{match:[i,n.concat("::",n.lookahead(/(?!class\b)/))], -scope:{1:"title.class"}},{match:[i,/::/,/class/],scope:{1:"title.class", -3:"variable.language"}}]},E={scope:"attr", -match:n.concat(a,n.lookahead(":"),n.lookahead(/(?!::)/))},y={relevance:0, -begin:/\(/,end:/\)/,keywords:m,contains:[E,r,f,e.C_BLOCK_COMMENT_MODE,c,d,_] -},N={relevance:0, -match:[/\b/,n.concat("(?!fn\\b|function\\b|",p(u).join("\\b|"),"|",p(b).join("\\b|"),"\\b)"),a,n.concat(l,"*"),n.lookahead(/(?=\()/)], -scope:{3:"title.function.invoke"},contains:[y]};y.contains.push(N) -;const w=[E,f,e.C_BLOCK_COMMENT_MODE,c,d,_];return{case_insensitive:!1, -keywords:m,contains:[{begin:n.concat(/#\[\s*/,i),beginScope:"meta",end:/]/, -endScope:"meta",keywords:{literal:g,keyword:["new","array"]},contains:[{ -begin:/\[/,end:/]/,keywords:{literal:g,keyword:["new","array"]}, -contains:["self",...w]},...w,{scope:"meta",match:i}] -},e.HASH_COMMENT_MODE,e.COMMENT("//","$"),e.COMMENT("/\\*","\\*/",{contains:[{ -scope:"doctag",match:"@[A-Za-z]+"}]}),{match:/__halt_compiler\(\);/, -keywords:"__halt_compiler",starts:{scope:"comment",end:e.MATCH_NOTHING_RE, -contains:[{match:/\?>/,scope:"meta",endsParent:!0}]}},{scope:"meta",variants:[{ -begin:/<\?php/,relevance:10},{begin:/<\?=/},{begin:/<\?/,relevance:.1},{ -begin:/\?>/}]},{scope:"variable.language",match:/\$this\b/},r,N,f,{ -match:[/const/,/\s/,a],scope:{1:"keyword",3:"variable.constant"}},_,{ -scope:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/, -excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use" -},e.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{scope:"params", -begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:m, -contains:["self",r,f,e.C_BLOCK_COMMENT_MODE,c,d]}]},{scope:"class",variants:[{ -beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait", -illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{ -beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{ -beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/, -contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{scope:"title.class"})]},{ -beginKeywords:"use",relevance:0,end:";",contains:[{ -match:/\b(as|const|function)\b/,scope:"keyword"},e.UNDERSCORE_TITLE_MODE]},c,d]} -},grmr_php_template:e=>({name:"PHP template",subLanguage:"xml",contains:[{ -begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*", -end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0 -},e.inherit(e.APOS_STRING_MODE,{illegal:null,className:null,contains:null, -skip:!0}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null,className:null, -contains:null,skip:!0})]}]}),grmr_plaintext:e=>({name:"Plain text", -aliases:["text","txt"],disableAutodetect:!0}),grmr_python:e=>{ -const n=e.regex,t=/[\p{XID_Start}_]\p{XID_Continue}*/u,a=["and","as","assert","async","await","break","case","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","match","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],i={ -$pattern:/[A-Za-z]\w+|__\w+__/,keyword:a, -built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"], -literal:["__debug__","Ellipsis","False","None","NotImplemented","True"], -type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"] -},r={className:"meta",begin:/^(>>>|\.\.\.) /},s={className:"subst",begin:/\{/, -end:/\}/,keywords:i,illegal:/#/},o={begin:/\{\{/,relevance:0},l={ -className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{ -begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/, -contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ -begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/, -contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ -begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/, -contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/, -end:/"""/,contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([uU]|[rR])'/,end:/'/, -relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{ -begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/, -end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/, -contains:[e.BACKSLASH_ESCAPE,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/, -contains:[e.BACKSLASH_ESCAPE,o,s]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] -},c="[0-9](_?[0-9])*",d=`(\\b(${c}))?\\.(${c})|\\b(${c})\\.`,g="\\b|"+a.join("|"),u={ -className:"number",relevance:0,variants:[{ -begin:`(\\b(${c})|(${d}))[eE][+-]?(${c})[jJ]?(?=${g})`},{begin:`(${d})[jJ]?`},{ -begin:`\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${g})`},{ -begin:`\\b0[bB](_?[01])+[lL]?(?=${g})`},{begin:`\\b0[oO](_?[0-7])+[lL]?(?=${g})` -},{begin:`\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${g})`},{begin:`\\b(${c})[jJ](?=${g})` -}]},b={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:i, -contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},m={ -className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/, -end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:i, -contains:["self",r,u,l,e.HASH_COMMENT_MODE]}]};return s.contains=[l,u,r],{ -name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:i, -illegal:/(<\/|\?)|=>/,contains:[r,u,{begin:/\bself\b/},{beginKeywords:"if", -relevance:0},l,b,e.HASH_COMMENT_MODE,{match:[/\bdef/,/\s+/,t],scope:{ -1:"keyword",3:"title.function"},contains:[m]},{variants:[{ -match:[/\bclass/,/\s+/,t,/\s*/,/\(\s*/,t,/\s*\)/]},{match:[/\bclass/,/\s+/,t]}], -scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{ -className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[u,m,l]}]}}, -grmr_python_repl:e=>({aliases:["pycon"],contains:[{className:"meta.prompt", -starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{ -begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}),grmr_r:e=>{ -const n=e.regex,t=/(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/,a=n.either(/0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/,/0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/,/(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/),i=/[=!<>:]=|\|\||&&|:::?|<-|<<-|->>|->|\|>|[-+*\/?!$&|:<=>@^~]|\*\*/,r=n.either(/[()]/,/[{}]/,/\[\[/,/[[\]]/,/\\/,/,/) -;return{name:"R",keywords:{$pattern:t, -keyword:"function if in break next repeat else for while", -literal:"NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10", -built_in:"LETTERS letters month.abb month.name pi T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum switch tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm" -},contains:[e.COMMENT(/#'/,/$/,{contains:[{scope:"doctag",match:/@examples/, -starts:{end:n.lookahead(n.either(/\n^#'\s*(?=@[a-zA-Z]+)/,/\n^(?!#')/)), -endsParent:!0}},{scope:"doctag",begin:"@param",end:/$/,contains:[{ -scope:"variable",variants:[{match:t},{match:/`(?:\\.|[^`\\])+`/}],endsParent:!0 -}]},{scope:"doctag",match:/@[a-zA-Z]+/},{scope:"keyword",match:/\\[a-zA-Z]+/}] -}),e.HASH_COMMENT_MODE,{scope:"string",contains:[e.BACKSLASH_ESCAPE], -variants:[e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\(/,end:/\)(-*)"/ -}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\{/,end:/\}(-*)"/ -}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\[/,end:/\](-*)"/ -}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\(/,end:/\)(-*)'/ -}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\{/,end:/\}(-*)'/ -}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\[/,end:/\](-*)'/}),{begin:'"',end:'"', -relevance:0},{begin:"'",end:"'",relevance:0}]},{relevance:0,variants:[{scope:{ -1:"operator",2:"number"},match:[i,a]},{scope:{1:"operator",2:"number"}, -match:[/%[^%]*%/,a]},{scope:{1:"punctuation",2:"number"},match:[r,a]},{scope:{ -2:"number"},match:[/[^a-zA-Z0-9._]|^/,a]}]},{scope:{3:"operator"}, -match:[t,/\s+/,/<-/,/\s+/]},{scope:"operator",relevance:0,variants:[{match:i},{ -match:/%[^%]*%/}]},{scope:"punctuation",relevance:0,match:r},{begin:"`",end:"`", -contains:[{begin:/\\./}]}]}},grmr_ruby:e=>{ -const n=e.regex,t="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",a=n.either(/\b([A-Z]+[a-z0-9]+)+/,/\b([A-Z]+[a-z0-9]+)+[A-Z]+/),i=n.concat(a,/(::\w+)*/),r={ -"variable.constant":["__FILE__","__LINE__","__ENCODING__"], -"variable.language":["self","super"], -keyword:["alias","and","begin","BEGIN","break","case","class","defined","do","else","elsif","end","END","ensure","for","if","in","module","next","not","or","redo","require","rescue","retry","return","then","undef","unless","until","when","while","yield","include","extend","prepend","public","private","protected","raise","throw"], -built_in:["proc","lambda","attr_accessor","attr_reader","attr_writer","define_method","private_constant","module_function"], -literal:["true","false","nil"]},s={className:"doctag",begin:"@[A-Za-z]+"},o={ -begin:"#<",end:">"},l=[e.COMMENT("#","$",{contains:[s] -}),e.COMMENT("^=begin","^=end",{contains:[s],relevance:10 -}),e.COMMENT("^__END__",e.MATCH_NOTHING_RE)],c={className:"subst",begin:/#\{/, -end:/\}/,keywords:r},d={className:"string",contains:[e.BACKSLASH_ESCAPE,c], -variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{ -begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{ -begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//, -end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{ -begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{ -begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{ -begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{ -begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{ -begin:n.concat(/<<[-~]?'?/,n.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)), -contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/, -contains:[e.BACKSLASH_ESCAPE,c]})]}]},g="[0-9](_?[0-9])*",u={className:"number", -relevance:0,variants:[{ -begin:`\\b([1-9](_?[0-9])*|0)(\\.(${g}))?([eE][+-]?(${g})|r)?i?\\b`},{ -begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b" -},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{ -begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{ -begin:"\\b0(_?[0-7])+r?i?\\b"}]},b={variants:[{match:/\(\)/},{ -className:"params",begin:/\(/,end:/(?=\))/,excludeBegin:!0,endsParent:!0, -keywords:r}]},m=[d,{variants:[{match:[/class\s+/,i,/\s+<\s+/,i]},{ -match:[/\b(class|module)\s+/,i]}],scope:{2:"title.class", -4:"title.class.inherited"},keywords:r},{match:[/(include|extend)\s+/,i],scope:{ -2:"title.class"},keywords:r},{relevance:0,match:[i,/\.new[. (]/],scope:{ -1:"title.class"}},{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, -className:"variable.constant"},{relevance:0,match:a,scope:"title.class"},{ -match:[/def/,/\s+/,t],scope:{1:"keyword",3:"title.function"},contains:[b]},{ -begin:e.IDENT_RE+"::"},{className:"symbol", -begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol", -begin:":(?!\\s)",contains:[d,{begin:t}],relevance:0},u,{className:"variable", -begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{ -className:"params",begin:/\|/,end:/\|/,excludeBegin:!0,excludeEnd:!0, -relevance:0,keywords:r},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*", -keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c], -illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{ -begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[", -end:"\\][a-z]*"}]}].concat(o,l),relevance:0}].concat(o,l) -;c.contains=m,b.contains=m;const p=[{begin:/^\s*=>/,starts:{end:"$",contains:m} -},{className:"meta.prompt", -begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])", -starts:{end:"$",keywords:r,contains:m}}];return l.unshift(o),{name:"Ruby", -aliases:["rb","gemspec","podspec","thor","irb"],keywords:r,illegal:/\/\*/, -contains:[e.SHEBANG({binary:"ruby"})].concat(p).concat(l).concat(m)}}, -grmr_rust:e=>{const n=e.regex,t={className:"title.function.invoke",relevance:0, -begin:n.concat(/\b/,/(?!let|for|while|if|else|match\b)/,e.IDENT_RE,n.lookahead(/\s*\(/)) -},a="([ui](8|16|32|64|128|size)|f(32|64))?",i=["drop ","Copy","Send","Sized","Sync","Drop","Fn","FnMut","FnOnce","ToOwned","Clone","Debug","PartialEq","PartialOrd","Eq","Ord","AsRef","AsMut","Into","From","Default","Iterator","Extend","IntoIterator","DoubleEndedIterator","ExactSizeIterator","SliceConcatExt","ToString","assert!","assert_eq!","bitflags!","bytes!","cfg!","col!","concat!","concat_idents!","debug_assert!","debug_assert_eq!","env!","eprintln!","panic!","file!","format!","format_args!","include_bytes!","include_str!","line!","local_data_key!","module_path!","option_env!","print!","println!","select!","stringify!","try!","unimplemented!","unreachable!","vec!","write!","writeln!","macro_rules!","assert_ne!","debug_assert_ne!"],r=["i8","i16","i32","i64","i128","isize","u8","u16","u32","u64","u128","usize","f32","f64","str","char","bool","Box","Option","Result","String","Vec"] -;return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",type:r, -keyword:["abstract","as","async","await","become","box","break","const","continue","crate","do","dyn","else","enum","extern","false","final","fn","for","if","impl","in","let","loop","macro","match","mod","move","mut","override","priv","pub","ref","return","self","Self","static","struct","super","trait","true","try","type","typeof","unsafe","unsized","use","virtual","where","while","yield"], -literal:["true","false","Some","None","Ok","Err"],built_in:i},illegal:""},t]}}, -grmr_scss:e=>{const n=ie(e),t=le,a=oe,i="@[a-z-]+",r={className:"variable", -begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b",relevance:0};return{name:"SCSS", -case_insensitive:!0,illegal:"[=/|']", -contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,n.CSS_NUMBER_MODE,{ -className:"selector-id",begin:"#[A-Za-z0-9_-]+",relevance:0},{ -className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0 -},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-tag", -begin:"\\b("+re.join("|")+")\\b",relevance:0},{className:"selector-pseudo", -begin:":("+a.join("|")+")"},{className:"selector-pseudo", -begin:":(:)?("+t.join("|")+")"},r,{begin:/\(/,end:/\)/, -contains:[n.CSS_NUMBER_MODE]},n.CSS_VARIABLE,{className:"attribute", -begin:"\\b("+ce.join("|")+")\\b"},{ -begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b" -},{begin:/:/,end:/[;}{]/,relevance:0, -contains:[n.BLOCK_COMMENT,r,n.HEXCOLOR,n.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.IMPORTANT,n.FUNCTION_DISPATCH] -},{begin:"@(page|font-face)",keywords:{$pattern:i,keyword:"@page @font-face"}},{ -begin:"@",end:"[{;]",returnBegin:!0,keywords:{$pattern:/[a-z-]+/, -keyword:"and or not only",attribute:se.join(" ")},contains:[{begin:i, -className:"keyword"},{begin:/[a-z-]+(?=:)/,className:"attribute" -},r,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.HEXCOLOR,n.CSS_NUMBER_MODE] -},n.FUNCTION_DISPATCH]}},grmr_shell:e=>({name:"Shell Session", -aliases:["console","shellsession"],contains:[{className:"meta.prompt", -begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/, -subLanguage:"bash"}}]}),grmr_sql:e=>{ -const n=e.regex,t=e.COMMENT("--","$"),a=["true","false","unknown"],i=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],r=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],s=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],o=r,l=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter((e=>!r.includes(e))),c={ -begin:n.concat(/\b/,n.either(...o),/\s*\(/),relevance:0,keywords:{built_in:o}} -;return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{ -$pattern:/\b[\w\.]+/,keyword:((e,{exceptions:n,when:t}={})=>{const a=t -;return n=n||[],e.map((e=>e.match(/\|\d+$/)||n.includes(e)?e:a(e)?e+"|0":e)) -})(l,{when:e=>e.length<3}),literal:a,type:i, -built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"] -},contains:[{begin:n.either(...s),relevance:0,keywords:{$pattern:/[\w\.]+/, -keyword:l.concat(s),literal:a,type:i}},{className:"type", -begin:n.either("double precision","large object","with timezone","without timezone") -},c,{className:"variable",begin:/@[a-z0-9][a-z0-9_]*/},{className:"string", -variants:[{begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/, -contains:[{begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,{ -className:"operator",begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/, -relevance:0}]}},grmr_swift:e=>{const n={match:/\s+/,relevance:0 -},t=e.COMMENT("/\\*","\\*/",{contains:["self"]}),a=[e.C_LINE_COMMENT_MODE,t],i={ -match:[/\./,m(...xe,...Me)],className:{2:"keyword"}},r={match:b(/\./,m(...Ae)), -relevance:0},s=Ae.filter((e=>"string"==typeof e)).concat(["_|0"]),o={variants:[{ -className:"keyword", -match:m(...Ae.filter((e=>"string"!=typeof e)).concat(Se).map(ke),...Me)}]},l={ -$pattern:m(/\b\w+/,/#\w+/),keyword:s.concat(Re),literal:Ce},c=[i,r,o],g=[{ -match:b(/\./,m(...De)),relevance:0},{className:"built_in", -match:b(/\b/,m(...De),/(?=\()/)}],u={match:/->/,relevance:0},p=[u,{ -className:"operator",relevance:0,variants:[{match:Be},{match:`\\.(\\.|${Le})+`}] -}],_="([0-9]_*)+",h="([0-9a-fA-F]_*)+",f={className:"number",relevance:0, -variants:[{match:`\\b(${_})(\\.(${_}))?([eE][+-]?(${_}))?\\b`},{ -match:`\\b0x(${h})(\\.(${h}))?([pP][+-]?(${_}))?\\b`},{match:/\b0o([0-7]_*)+\b/ -},{match:/\b0b([01]_*)+\b/}]},E=(e="")=>({className:"subst",variants:[{ -match:b(/\\/,e,/[0\\tnr"']/)},{match:b(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}] -}),y=(e="")=>({className:"subst",match:b(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/) -}),N=(e="")=>({className:"subst",label:"interpol",begin:b(/\\/,e,/\(/),end:/\)/ -}),w=(e="")=>({begin:b(e,/"""/),end:b(/"""/,e),contains:[E(e),y(e),N(e)] -}),v=(e="")=>({begin:b(e,/"/),end:b(/"/,e),contains:[E(e),N(e)]}),O={ -className:"string", -variants:[w(),w("#"),w("##"),w("###"),v(),v("#"),v("##"),v("###")] -},k=[e.BACKSLASH_ESCAPE,{begin:/\[/,end:/\]/,relevance:0, -contains:[e.BACKSLASH_ESCAPE]}],x={begin:/\/[^\s](?=[^/\n]*\/)/,end:/\//, -contains:k},M=e=>{const n=b(e,/\//),t=b(/\//,e);return{begin:n,end:t, -contains:[...k,{scope:"comment",begin:`#(?!.*${t})`,end:/$/}]}},S={ -scope:"regexp",variants:[M("###"),M("##"),M("#"),x]},A={match:b(/`/,Fe,/`/) -},C=[A,{className:"variable",match:/\$\d+/},{className:"variable", -match:`\\$${ze}+`}],T=[{match:/(@|#(un)?)available/,scope:"keyword",starts:{ -contains:[{begin:/\(/,end:/\)/,keywords:Pe,contains:[...p,f,O]}]}},{ -scope:"keyword",match:b(/@/,m(...je))},{scope:"meta",match:b(/@/,Fe)}],R={ -match:d(/\b[A-Z]/),relevance:0,contains:[{className:"type", -match:b(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,ze,"+") -},{className:"type",match:Ue,relevance:0},{match:/[?!]+/,relevance:0},{ -match:/\.\.\./,relevance:0},{match:b(/\s+&\s+/,d(Ue)),relevance:0}]},D={ -begin://,keywords:l,contains:[...a,...c,...T,u,R]};R.contains.push(D) -;const I={begin:/\(/,end:/\)/,relevance:0,keywords:l,contains:["self",{ -match:b(Fe,/\s*:/),keywords:"_|0",relevance:0 -},...a,S,...c,...g,...p,f,O,...C,...T,R]},L={begin://, -keywords:"repeat each",contains:[...a,R]},B={begin:/\(/,end:/\)/,keywords:l, -contains:[{begin:m(d(b(Fe,/\s*:/)),d(b(Fe,/\s+/,Fe,/\s*:/))),end:/:/, -relevance:0,contains:[{className:"keyword",match:/\b_\b/},{className:"params", -match:Fe}]},...a,...c,...p,f,O,...T,R,I],endsParent:!0,illegal:/["']/},$={ -match:[/(func|macro)/,/\s+/,m(A.match,Fe,Be)],className:{1:"keyword", -3:"title.function"},contains:[L,B,n],illegal:[/\[/,/%/]},z={ -match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"}, -contains:[L,B,n],illegal:/\[|%/},F={match:[/operator/,/\s+/,Be],className:{ -1:"keyword",3:"title"}},U={begin:[/precedencegroup/,/\s+/,Ue],className:{ -1:"keyword",3:"title"},contains:[R],keywords:[...Te,...Ce],end:/}/} -;for(const e of O.variants){const n=e.contains.find((e=>"interpol"===e.label)) -;n.keywords=l;const t=[...c,...g,...p,f,O,...C];n.contains=[...t,{begin:/\(/, -end:/\)/,contains:["self",...t]}]}return{name:"Swift",keywords:l, -contains:[...a,$,z,{beginKeywords:"struct protocol class extension enum actor", -end:"\\{",excludeEnd:!0,keywords:l,contains:[e.inherit(e.TITLE_MODE,{ -className:"title.class",begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/}),...c] -},F,U,{beginKeywords:"import",end:/$/,contains:[...a],relevance:0 -},S,...c,...g,...p,f,O,...C,...T,R,I]}},grmr_typescript:e=>{ -const n=Oe(e),t=_e,a=["any","void","number","boolean","string","object","never","symbol","bigint","unknown"],i={ -beginKeywords:"namespace",end:/\{/,excludeEnd:!0, -contains:[n.exports.CLASS_REFERENCE]},r={beginKeywords:"interface",end:/\{/, -excludeEnd:!0,keywords:{keyword:"interface extends",built_in:a}, -contains:[n.exports.CLASS_REFERENCE]},s={$pattern:_e, -keyword:he.concat(["type","namespace","interface","public","private","protected","implements","declare","abstract","readonly","enum","override"]), -literal:fe,built_in:ve.concat(a),"variable.language":we},o={className:"meta", -begin:"@"+t},l=(e,n,t)=>{const a=e.contains.findIndex((e=>e.label===n)) -;if(-1===a)throw Error("can not find mode to replace");e.contains.splice(a,1,t)} -;return Object.assign(n.keywords,s), -n.exports.PARAMS_CONTAINS.push(o),n.contains=n.contains.concat([o,i,r]), -l(n,"shebang",e.SHEBANG()),l(n,"use_strict",{className:"meta",relevance:10, -begin:/^\s*['"]use strict['"]/ -}),n.contains.find((e=>"func.def"===e.label)).relevance=0,Object.assign(n,{ -name:"TypeScript",aliases:["ts","tsx","mts","cts"]}),n},grmr_vbnet:e=>{ -const n=e.regex,t=/\d{1,2}\/\d{1,2}\/\d{4}/,a=/\d{4}-\d{1,2}-\d{1,2}/,i=/(\d|1[012])(:\d+){0,2} *(AM|PM)/,r=/\d{1,2}(:\d{1,2}){1,2}/,s={ -className:"literal",variants:[{begin:n.concat(/# */,n.either(a,t),/ *#/)},{ -begin:n.concat(/# */,r,/ *#/)},{begin:n.concat(/# */,i,/ *#/)},{ -begin:n.concat(/# */,n.either(a,t),/ +/,n.either(i,r),/ *#/)}] -},o=e.COMMENT(/'''/,/$/,{contains:[{className:"doctag",begin:/<\/?/,end:/>/}] -}),l=e.COMMENT(null,/$/,{variants:[{begin:/'/},{begin:/([\t ]|^)REM(?=\s)/}]}) -;return{name:"Visual Basic .NET",aliases:["vb"],case_insensitive:!0, -classNameAliases:{label:"symbol"},keywords:{ -keyword:"addhandler alias aggregate ansi as async assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into iterator join key let lib loop me mid module mustinherit mustoverride mybase myclass namespace narrowing new next notinheritable notoverridable of off on operator option optional order overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly yield", -built_in:"addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort", -type:"boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort", -literal:"true false nothing"}, -illegal:"//|\\{|\\}|endif|gosub|variant|wend|^\\$ ",contains:[{ -className:"string",begin:/"(""|[^/n])"C\b/},{className:"string",begin:/"/, -end:/"/,illegal:/\n/,contains:[{begin:/""/}]},s,{className:"number",relevance:0, -variants:[{begin:/\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/ -},{begin:/\b\d[\d_]*((U?[SIL])|[%&])?/},{begin:/&H[\dA-F_]+((U?[SIL])|[%&])?/},{ -begin:/&O[0-7_]+((U?[SIL])|[%&])?/},{begin:/&B[01_]+((U?[SIL])|[%&])?/}]},{ -className:"label",begin:/^\w+:/},o,l,{className:"meta", -begin:/[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/, -end:/$/,keywords:{ -keyword:"const disable else elseif enable end externalsource if region then"}, -contains:[l]}]}},grmr_wasm:e=>{e.regex;const n=e.COMMENT(/\(;/,/;\)/) -;return n.contains.push("self"),{name:"WebAssembly",keywords:{$pattern:/[\w.]+/, -keyword:["anyfunc","block","br","br_if","br_table","call","call_indirect","data","drop","elem","else","end","export","func","global.get","global.set","local.get","local.set","local.tee","get_global","get_local","global","if","import","local","loop","memory","memory.grow","memory.size","module","mut","nop","offset","param","result","return","select","set_global","set_local","start","table","tee_local","then","type","unreachable"] -},contains:[e.COMMENT(/;;/,/$/),n,{match:[/(?:offset|align)/,/\s*/,/=/], -className:{1:"keyword",3:"operator"}},{className:"variable",begin:/\$[\w_]+/},{ -match:/(\((?!;)|\))+/,className:"punctuation",relevance:0},{ -begin:[/(?:func|call|call_indirect)/,/\s+/,/\$[^\s)]+/],className:{1:"keyword", -3:"title.function"}},e.QUOTE_STRING_MODE,{match:/(i32|i64|f32|f64)(?!\.)/, -className:"type"},{className:"keyword", -match:/\b(f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|nearest|neg?|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|store(?:8|16|32)?|sqrt|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))\b/ -},{className:"number",relevance:0, -match:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/ -}]}},grmr_xml:e=>{ -const n=e.regex,t=n.concat(/[\p{L}_]/u,n.optional(/[\p{L}0-9_.-]*:/u),/[\p{L}0-9_.-]*/u),a={ -className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},i={begin:/\s/, -contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}] -},r=e.inherit(i,{begin:/\(/,end:/\)/}),s=e.inherit(e.APOS_STRING_MODE,{ -className:"string"}),o=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),l={ -endsWithParent:!0,illegal:/`]+/}]}]}]};return{ -name:"HTML, XML", -aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"], -case_insensitive:!0,unicodeRegex:!0,contains:[{className:"meta",begin://,relevance:10,contains:[i,o,s,r,{begin:/\[/,end:/\]/,contains:[{ -className:"meta",begin://,contains:[i,r,o,s]}]}] -},e.COMMENT(//,{relevance:10}),{begin://, -relevance:10},a,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/, -relevance:10,contains:[o]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag", -begin:/)/,end:/>/,keywords:{name:"style"},contains:[l],starts:{ -end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag", -begin:/)/,end:/>/,keywords:{name:"script"},contains:[l],starts:{ -end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{ -className:"tag",begin:/<>|<\/>/},{className:"tag", -begin:n.concat(//,/>/,/\s/)))), -end:/\/?>/,contains:[{className:"name",begin:t,relevance:0,starts:l}]},{ -className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(t,/>/))),contains:[{ -className:"name",begin:t,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]} -},grmr_yaml:e=>{ -const n="true false yes no null",t="[\\w#;/?:@&=+$,.~*'()[\\]]+",a={ -className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/ -},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable", -variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(a,{ -variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),r={ -end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},s={begin:/\{/, -end:/\}/,contains:[r],illegal:"\\n",relevance:0},o={begin:"\\[",end:"\\]", -contains:[r],illegal:"\\n",relevance:0},l=[{className:"attr",variants:[{ -begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{ -begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$", -relevance:10},{className:"string", -begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{ -begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0, -relevance:0},{className:"type",begin:"!\\w+!"+t},{className:"type", -begin:"!<"+t+">"},{className:"type",begin:"!"+t},{className:"type",begin:"!!"+t -},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta", -begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)", -relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{ -className:"number", -begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b" -},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},s,o,a],c=[...l] -;return c.pop(),c.push(i),r.contains=c,{name:"YAML",case_insensitive:!0, -aliases:["yml"],contains:l}}});const He=ae;for(const e of Object.keys(Ke)){ -const n=e.replace("grmr_","").replace("_","-");He.registerLanguage(n,Ke[e])} -return He}() -;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); \ No newline at end of file diff --git a/lib/marked.min.js b/lib/marked.min.js deleted file mode 100644 index a91afe7..0000000 --- a/lib/marked.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * marked v12.0.2 - a markdown parser - * Copyright (c) 2011-2024, Christopher Jeffrey. (MIT Licensed) - * https://github.com/markedjs/marked - */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).marked={})}(this,(function(e){"use strict";function t(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}function n(t){e.defaults=t}e.defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};const s=/[&<>"']/,r=new RegExp(s.source,"g"),i=/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,l=new RegExp(i.source,"g"),o={"&":"&","<":"<",">":">",'"':""","'":"'"},a=e=>o[e];function c(e,t){if(t){if(s.test(e))return e.replace(r,a)}else if(i.test(e))return e.replace(l,a);return e}const h=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function p(e){return e.replace(h,((e,t)=>"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""))}const u=/(^|[^\[])\^/g;function k(e,t){let n="string"==typeof e?e:e.source;t=t||"";const s={replace:(e,t)=>{let r="string"==typeof t?t:t.source;return r=r.replace(u,"$1"),n=n.replace(e,r),s},getRegex:()=>new RegExp(n,t)};return s}function g(e){try{e=encodeURI(e).replace(/%25/g,"%")}catch(e){return null}return e}const f={exec:()=>null};function d(e,t){const n=e.replace(/\|/g,((e,t,n)=>{let s=!1,r=t;for(;--r>=0&&"\\"===n[r];)s=!s;return s?"|":" |"})).split(/ \|/);let s=0;if(n[0].trim()||n.shift(),n.length>0&&!n[n.length-1].trim()&&n.pop(),t)if(n.length>t)n.splice(t);else for(;n.length0)return{type:"space",raw:t[0]}}code(e){const t=this.rules.block.code.exec(e);if(t){const e=t[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?e:x(e,"\n")}}}fences(e){const t=this.rules.block.fences.exec(e);if(t){const e=t[0],n=function(e,t){const n=e.match(/^(\s+)(?:```)/);if(null===n)return t;const s=n[1];return t.split("\n").map((e=>{const t=e.match(/^\s+/);if(null===t)return e;const[n]=t;return n.length>=s.length?e.slice(s.length):e})).join("\n")}(e,t[3]||"");return{type:"code",raw:e,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:n}}}heading(e){const t=this.rules.block.heading.exec(e);if(t){let e=t[2].trim();if(/#$/.test(e)){const t=x(e,"#");this.options.pedantic?e=t.trim():t&&!/ $/.test(t)||(e=t.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:e,tokens:this.lexer.inline(e)}}}hr(e){const t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:t[0]}}blockquote(e){const t=this.rules.block.blockquote.exec(e);if(t){let e=t[0].replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,"\n $1");e=x(e.replace(/^ *>[ \t]?/gm,""),"\n");const n=this.lexer.state.top;this.lexer.state.top=!0;const s=this.lexer.blockTokens(e);return this.lexer.state.top=n,{type:"blockquote",raw:t[0],tokens:s,text:e}}}list(e){let t=this.rules.block.list.exec(e);if(t){let n=t[1].trim();const s=n.length>1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:!1,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");const i=new RegExp(`^( {0,3}${n})((?:[\t ][^\\n]*)?(?:\\n|$))`);let l="",o="",a=!1;for(;e;){let n=!1;if(!(t=i.exec(e)))break;if(this.rules.block.hr.test(e))break;l=t[0],e=e.substring(l.length);let s=t[2].split("\n",1)[0].replace(/^\t+/,(e=>" ".repeat(3*e.length))),c=e.split("\n",1)[0],h=0;this.options.pedantic?(h=2,o=s.trimStart()):(h=t[2].search(/[^ ]/),h=h>4?1:h,o=s.slice(h),h+=t[1].length);let p=!1;if(!s&&/^ *$/.test(c)&&(l+=c+"\n",e=e.substring(c.length+1),n=!0),!n){const t=new RegExp(`^ {0,${Math.min(3,h-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`),n=new RegExp(`^ {0,${Math.min(3,h-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),r=new RegExp(`^ {0,${Math.min(3,h-1)}}(?:\`\`\`|~~~)`),i=new RegExp(`^ {0,${Math.min(3,h-1)}}#`);for(;e;){const a=e.split("\n",1)[0];if(c=a,this.options.pedantic&&(c=c.replace(/^ {1,4}(?=( {4})*[^ ])/g," ")),r.test(c))break;if(i.test(c))break;if(t.test(c))break;if(n.test(e))break;if(c.search(/[^ ]/)>=h||!c.trim())o+="\n"+c.slice(h);else{if(p)break;if(s.search(/[^ ]/)>=4)break;if(r.test(s))break;if(i.test(s))break;if(n.test(s))break;o+="\n"+c}p||c.trim()||(p=!0),l+=a+"\n",e=e.substring(a.length+1),s=c.slice(h)}}r.loose||(a?r.loose=!0:/\n *\n *$/.test(l)&&(a=!0));let u,k=null;this.options.gfm&&(k=/^\[[ xX]\] /.exec(o),k&&(u="[ ] "!==k[0],o=o.replace(/^\[[ xX]\] +/,""))),r.items.push({type:"list_item",raw:l,task:!!k,checked:u,loose:!1,text:o,tokens:[]}),r.raw+=l}r.items[r.items.length-1].raw=l.trimEnd(),r.items[r.items.length-1].text=o.trimEnd(),r.raw=r.raw.trimEnd();for(let e=0;e"space"===e.type)),n=t.length>0&&t.some((e=>/\n.*\n/.test(e.raw)));r.loose=n}if(r.loose)for(let e=0;e$/,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",s=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):t[3];return{type:"def",tag:e,raw:t[0],href:n,title:s}}}table(e){const t=this.rules.block.table.exec(e);if(!t)return;if(!/[:|]/.test(t[2]))return;const n=d(t[1]),s=t[2].replace(/^\||\| *$/g,"").split("|"),r=t[3]&&t[3].trim()?t[3].replace(/\n[ \t]*$/,"").split("\n"):[],i={type:"table",raw:t[0],header:[],align:[],rows:[]};if(n.length===s.length){for(const e of s)/^ *-+: *$/.test(e)?i.align.push("right"):/^ *:-+: *$/.test(e)?i.align.push("center"):/^ *:-+ *$/.test(e)?i.align.push("left"):i.align.push(null);for(const e of n)i.header.push({text:e,tokens:this.lexer.inline(e)});for(const e of r)i.rows.push(d(e,i.header.length).map((e=>({text:e,tokens:this.lexer.inline(e)}))));return i}}lheading(e){const t=this.rules.block.lheading.exec(e);if(t)return{type:"heading",raw:t[0],depth:"="===t[2].charAt(0)?1:2,text:t[1],tokens:this.lexer.inline(t[1])}}paragraph(e){const t=this.rules.block.paragraph.exec(e);if(t){const e="\n"===t[1].charAt(t[1].length-1)?t[1].slice(0,-1):t[1];return{type:"paragraph",raw:t[0],text:e,tokens:this.lexer.inline(e)}}}text(e){const t=this.rules.block.text.exec(e);if(t)return{type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){const t=this.rules.inline.escape.exec(e);if(t)return{type:"escape",raw:t[0],text:c(t[1])}}tag(e){const t=this.rules.inline.tag.exec(e);if(t)return!this.lexer.state.inLink&&/^/i.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:t[0]}}link(e){const t=this.rules.inline.link.exec(e);if(t){const e=t[2].trim();if(!this.options.pedantic&&/^$/.test(e))return;const t=x(e.slice(0,-1),"\\");if((e.length-t.length)%2==0)return}else{const e=function(e,t){if(-1===e.indexOf(t[1]))return-1;let n=0;for(let s=0;s-1){const n=(0===t[0].indexOf("!")?5:4)+t[1].length+e;t[2]=t[2].substring(0,e),t[0]=t[0].substring(0,n).trim(),t[3]=""}}let n=t[2],s="";if(this.options.pedantic){const e=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(n);e&&(n=e[1],s=e[3])}else s=t[3]?t[3].slice(1,-1):"";return n=n.trim(),/^$/.test(e)?n.slice(1):n.slice(1,-1)),b(t,{href:n?n.replace(this.rules.inline.anyPunctuation,"$1"):n,title:s?s.replace(this.rules.inline.anyPunctuation,"$1"):s},t[0],this.lexer)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){const e=t[(n[2]||n[1]).replace(/\s+/g," ").toLowerCase()];if(!e){const e=n[0].charAt(0);return{type:"text",raw:e,text:e}}return b(n,e,n[0],this.lexer)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s)return;if(s[3]&&n.match(/[\p{L}\p{N}]/u))return;if(!(s[1]||s[2]||"")||!n||this.rules.inline.punctuation.exec(n)){const n=[...s[0]].length-1;let r,i,l=n,o=0;const a="*"===s[0][0]?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(a.lastIndex=0,t=t.slice(-1*e.length+n);null!=(s=a.exec(t));){if(r=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!r)continue;if(i=[...r].length,s[3]||s[4]){l+=i;continue}if((s[5]||s[6])&&n%3&&!((n+i)%3)){o+=i;continue}if(l-=i,l>0)continue;i=Math.min(i,i+l+o);const t=[...s[0]][0].length,a=e.slice(0,n+s.index+t+i);if(Math.min(n,i)%2){const e=a.slice(1,-1);return{type:"em",raw:a,text:e,tokens:this.lexer.inlineTokens(e)}}const c=a.slice(2,-2);return{type:"strong",raw:a,text:c,tokens:this.lexer.inlineTokens(c)}}}}codespan(e){const t=this.rules.inline.code.exec(e);if(t){let e=t[2].replace(/\n/g," ");const n=/[^ ]/.test(e),s=/^ /.test(e)&&/ $/.test(e);return n&&s&&(e=e.substring(1,e.length-1)),e=c(e,!0),{type:"codespan",raw:t[0],text:e}}}br(e){const t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}}del(e){const t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2])}}autolink(e){const t=this.rules.inline.autolink.exec(e);if(t){let e,n;return"@"===t[2]?(e=c(t[1]),n="mailto:"+e):(e=c(t[1]),n=e),{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let e,n;if("@"===t[2])e=c(t[0]),n="mailto:"+e;else{let s;do{s=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??""}while(s!==t[0]);e=c(t[0]),n="www."===t[1]?"http://"+t[0]:t[0]}return{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}inlineText(e){const t=this.rules.inline.text.exec(e);if(t){let e;return e=this.lexer.state.inRawBlock?t[0]:c(t[0]),{type:"text",raw:t[0],text:e}}}}const m=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,y=/(?:[*+-]|\d{1,9}[.)])/,$=k(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/).replace(/bull/g,y).replace(/blockCode/g,/ {4}/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).getRegex(),z=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,T=/(?!\s*\])(?:\\.|[^\[\]\\])+/,R=k(/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/).replace("label",T).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),_=k(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,y).getRegex(),A="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",S=/|$))/,I=k("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))","i").replace("comment",S).replace("tag",A).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),E=k(z).replace("hr",m).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",A).getRegex(),q={blockquote:k(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",E).getRegex(),code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,def:R,fences:/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,hr:m,html:I,lheading:$,list:_,newline:/^(?: *(?:\n|$))+/,paragraph:E,table:f,text:/^[^\n]+/},Z=k("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",m).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",A).getRegex(),L={...q,table:Z,paragraph:k(z).replace("hr",m).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",Z).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",A).getRegex()},P={...q,html:k("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",S).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:f,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:k(z).replace("hr",m).replace("heading"," *#{1,6} *[^\n]").replace("lheading",$).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},Q=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,v=/^( {2,}|\\)\n(?!\s*$)/,B="\\p{P}\\p{S}",C=k(/^((?![*_])[\spunctuation])/,"u").replace(/punctuation/g,B).getRegex(),M=k(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/,"u").replace(/punct/g,B).getRegex(),O=k("^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)[punct](\\*+)(?=[\\s]|$)|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])|[\\s](\\*+)(?!\\*)(?=[punct])|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])|[^punct\\s](\\*+)(?=[^punct\\s])","gu").replace(/punct/g,B).getRegex(),D=k("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\\s]|$)|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)|(?!_)[punct\\s](_+)(?=[^punct\\s])|[\\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])","gu").replace(/punct/g,B).getRegex(),j=k(/\\([punct])/,"gu").replace(/punct/g,B).getRegex(),H=k(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),U=k(S).replace("(?:--\x3e|$)","--\x3e").getRegex(),X=k("^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^").replace("comment",U).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),F=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,N=k(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/).replace("label",F).replace("href",/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),G=k(/^!?\[(label)\]\[(ref)\]/).replace("label",F).replace("ref",T).getRegex(),J=k(/^!?\[(ref)\](?:\[\])?/).replace("ref",T).getRegex(),K={_backpedal:f,anyPunctuation:j,autolink:H,blockSkip:/\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g,br:v,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,del:f,emStrongLDelim:M,emStrongRDelimAst:O,emStrongRDelimUnd:D,escape:Q,link:N,nolink:J,punctuation:C,reflink:G,reflinkSearch:k("reflink|nolink(?!\\()","g").replace("reflink",G).replace("nolink",J).getRegex(),tag:X,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\t+" ".repeat(n.length)));e;)if(!(this.options.extensions&&this.options.extensions.block&&this.options.extensions.block.some((s=>!!(n=s.call({lexer:this},e,t))&&(e=e.substring(n.raw.length),t.push(n),!0)))))if(n=this.tokenizer.space(e))e=e.substring(n.raw.length),1===n.raw.length&&t.length>0?t[t.length-1].raw+="\n":t.push(n);else if(n=this.tokenizer.code(e))e=e.substring(n.raw.length),s=t[t.length-1],!s||"paragraph"!==s.type&&"text"!==s.type?t.push(n):(s.raw+="\n"+n.raw,s.text+="\n"+n.text,this.inlineQueue[this.inlineQueue.length-1].src=s.text);else if(n=this.tokenizer.fences(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.heading(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.hr(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.blockquote(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.list(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.html(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.def(e))e=e.substring(n.raw.length),s=t[t.length-1],!s||"paragraph"!==s.type&&"text"!==s.type?this.tokens.links[n.tag]||(this.tokens.links[n.tag]={href:n.href,title:n.title}):(s.raw+="\n"+n.raw,s.text+="\n"+n.raw,this.inlineQueue[this.inlineQueue.length-1].src=s.text);else if(n=this.tokenizer.table(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.lheading(e))e=e.substring(n.raw.length),t.push(n);else{if(r=e,this.options.extensions&&this.options.extensions.startBlock){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startBlock.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}if(this.state.top&&(n=this.tokenizer.paragraph(r)))s=t[t.length-1],i&&"paragraph"===s.type?(s.raw+="\n"+n.raw,s.text+="\n"+n.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=s.text):t.push(n),i=r.length!==e.length,e=e.substring(n.raw.length);else if(n=this.tokenizer.text(e))e=e.substring(n.raw.length),s=t[t.length-1],s&&"text"===s.type?(s.raw+="\n"+n.raw,s.text+="\n"+n.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=s.text):t.push(n);else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){let n,s,r,i,l,o,a=e;if(this.tokens.links){const e=Object.keys(this.tokens.links);if(e.length>0)for(;null!=(i=this.tokenizer.rules.inline.reflinkSearch.exec(a));)e.includes(i[0].slice(i[0].lastIndexOf("[")+1,-1))&&(a=a.slice(0,i.index)+"["+"a".repeat(i[0].length-2)+"]"+a.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(i=this.tokenizer.rules.inline.blockSkip.exec(a));)a=a.slice(0,i.index)+"["+"a".repeat(i[0].length-2)+"]"+a.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;null!=(i=this.tokenizer.rules.inline.anyPunctuation.exec(a));)a=a.slice(0,i.index)+"++"+a.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);for(;e;)if(l||(o=""),l=!1,!(this.options.extensions&&this.options.extensions.inline&&this.options.extensions.inline.some((s=>!!(n=s.call({lexer:this},e,t))&&(e=e.substring(n.raw.length),t.push(n),!0)))))if(n=this.tokenizer.escape(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.tag(e))e=e.substring(n.raw.length),s=t[t.length-1],s&&"text"===n.type&&"text"===s.type?(s.raw+=n.raw,s.text+=n.text):t.push(n);else if(n=this.tokenizer.link(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.reflink(e,this.tokens.links))e=e.substring(n.raw.length),s=t[t.length-1],s&&"text"===n.type&&"text"===s.type?(s.raw+=n.raw,s.text+=n.text):t.push(n);else if(n=this.tokenizer.emStrong(e,a,o))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.codespan(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.br(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.del(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.autolink(e))e=e.substring(n.raw.length),t.push(n);else if(this.state.inLink||!(n=this.tokenizer.url(e))){if(r=e,this.options.extensions&&this.options.extensions.startInline){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startInline.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}if(n=this.tokenizer.inlineText(r))e=e.substring(n.raw.length),"_"!==n.raw.slice(-1)&&(o=n.raw.slice(-1)),l=!0,s=t[t.length-1],s&&"text"===s.type?(s.raw+=n.raw,s.text+=n.text):t.push(n);else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}else e=e.substring(n.raw.length),t.push(n);return t}}class se{options;constructor(t){this.options=t||e.defaults}code(e,t,n){const s=(t||"").match(/^\S*/)?.[0];return e=e.replace(/\n$/,"")+"\n",s?'
'+(n?e:c(e,!0))+"
\n":"
"+(n?e:c(e,!0))+"
\n"}blockquote(e){return`
\n${e}
\n`}html(e,t){return e}heading(e,t,n){return`${e}\n`}hr(){return"
\n"}list(e,t,n){const s=t?"ol":"ul";return"<"+s+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"\n"}listitem(e,t,n){return`
  • ${e}
  • \n`}checkbox(e){return"'}paragraph(e){return`

    ${e}

    \n`}table(e,t){return t&&(t=`${t}`),"\n\n"+e+"\n"+t+"
    \n"}tablerow(e){return`\n${e}\n`}tablecell(e,t){const n=t.header?"th":"td";return(t.align?`<${n} align="${t.align}">`:`<${n}>`)+e+`\n`}strong(e){return`${e}`}em(e){return`${e}`}codespan(e){return`${e}`}br(){return"
    "}del(e){return`${e}`}link(e,t,n){const s=g(e);if(null===s)return n;let r='
    ",r}image(e,t,n){const s=g(e);if(null===s)return n;let r=`${n}0&&"paragraph"===n.tokens[0].type?(n.tokens[0].text=e+" "+n.tokens[0].text,n.tokens[0].tokens&&n.tokens[0].tokens.length>0&&"text"===n.tokens[0].tokens[0].type&&(n.tokens[0].tokens[0].text=e+" "+n.tokens[0].tokens[0].text)):n.tokens.unshift({type:"text",text:e+" "}):o+=e+" "}o+=this.parse(n.tokens,i),l+=this.renderer.listitem(o,r,!!s)}n+=this.renderer.list(l,t,s);continue}case"html":{const e=r;n+=this.renderer.html(e.text,e.block);continue}case"paragraph":{const e=r;n+=this.renderer.paragraph(this.parseInline(e.tokens));continue}case"text":{let i=r,l=i.tokens?this.parseInline(i.tokens):i.text;for(;s+1{const r=e[s].flat(1/0);n=n.concat(this.walkTokens(r,t))})):e.tokens&&(n=n.concat(this.walkTokens(e.tokens,t)))}}return n}use(...e){const t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach((e=>{const n={...e};if(n.async=this.defaults.async||n.async||!1,e.extensions&&(e.extensions.forEach((e=>{if(!e.name)throw new Error("extension name required");if("renderer"in e){const n=t.renderers[e.name];t.renderers[e.name]=n?function(...t){let s=e.renderer.apply(this,t);return!1===s&&(s=n.apply(this,t)),s}:e.renderer}if("tokenizer"in e){if(!e.level||"block"!==e.level&&"inline"!==e.level)throw new Error("extension level must be 'block' or 'inline'");const n=t[e.level];n?n.unshift(e.tokenizer):t[e.level]=[e.tokenizer],e.start&&("block"===e.level?t.startBlock?t.startBlock.push(e.start):t.startBlock=[e.start]:"inline"===e.level&&(t.startInline?t.startInline.push(e.start):t.startInline=[e.start]))}"childTokens"in e&&e.childTokens&&(t.childTokens[e.name]=e.childTokens)})),n.extensions=t),e.renderer){const t=this.defaults.renderer||new se(this.defaults);for(const n in e.renderer){if(!(n in t))throw new Error(`renderer '${n}' does not exist`);if("options"===n)continue;const s=n,r=e.renderer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n||""}}n.renderer=t}if(e.tokenizer){const t=this.defaults.tokenizer||new w(this.defaults);for(const n in e.tokenizer){if(!(n in t))throw new Error(`tokenizer '${n}' does not exist`);if(["options","rules","lexer"].includes(n))continue;const s=n,r=e.tokenizer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.tokenizer=t}if(e.hooks){const t=this.defaults.hooks||new le;for(const n in e.hooks){if(!(n in t))throw new Error(`hook '${n}' does not exist`);if("options"===n)continue;const s=n,r=e.hooks[s],i=t[s];le.passThroughHooks.has(n)?t[s]=e=>{if(this.defaults.async)return Promise.resolve(r.call(t,e)).then((e=>i.call(t,e)));const n=r.call(t,e);return i.call(t,n)}:t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.hooks=t}if(e.walkTokens){const t=this.defaults.walkTokens,s=e.walkTokens;n.walkTokens=function(e){let n=[];return n.push(s.call(this,e)),t&&(n=n.concat(t.call(this,e))),n}}this.defaults={...this.defaults,...n}})),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return ne.lex(e,t??this.defaults)}parser(e,t){return ie.parse(e,t??this.defaults)}#e(e,t){return(n,s)=>{const r={...s},i={...this.defaults,...r};!0===this.defaults.async&&!1===r.async&&(i.silent||console.warn("marked(): The async option was set to true by an extension. The async: false option sent to parse will be ignored."),i.async=!0);const l=this.#t(!!i.silent,!!i.async);if(null==n)return l(new Error("marked(): input parameter is undefined or null"));if("string"!=typeof n)return l(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));if(i.hooks&&(i.hooks.options=i),i.async)return Promise.resolve(i.hooks?i.hooks.preprocess(n):n).then((t=>e(t,i))).then((e=>i.hooks?i.hooks.processAllTokens(e):e)).then((e=>i.walkTokens?Promise.all(this.walkTokens(e,i.walkTokens)).then((()=>e)):e)).then((e=>t(e,i))).then((e=>i.hooks?i.hooks.postprocess(e):e)).catch(l);try{i.hooks&&(n=i.hooks.preprocess(n));let s=e(n,i);i.hooks&&(s=i.hooks.processAllTokens(s)),i.walkTokens&&this.walkTokens(s,i.walkTokens);let r=t(s,i);return i.hooks&&(r=i.hooks.postprocess(r)),r}catch(e){return l(e)}}}#t(e,t){return n=>{if(n.message+="\nPlease report this to https://github.com/markedjs/marked.",e){const e="

    An error occurred:

    "+c(n.message+"",!0)+"
    ";return t?Promise.resolve(e):e}if(t)return Promise.reject(n);throw n}}}const ae=new oe;function ce(e,t){return ae.parse(e,t)}ce.options=ce.setOptions=function(e){return ae.setOptions(e),ce.defaults=ae.defaults,n(ce.defaults),ce},ce.getDefaults=t,ce.defaults=e.defaults,ce.use=function(...e){return ae.use(...e),ce.defaults=ae.defaults,n(ce.defaults),ce},ce.walkTokens=function(e,t){return ae.walkTokens(e,t)},ce.parseInline=ae.parseInline,ce.Parser=ie,ce.parser=ie.parse,ce.Renderer=se,ce.TextRenderer=re,ce.Lexer=ne,ce.lexer=ne.lex,ce.Tokenizer=w,ce.Hooks=le,ce.parse=ce;const he=ce.options,pe=ce.setOptions,ue=ce.use,ke=ce.walkTokens,ge=ce.parseInline,fe=ce,de=ie.parse,xe=ne.lex;e.Hooks=le,e.Lexer=ne,e.Marked=oe,e.Parser=ie,e.Renderer=se,e.TextRenderer=re,e.Tokenizer=w,e.getDefaults=t,e.lexer=xe,e.marked=ce,e.options=he,e.parse=fe,e.parseInline=ge,e.parser=de,e.setOptions=pe,e.use=ue,e.walkTokens=ke})); diff --git a/main.js b/main.js deleted file mode 100644 index c7725fa..0000000 --- a/main.js +++ /dev/null @@ -1,447 +0,0 @@ -const { app, BrowserWindow, dialog, ipcMain } = require('electron'); -const path = require('path'); -const fs = require('fs'); -const { readFile, stat } = require('fs/promises'); - -const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB - -let mainWindow = null; -let activeFilePath = null; // Currently active tab's file path -let pendingFilePath = null; -let fileWatcher = null; -let closeTimeout = null; -let isClosing = false; // Prevent re-entrant close -let isSelfWriting = false; // Skip fs.watch events triggered by our own writes - -// ===== Single Instance Lock ===== -const gotTheLock = app.requestSingleInstanceLock(); - -if (!gotTheLock) { - app.quit(); -} else { - app.on('second-instance', (event, commandLine, workingDirectory) => { - // A second instance was launched (e.g. double-clicking a .md file) - // Focus the existing window and open the file in it - if (mainWindow && !mainWindow.isDestroyed()) { - if (mainWindow.isMinimized()) mainWindow.restore(); - mainWindow.focus(); - - // Extract file path from the second instance's command line args - const filePath = getFilePathFromArgs(commandLine); - if (filePath) { - openFileInTab(filePath); - } - } - }); -} - -// Extract a valid file path from command line arguments (skip Electron flags) -function getFilePathFromArgs(args) { - for (let i = 1; i < args.length; i++) { - const arg = args[i]; - if (!arg.startsWith('--') && !arg.startsWith('-')) { - try { - if (fs.existsSync(arg)) return arg; - } catch (e) { /* ignore */ } - } - } - return null; -} - -function createWindow() { - mainWindow = new BrowserWindow({ - width: 1200, - height: 800, - minWidth: 800, - minHeight: 600, - icon: path.join(__dirname, 'assets', 'icon.ico'), - webPreferences: { - preload: path.join(__dirname, 'preload.js'), - contextIsolation: true, - nodeIntegration: false - }, - titleBarStyle: 'default', - show: false - }); - - mainWindow.webContents.on('did-finish-load', () => { - if (pendingFilePath) { - openFileInTab(pendingFilePath); - pendingFilePath = null; - } - }); - - mainWindow.loadFile(path.join(__dirname, 'renderer', 'index.html')); - - mainWindow.once('ready-to-show', () => { - mainWindow.show(); - }); - - mainWindow.setMenu(null); - - // Unsaved changes warning on close - mainWindow.on('close', (e) => { - if (isClosing) return; // Prevent re-entrant close - isClosing = true; - e.preventDefault(); - try { - // 检查 webContents 是否仍可用 - if (!mainWindow.webContents.isDestroyed()) { - mainWindow.webContents.send('window:confirmClose'); - } else { - // 渲染进程已销毁,直接关闭 - mainWindow.removeAllListeners('close'); - mainWindow.close(); - return; - } - } catch (err) { - mainWindow.removeAllListeners('close'); - mainWindow.close(); - return; - } - // 5s safety timeout in case renderer is unresponsive - closeTimeout = setTimeout(() => { - closeTimeout = null; - if (mainWindow && !mainWindow.isDestroyed()) { - mainWindow.removeAllListeners('close'); - mainWindow.close(); - } - }, 5000); - }); - - mainWindow.on('closed', () => { - stopWatching(); - stopSidebarWatching(); - mainWindow = null; - }); -} - -// File watcher -function startWatching(filePath) { - stopWatching(); - if (!filePath) return; - try { - fileWatcher = fs.watch(filePath, (eventType) => { - if (eventType === 'change' && mainWindow && !mainWindow.isDestroyed()) { - // 跳过自身写入触发的 change 事件 - if (isSelfWriting) return; - mainWindow.webContents.send('file:externallyModified', filePath); - } - }); - } catch (err) { - // Silently ignore - } -} - -function stopWatching() { - if (fileWatcher) { - fileWatcher.close(); - fileWatcher = null; - } -} - -async function showOpenDialog() { - const result = await dialog.showOpenDialog(mainWindow, { - properties: ['openFile'], - filters: [ - { name: 'Markdown 文件', extensions: ['md', 'markdown', 'txt'] } - ] - }); - if (!result.canceled && result.filePaths.length > 0) { - return result.filePaths; - } - return null; -} - -async function readFileContent(filePath) { - // 文件大小检查 - const stats = await stat(filePath); - if (stats.size > MAX_FILE_SIZE) { - throw new Error(`文件过大(${(stats.size / 1024 / 1024).toFixed(1)} MB),暂不支持超过 20MB 的文件`); - } - let content = await readFile(filePath, 'utf-8'); - // 剥离 UTF-8 BOM(Windows 某些编辑器会添加) - if (content.charCodeAt(0) === 0xFEFF) content = content.slice(1); - return content; -} - -// Open file in a new tab (renderer manages tabs) -async function openFileInTab(filePath) { - if (!mainWindow || mainWindow.isDestroyed()) return; - try { - const content = await readFileContent(filePath); - activeFilePath = filePath; - startWatching(filePath); - mainWindow.setTitle(`MarkLite - ${path.basename(filePath)}`); - mainWindow.webContents.send('file:openInTab', { filePath, content }); - } catch (err) { - dialog.showErrorBox('错误', `无法读取文件: ${err.message}`); - } -} - -// Switch active file (for tab switching) -function switchActiveFile(filePath) { - activeFilePath = filePath || null; - startWatching(filePath); - if (mainWindow && !mainWindow.isDestroyed()) { - if (filePath) { - mainWindow.setTitle(`MarkLite - ${path.basename(filePath)}`); - } else { - mainWindow.setTitle('MarkLite'); - } - } -} - -// IPC Handlers - -// Save file to a specific path with watcher management -async function saveToPath(filePath, content) { - stopWatching(); - try { - isSelfWriting = true; - await fs.promises.writeFile(filePath, content, 'utf-8'); - isSelfWriting = false; - } catch (err) { - isSelfWriting = false; - startWatching(activeFilePath); - return { success: false, error: err.message }; - } - activeFilePath = filePath; - // 延迟 300ms 重新监听,确保文件系统的 change 事件已过期 - setTimeout(() => { - if (activeFilePath === filePath) { - startWatching(filePath); - } - }, 300); - if (mainWindow && !mainWindow.isDestroyed()) { - mainWindow.setTitle(`MarkLite - ${path.basename(filePath)}`); - } - return { success: true, filePath }; -} - -// Open single file via dialog -ipcMain.handle('dialog:openFile', async () => { - try { - const files = await showOpenDialog(); - if (files && files.length > 0) { - const content = await readFileContent(files[0]); - activeFilePath = files[0]; - startWatching(files[0]); - mainWindow.setTitle(`MarkLite - ${path.basename(files[0])}`); - return { filePath: files[0], content }; - } - return null; - } catch (err) { - return { error: err.message }; - } -}); - - -ipcMain.handle('file:read', async (event, filePath) => { - try { - const content = await readFileContent(filePath); - return { success: true, content }; - } catch (err) { - return { success: false, error: err.message }; - } -}); - -ipcMain.handle('file:save', async (event, { filePath, content }) => { - try { - if (filePath) { - return await saveToPath(filePath, content); - } else { - const result = await dialog.showSaveDialog(mainWindow, { - filters: [ - { name: 'Markdown 文件', extensions: ['md'] } - ] - }); - if (!result.canceled) { - return await saveToPath(result.filePath, content); - } - return { success: false, canceled: true }; - } - } catch (err) { - return { success: false, error: err.message }; - } -}); - -ipcMain.handle('file:saveAs', async (event, { content }) => { - try { - const result = await dialog.showSaveDialog(mainWindow, { - filters: [ - { name: 'Markdown 文件', extensions: ['md'] } - ] - }); - if (!result.canceled) { - return await saveToPath(result.filePath, content); - } - return { success: false, canceled: true }; - } catch (err) { - return { success: false, error: err.message }; - } -}); - -ipcMain.handle('file:getCurrentPath', () => { - return activeFilePath; -}); - -ipcMain.handle('file:stats', async (event, filePath) => { - try { - const fileStat = await stat(filePath); - return { success: true, size: fileStat.size, mtime: fileStat.mtime.toISOString() }; - } catch (err) { - return { success: false, error: err.message }; - } -}); - -ipcMain.handle('file:reload', async () => { - if (!activeFilePath) return { success: false, error: '没有打开的文件' }; - try { - const content = await readFileContent(activeFilePath); - return { success: true, content, filePath: activeFilePath }; - } catch (err) { - return { success: false, error: err.message }; - } -}); - -// ===== File Tree (Sidebar) ===== -const SKIP_DIRS = new Set(['node_modules', '.git', '.svn', '.hg', 'dist', 'out', '.next', '.nuxt', '__pycache__', '.DS_Store']); -const MARKDOWN_EXTS = new Set(['.md', '.markdown', '.txt']); - -async function buildDirTree(dirPath) { - const entries = await fs.promises.readdir(dirPath, { withFileTypes: true }); - // Sort: directories first, then files, alphabetically - entries.sort((a, b) => { - if (a.isDirectory() && !b.isDirectory()) return -1; - if (!a.isDirectory() && b.isDirectory()) return 1; - return a.name.localeCompare(b.name); - }); - - const children = []; - for (const entry of entries) { - if (SKIP_DIRS.has(entry.name)) continue; - if (entry.name.startsWith('.')) continue; - - const childPath = path.join(dirPath, entry.name); - if (entry.isDirectory()) { - const subChildren = await buildDirTree(childPath); - if (subChildren.length > 0) { - children.push({ name: entry.name, path: childPath, type: 'dir', children: subChildren }); - } - } else { - const ext = path.extname(entry.name).toLowerCase(); - if (MARKDOWN_EXTS.has(ext)) { - children.push({ name: entry.name, path: childPath, type: 'file' }); - } - } - } - return children; -} - -ipcMain.handle('dir:readTree', async (event, dirPath) => { - try { - const tree = await buildDirTree(dirPath); - return { success: true, tree, rootPath: dirPath }; - } catch (err) { - return { success: false, error: err.message }; - } -}); - -let sidebarWatcher = null; -let sidebarWatchPath = null; - -function startSidebarWatching(dirPath) { - stopSidebarWatching(); - if (!dirPath) return; - try { - sidebarWatchPath = dirPath; - sidebarWatcher = fs.watch(dirPath, { recursive: true }, (eventType, filename) => { - if (mainWindow && !mainWindow.isDestroyed()) { - mainWindow.webContents.send('sidebar:dirChanged'); - } - }); - } catch (err) { /* ignore */ } -} - -function stopSidebarWatching() { - if (sidebarWatcher) { sidebarWatcher.close(); sidebarWatcher = null; } - sidebarWatchPath = null; -} - -ipcMain.handle('dir:watch', (event, dirPath) => { - startSidebarWatching(dirPath); -}); - -ipcMain.handle('dir:unwatch', () => { - stopSidebarWatching(); -}); - -ipcMain.handle('dir:openDialog', async () => { - const result = await dialog.showOpenDialog(mainWindow, { - properties: ['openDirectory'] - }); - if (!result.canceled && result.filePaths.length > 0) { - return result.filePaths[0]; - } - return null; -}); - -// Tab switched - update active file tracking -ipcMain.handle('tab:switched', (event, filePath) => { - switchActiveFile(filePath); -}); - -ipcMain.handle('window:forceClose', () => { - if (closeTimeout) { - clearTimeout(closeTimeout); - closeTimeout = null; - } - // 窗口已销毁则无需操作(超时兜底可能已经关闭了窗口) - if (!mainWindow || mainWindow.isDestroyed()) return; - stopWatching(); - mainWindow.removeAllListeners('close'); - mainWindow.close(); -}); - -ipcMain.handle('window:cancelClose', () => { - if (closeTimeout) { - clearTimeout(closeTimeout); - closeTimeout = null; - } - isClosing = false; // Reset so close can be triggered again -}); - -// Command line file (first instance) -function getCommandLineFile() { - return getFilePathFromArgs(process.argv); -} - -// App lifecycle -app.whenReady().then(() => { - app.on('open-file', (event, filePath) => { - event.preventDefault(); - if (mainWindow && !mainWindow.isDestroyed() && mainWindow.webContents.isLoading()) { - pendingFilePath = filePath; - } else if (mainWindow && !mainWindow.isDestroyed()) { - openFileInTab(filePath); - } else { - pendingFilePath = filePath; - } - }); - - createWindow(); - - const fileToOpen = getCommandLineFile(); - if (fileToOpen) { - pendingFilePath = fileToOpen; - } -}); - -app.on('window-all-closed', () => { - if (process.platform !== 'darwin') app.quit(); -}); - -app.on('activate', () => { - if (BrowserWindow.getAllWindows().length === 0) createWindow(); -}); diff --git a/preload.js b/preload.js deleted file mode 100644 index 352131e..0000000 --- a/preload.js +++ /dev/null @@ -1,40 +0,0 @@ -const { contextBridge, ipcRenderer, shell } = require('electron'); - -contextBridge.exposeInMainWorld('electronAPI', { - // File operations - openFile: () => ipcRenderer.invoke('dialog:openFile'), - readFile: (filePath) => ipcRenderer.invoke('file:read', filePath), - saveFile: (data) => ipcRenderer.invoke('file:save', data), - saveFileAs: (data) => ipcRenderer.invoke('file:saveAs', data), - getCurrentPath: () => ipcRenderer.invoke('file:getCurrentPath'), - getFileStats: (filePath) => ipcRenderer.invoke('file:stats', filePath), - reloadFile: () => ipcRenderer.invoke('file:reload'), - - // Tab management - tabSwitched: (filePath) => ipcRenderer.invoke('tab:switched', filePath), - - // Window control - forceClose: () => ipcRenderer.invoke('window:forceClose'), - cancelClose: () => ipcRenderer.invoke('window:cancelClose'), - - // Shell - openExternal: (url) => shell.openExternal(url), - - // File Tree (Sidebar) - readDirTree: (dirPath) => ipcRenderer.invoke('dir:readTree', dirPath), - openFolderDialog: () => ipcRenderer.invoke('dir:openDialog'), - watchDir: (dirPath) => ipcRenderer.invoke('dir:watch', dirPath), - unwatchDir: () => ipcRenderer.invoke('dir:unwatch'), - - // Events from main process - onFileOpenInTab: (callback) => ipcRenderer.on('file:openInTab', (event, data) => callback(data)), - onMenuSave: (callback) => ipcRenderer.on('menu:save', () => callback()), - onMenuSaveAs: (callback) => ipcRenderer.on('menu:saveAs', () => callback()), - onViewModeChange: (callback) => ipcRenderer.on('menu:viewMode', (event, mode) => callback(mode)), - onExternalModification: (callback) => ipcRenderer.on('file:externallyModified', (event, filePath) => callback(filePath)), - onDirChanged: (callback) => ipcRenderer.on('sidebar:dirChanged', () => callback()), - onConfirmClose: (callback) => ipcRenderer.on('window:confirmClose', () => callback()), - - // Remove listeners - removeAllListeners: (channel) => ipcRenderer.removeAllListeners(channel) -}); diff --git a/renderer/index.html b/renderer/index.html deleted file mode 100644 index e6e7b71..0000000 --- a/renderer/index.html +++ /dev/null @@ -1,216 +0,0 @@ - - - - - - - - - MarkLite - - - - -
    - -
    -
    - - -
    - - - -
    -
    - -
    -
    - - -
    - - - - -
    - -
    -
    - -
    -
    - - - -
    - - -
    -
    - -
    -
    - - -
    - - -
    -
    -
    -
    - - -
    -
    -
    - - - M↓ - MarkLite - -
    -

    欢迎使用 MarkLite

    -

    一款轻量级的 Markdown 阅读器

    -
    - - -
    -
    -

    💡 提示:可以直接拖拽 .md 文件到窗口打开

    -

    ⌨️ 快捷键:Ctrl+O 打开 | Ctrl+S 保存 | Ctrl+F 搜索 | Ctrl+H 替换 | Ctrl+1/2/3 视图 | Ctrl+T 标签

    -
    -
    -
    -
    -
    - - -
    -
    - 就绪 -
    -
    - UTF-8 - | - Markdown - | - - | - 行 1, 列 1 -
    -
    - - - -
    - - - - - - diff --git a/renderer/renderer.js b/renderer/renderer.js deleted file mode 100644 index dae606e..0000000 --- a/renderer/renderer.js +++ /dev/null @@ -1,1735 +0,0 @@ -// MarkLite Renderer Process -(function () { - 'use strict'; - - // ===== DOM Elements ===== - const editor = document.getElementById('editor'); - const preview = document.getElementById('preview'); - const lineNumbers = document.getElementById('line-numbers'); - const welcomeScreen = document.getElementById('welcome-screen'); - const dropOverlay = document.getElementById('drop-overlay'); - const modifiedBanner = document.getElementById('modified-banner'); - const statusText = document.getElementById('status-text'); - const statusCursor = document.getElementById('status-cursor'); - const statusSize = document.getElementById('status-size'); - const statusSizeDivider = document.querySelector('.status-size-divider'); - const resizer = document.getElementById('resizer'); - const editorPanel = document.getElementById('editor-panel'); - const previewPanel = document.getElementById('preview-panel'); - const mainContent = document.getElementById('main-content'); - const contentWrapper = document.getElementById('content-wrapper'); - const tabList = document.getElementById('tab-list'); - - // Sidebar - const sidebar = document.getElementById('sidebar'); - const sidebarTree = document.getElementById('sidebar-tree'); - const btnOpenFolder = document.getElementById('btn-open-folder'); - - // Search - const searchBar = document.getElementById('search-bar'); - const searchInput = document.getElementById('search-input'); - const replaceInput = document.getElementById('replace-input'); - const searchCount = document.getElementById('search-count'); - const replaceRow = document.getElementById('replace-row'); - const btnCase = document.getElementById('btn-case'); - const btnRegex = document.getElementById('btn-regex'); - const btnNext = document.getElementById('btn-next'); - const btnPrev = document.getElementById('btn-prev'); - const btnSearchClose = document.getElementById('btn-search-close'); - const btnReplace = document.getElementById('btn-replace'); - const btnReplaceAll = document.getElementById('btn-replace-all'); - const btnToggleReplace = document.getElementById('btn-toggle-replace'); - - // Buttons - const btnOpen = document.getElementById('btn-open'); - const btnSave = document.getElementById('btn-save'); - const btnSplit = document.getElementById('btn-split'); - const btnEditor = document.getElementById('btn-editor'); - const btnPreview = document.getElementById('btn-preview'); - const btnWelcomeOpen = document.getElementById('btn-welcome-open'); - const btnWelcomeNew = document.getElementById('btn-welcome-new'); - const btnDark = document.getElementById('btn-dark'); - const btnReload = document.getElementById('btn-reload'); - const btnDismiss = document.getElementById('btn-dismiss'); - const btnNewTab = document.getElementById('btn-new-tab'); - - // ===== Tab State ===== - let tabs = []; // Array of tab objects - let activeTabId = null; - let tabIdCounter = 0; - let mruTabStack = []; // Most-recently-used tab IDs for Ctrl+Tab - - // ===== Other State ===== - let viewMode = 'split'; - let updateTimer = null; - let lineCountCache = 0; - let _loadingTab = false; // 加载 tab 内容期间跳过 input 事件的 isModified 标记 - let currentRootPath = null; - - // Search state - let searchMatches = []; - let searchIndex = -1; - let searchCaseSensitive = false; - let searchUseRegex = false; - let searchHighlightsOverlay = null; // 当前搜索高亮 overlay 元素引用 - - // ===== Character Width Measurement (#1) ===== - const _charWidthCanvas = document.createElement('canvas'); - const _charWidthCtx = _charWidthCanvas.getContext('2d'); - let _cachedCharWidth = null; - function getCharWidth() { - if (_cachedCharWidth !== null) return _cachedCharWidth; - const style = getComputedStyle(editor); - _charWidthCtx.font = `${style.fontSize} ${style.fontFamily}`; - _cachedCharWidth = _charWidthCtx.measureText('M').width; - return _cachedCharWidth; - } - // Recalculate on font/theme change - new MutationObserver(() => { _cachedCharWidth = null; }).observe(document.documentElement, { attributes: true, attributeFilter: ['class'] }); - - // ===== Actual Line Height Measurement ===== - // textarea 的实际渲染行高可能与 CSS line-height 计算值有微小差异, - // 导致行号面板与编辑器内容逐渐错位。动态测量真实行高来解决。 - let _cachedLineHeight = null; - function getLineHeight() { - if (_cachedLineHeight !== null) return _cachedLineHeight; - const style = getComputedStyle(editor); - const measure = document.createElement('div'); - measure.style.cssText = `position:absolute;visibility:hidden;font-family:${style.fontFamily};font-size:${style.fontSize};line-height:${style.lineHeight};white-space:pre;width:0;`; - measure.textContent = 'X'; - document.body.appendChild(measure); - const singleHeight = measure.offsetHeight; - measure.textContent = 'X\nX'; - const doubleHeight = measure.offsetHeight; - document.body.removeChild(measure); - _cachedLineHeight = doubleHeight - singleHeight || 20.8; - return _cachedLineHeight; - } - // 字体/主题变化时清除缓存 - new MutationObserver(() => { _cachedLineHeight = null; _cachedCharWidth = null; }).observe(document.documentElement, { attributes: true, attributeFilter: ['class'] }); - - // ===== Toast Notification (#5) ===== - function showToast(message, duration) { - duration = duration || 3000; - let toast = document.getElementById('toast-notification'); - if (!toast) { - toast = document.createElement('div'); - toast.id = 'toast-notification'; - document.getElementById('app').appendChild(toast); - } - toast.textContent = message; - toast.classList.add('show'); - clearTimeout(toast._timer); - toast._timer = setTimeout(() => toast.classList.remove('show'), duration); - } - - // ===== Tab Object ===== - function createTab(filePath, content) { - const id = ++tabIdCounter; - return { - id, - filePath: filePath || null, - content: content || '', - isModified: false, - scrollTop: 0, - scrollLeft: 0, - selectionStart: 0, - selectionEnd: 0, - previewScrollTop: 0 - }; - } - - // ===== localStorage Helpers ===== - function loadSettings() { - try { - return JSON.parse(localStorage.getItem('marklite-settings') || '{}'); - } catch { return {}; } - } - - function saveSetting(key, value) { - try { - const s = loadSettings(); - s[key] = value; - localStorage.setItem('marklite-settings', JSON.stringify(s)); - } catch { /* ignore */ } - } - - // ===== Dark Mode ===== - function initDarkMode() { - const settings = loadSettings(); - const iconDark = document.getElementById('icon-dark'); - const iconLight = document.getElementById('icon-light'); - - function apply(isDark) { - document.documentElement.classList.toggle('dark', isDark); - iconDark.style.display = isDark ? 'none' : ''; - iconLight.style.display = isDark ? '' : 'none'; - } - - // Respect system preference if no saved setting - const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; - apply(settings.darkMode !== undefined ? !!settings.darkMode : prefersDark); - - btnDark.addEventListener('click', () => { - const isDark = !document.documentElement.classList.contains('dark'); - apply(isDark); - saveSetting('darkMode', isDark); - }); - } - - // ===== Initialize marked.js ===== - function initMarked() { - if (typeof marked !== 'undefined') { - const renderer = new marked.Renderer(); - // 兼容 marked v4(positional args)和 v9+(token object) - renderer.code = function (codeOrToken, legacyLang) { - const text = (typeof codeOrToken === 'object' && codeOrToken !== null) - ? codeOrToken.text - : codeOrToken; - const lang = (typeof codeOrToken === 'object' && codeOrToken !== null) - ? codeOrToken.lang - : legacyLang; - let highlighted = text; - if (typeof hljs !== 'undefined') { - if (lang && hljs.getLanguage(lang)) { - try { highlighted = hljs.highlight(text, { language: lang }).value; } catch (e) { /* fallback */ } - } else { - try { highlighted = hljs.highlightAuto(text).value; } catch (e) { /* fallback */ } - } - } - const langClass = lang ? ` language-${lang}` : ''; - return `
    ${highlighted}
    `; - }; - // 处理相对路径图片 → file:// URL - renderer.image = function (hrefOrToken, title, text) { - const href = (typeof hrefOrToken === 'object' && hrefOrToken !== null) - ? hrefOrToken.href - : hrefOrToken; - const alt = (typeof hrefOrToken === 'object' && hrefOrToken !== null) - ? hrefOrToken.text - : text; - const titleAttr = (typeof hrefOrToken === 'object' && hrefOrToken !== null) - ? hrefOrToken.title - : title; - let src = href; - // 相对路径转绝对路径 - if (src && !src.startsWith('http://') && !src.startsWith('https://') && !src.startsWith('data:') && !src.startsWith('file://')) { - const tab = getActiveTab(); - if (tab && tab.filePath) { - const dir = tab.filePath.replace(/[/\\][^/\\]+$/, ''); - // 简单路径拼接(不依赖 require('path')) - const sep = dir.includes('\\') ? '\\' : '/'; - src = 'file://' + (dir + sep + src).replace(/\\/g, '/'); - } - } - const titleStr = titleAttr ? ` title="${titleAttr}"` : ''; - return `${alt}`; - }; - marked.setOptions({ gfm: true, breaks: true, pedantic: false }); - marked.use({ renderer }); - } - } - - // ===== HTML Sanitizer ===== - // 移除事件处理器、危险元素和 javascript: 协议,防止 XSS - const DANGEROUS_TAGS = new Set([ - 'script', 'iframe', 'object', 'embed', 'applet', 'form', - 'base', 'meta', 'link', 'style' - ]); - const DANGEROUS_ATTRS = new Set([ - 'onabort', 'onanimationend', 'onanimationiteration', 'onanimationstart', - 'onauxclick', 'onbeforecopy', 'onbeforecut', 'onbeforepaste', 'onblur', - 'oncancel', 'oncanplay', 'oncanplaythrough', 'onchange', 'onclick', - 'onclose', 'oncontextmenu', 'oncopy', 'oncuechange', 'oncut', - 'ondblclick', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', - 'ondragover', 'ondragstart', 'ondrop', 'ondurationchange', 'onemptied', - 'onended', 'onerror', 'onfocus', 'onfocusin', 'onfocusout', - 'onfullscreenchange', 'onfullscreenerror', 'ongotpointercapture', - 'oninput', 'oninvalid', 'onkeydown', 'onkeypress', 'onkeyup', - 'onload', 'onloadeddata', 'onloadedmetadata', 'onloadstart', - 'onlostpointercapture', 'onmousedown', 'onmouseenter', 'onmouseleave', - 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', - 'onpaste', 'onpause', 'onplay', 'onplaying', 'onpointercancel', - 'onpointerdown', 'onpointerenter', 'onpointerleave', 'onpointermove', - 'onpointerout', 'onpointerover', 'onpointerup', 'onprogress', - 'onratechange', 'onreset', 'onresize', 'onscroll', 'onsearch', - 'onseeked', 'onseeking', 'onselect', 'onselectionchange', - 'onselectstart', 'onshow', 'onstalled', 'onsubmit', 'onsuspend', - 'ontimeupdate', 'ontoggle', 'ontouchcancel', 'ontouchend', - 'ontouchmove', 'ontouchstart', 'ontransitionend', 'onvolumechange', - 'onwaiting', 'onwheel', 'onanimationend', 'oncontentvisibilityautostatechange', - 'onscrollend', 'onscrollsnapchange', 'onscrollsnapchanging' - ]); - - function sanitizeHTML(html) { - // 用 DOMParser 解析(不会执行脚本) - const doc = new DOMParser().parseFromString(html, 'text/html'); - const walker = document.createTreeWalker(doc.body, NodeFilter.SHOW_ELEMENT); - const toRemove = []; - - while (walker.nextNode()) { - const el = walker.currentNode; - const tag = el.tagName.toLowerCase(); - - // 移除危险元素 - if (DANGEROUS_TAGS.has(tag)) { - toRemove.push(el); - continue; - } - - // 移除危险属性(on* 事件处理器 + javascript: 协议) - for (const attr of Array.from(el.attributes)) { - const name = attr.name.toLowerCase(); - if (DANGEROUS_ATTRS.has(name) || name.startsWith('on')) { - el.removeAttribute(attr.name); - } else if ( - (name === 'href' || name === 'action' || name === 'formaction' || name === 'xlink:href') && - /^\s*javascript:/i.test(attr.value) - ) { - el.removeAttribute(attr.name); - } else if (name === 'style' && /expression\s*\(|url\s*\(\s*['"]?\s*javascript:/i.test(attr.value)) { - el.removeAttribute(attr.name); - } - } - } - - // 批量移除危险元素 - for (const el of toRemove) { - el.parentNode.removeChild(el); - } - - return doc.body.innerHTML; - } - - // ===== Markdown Rendering ===== - function renderMarkdown(text) { - if (typeof marked === 'undefined') { - preview.textContent = '错误: Markdown 解析库未加载'; - preview.style.color = 'red'; - return; - } - try { - const raw = marked.parse(text); - preview.innerHTML = sanitizeHTML(raw); - preview.style.color = ''; - } catch (e) { - preview.textContent = '渲染错误: ' + e.message; - preview.style.color = 'red'; - } - } - - // Intercept link clicks in preview — open in system browser - function initPreviewLinks() { - preview.addEventListener('click', (e) => { - const link = e.target.closest('a'); - if (!link) return; - e.preventDefault(); - const href = link.getAttribute('href'); - if (!href) return; - // Anchor links: scroll within preview - if (href.startsWith('#')) { - const target = preview.querySelector(href); - if (target) target.scrollIntoView({ behavior: 'smooth' }); - return; - } - // Only allow http/https protocols - try { - const url = new URL(href); - if (url.protocol !== 'http:' && url.protocol !== 'https:') return; - } catch { - // Relative URLs fail new URL(), but we already handled anchors above - return; - } - // External links: open in system browser - if (typeof window.electronAPI !== 'undefined' && window.electronAPI.openExternal) { - window.electronAPI.openExternal(href); - } else { - window.open(href, '_blank', 'noopener'); - } - }); - } - - // ===== Line Numbers ===== - // 快速计算换行符数量,避免 split 产生大数组 - function countNewlines(text) { - let count = 1; - for (let i = 0, len = text.length; i < len; i++) { - if (text.charCodeAt(i) === 10) count++; // '\n' = 0x0A - } - return count; - } - - function updateLineNumbers() { - const count = countNewlines(editor.value); - if (count === lineCountCache) return; - lineCountCache = count; - - // 大文件(>2000 行)时用虚拟化:只渲染可视区域的行号 - const LARGE_FILE_THRESHOLD = 2000; - if (count > LARGE_FILE_THRESHOLD) { - renderVirtualLineNumbers(count); - } else { - // 小文件:一次性生成全部行号(使用数组 join 比字符串拼接快) - const arr = new Array(count); - for (let i = 0; i < count; i++) { - arr[i] = '
    ' + (i + 1) + '
    '; - } - lineNumbers.innerHTML = arr.join(''); - } - } - - // 虚拟化行号:只渲染当前可视区域附近的行号 - function renderVirtualLineNumbers(totalLines) { - const lineHeight = getLineHeight(); - const scrollTop = editor.scrollTop; - const viewportHeight = editor.clientHeight; - const buffer = 20; // 上下缓冲行数 - - const startLine = Math.max(0, Math.floor(scrollTop / lineHeight) - buffer); - const endLine = Math.min(totalLines, Math.ceil((scrollTop + viewportHeight) / lineHeight) + buffer); - const visibleCount = endLine - startLine; - - // 顶部占位 - const topPadding = startLine * lineHeight; - // 底部占位 - const bottomPadding = (totalLines - endLine) * lineHeight; - - const arr = new Array(visibleCount + 2); - arr[0] = '
    '; - for (let i = 0; i < visibleCount; i++) { - arr[i + 1] = '
    ' + (startLine + i + 1) + '
    '; - } - arr[visibleCount + 1] = '
    '; - lineNumbers.innerHTML = arr.join(''); - } - - // ===== Cursor Position ===== - function updateCursorPosition() { - const text = editor.value; - const pos = editor.selectionStart; - const textBefore = text.substring(0, pos); - const lines = textBefore.split('\n'); - statusCursor.textContent = `行 ${lines.length}, 列 ${lines[lines.length - 1].length + 1}`; - } - - // ===== File Size ===== - function formatBytes(bytes) { - if (bytes < 1024) return bytes + ' B'; - if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; - return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; - } - - function updateFileSize() { - const bytes = new Blob([editor.value]).size; - statusSize.textContent = formatBytes(bytes); - statusSizeDivider.classList.add('visible'); - } - - // ===== Scroll Sync ===== - let previewPositions = null; - let lineToPreviewMap = null; // 行号 → 预览像素位置的映射 - - function cachePreviewPositions() { - previewPositions = []; - for (let i = 0; i < preview.children.length; i++) { - previewPositions.push(preview.children[i].offsetTop); - } - // 构建行号→预览位置的映射表 - buildLineToPreviewMap(); - } - - // 通过分析原始 Markdown 文本,建立编辑器行号到预览 DOM 位置的映射 - function buildLineToPreviewMap() { - if (!previewPositions || previewPositions.length === 0) { - lineToPreviewMap = null; - return; - } - - const text = editor.value; - const lines = text.split('\n'); - const totalLines = lines.length; - - // 找出每个"块级元素"在编辑器中的起始行 - // 块级元素:标题、段落、代码块、列表、引用、表格、水平线 - const blockStartLines = []; - let inCodeBlock = false; - - for (let i = 0; i < totalLines; i++) { - const line = lines[i]; - const trimmed = line.trimStart(); - - // 围栏代码块边界 - if (trimmed.startsWith('```')) { - if (!inCodeBlock) { - blockStartLines.push(i); - inCodeBlock = true; - } else { - inCodeBlock = false; - } - continue; - } - - if (inCodeBlock) continue; - - // 块级元素起始行 - if ( - trimmed.startsWith('#') || // 标题 - trimmed.startsWith('- ') || // 无序列表 - trimmed.startsWith('* ') || // 无序列表 - trimmed.startsWith('+ ') || // 无序列表 - /^\d+\.\s/.test(trimmed) || // 有序列表 - trimmed.startsWith('> ') || // 引用 - trimmed.startsWith('|') || // 表格 - trimmed.startsWith('---') || // 水平线 - trimmed.startsWith('***') || // 水平线 - trimmed.startsWith('___') || // 水平线 - (trimmed === '' && i > 0 && lines[i - 1].trim() === '') // 连续空行=段落分隔 - ) { - blockStartLines.push(i); - } - } - - // 去重并排序 - const uniqueStartsArr = [...new Set(blockStartLines)].sort((a, b) => a - b); - const uniqueStartsSet = new Set(uniqueStartsArr); - - // 将编辑器行号映射到预览 DOM 位置 - // 每个块的起始行对应一个预览元素,用线性插值填充中间行 - lineToPreviewMap = new Float32Array(totalLines); - - if (uniqueStartsArr.length === 0) { - // 没有找到块边界,回退到线性映射 - for (let i = 0; i < totalLines; i++) { - lineToPreviewMap[i] = (i / Math.max(1, totalLines - 1)) * previewPositions[previewPositions.length - 1]; - } - return; - } - - // 将块起始行映射到预览 DOM 索引 - const domCount = previewPositions.length; - for (let i = 0; i < uniqueStartsArr.length; i++) { - const lineIdx = uniqueStartsArr[i]; - const domIdx = Math.min(Math.floor((i / uniqueStartsArr.length) * domCount), domCount - 1); - lineToPreviewMap[lineIdx] = previewPositions[domIdx]; - } - - // 线性插值填充所有行 - for (let i = 0; i < totalLines; i++) { - if (lineToPreviewMap[i] !== 0 && uniqueStartsSet.has(i)) continue; - - // 找到前后最近的已映射行 - let prevLine = -1, nextLine = -1; - for (let j = i - 1; j >= 0; j--) { - if (lineToPreviewMap[j] !== 0 || uniqueStartsSet.has(j)) { prevLine = j; break; } - } - for (let j = i + 1; j < totalLines; j++) { - if (lineToPreviewMap[j] !== 0 || uniqueStartsSet.has(j)) { nextLine = j; break; } - } - - if (prevLine === -1 && nextLine === -1) { - lineToPreviewMap[i] = 0; - } else if (prevLine === -1) { - lineToPreviewMap[i] = lineToPreviewMap[nextLine]; - } else if (nextLine === -1) { - lineToPreviewMap[i] = lineToPreviewMap[prevLine]; - } else { - // 线性插值 - const ratio = (i - prevLine) / (nextLine - prevLine); - lineToPreviewMap[i] = lineToPreviewMap[prevLine] + ratio * (lineToPreviewMap[nextLine] - lineToPreviewMap[prevLine]); - } - } - } - - function syncScroll() { - if (viewMode !== 'split') return; - const lineHeight = getLineHeight(); - const scrollTop = editor.scrollTop; - const topLine = Math.floor(scrollTop / lineHeight); - - if (!previewPositions || previewPositions.length === 0) cachePreviewPositions(); - if (!previewPositions || previewPositions.length === 0) return; - - // 使用行号→预览位置映射表 - if (lineToPreviewMap && topLine >= 0 && topLine < lineToPreviewMap.length) { - previewPanel.scrollTop = lineToPreviewMap[topLine]; - } else { - // fallback: 线性比例映射 - const totalLines = editor.value.split('\n').length; - const ratio = totalLines > 1 ? topLine / (totalLines - 1) : 0; - const targetIndex = Math.min(Math.floor(ratio * previewPositions.length), previewPositions.length - 1); - if (targetIndex >= 0 && previewPositions[targetIndex] !== undefined) { - previewPanel.scrollTop = previewPositions[targetIndex]; - } - } - } - - // ===== Schedule Update ===== - function scheduleUpdate() { - if (updateTimer) clearTimeout(updateTimer); - updateTimer = setTimeout(() => { - renderMarkdown(editor.value); - updateLineNumbers(); - updateFileSize(); - cachePreviewPositions(); - _cachedLineHeight = null; // 内容变化后重新测量行高 - }, 150); - } - - // ===== Helper ===== - function getFileName(filePath) { - return filePath.split(/[/\\]/).pop(); - } - - // ===== Tab UI ===== - function renderTabBar() { - tabList.innerHTML = ''; - for (const tab of tabs) { - const el = document.createElement('div'); - el.className = 'tab-item' + (tab.id === activeTabId ? ' active' : '') + (tab.isModified ? ' modified' : ''); - el.dataset.tabId = tab.id; - - const name = document.createElement('span'); - name.className = 'tab-name'; - name.textContent = tab.filePath ? getFileName(tab.filePath) : '未命名'; - el.appendChild(name); - - const close = document.createElement('button'); - close.className = 'tab-close'; - close.innerHTML = ''; - close.addEventListener('click', (e) => { - e.stopPropagation(); - closeTab(tab.id); - }); - el.appendChild(close); - - el.addEventListener('click', () => switchToTab(tab.id)); - tabList.appendChild(el); - } - } - - function updateTitle() { - const tab = getActiveTab(); - if (tab) { - const name = tab.filePath ? getFileName(tab.filePath) : '未命名'; - const mod = tab.isModified ? ' *' : ''; - document.title = `MarkLite - ${name}${mod}`; - statusText.textContent = name; - } else { - document.title = 'MarkLite'; - statusText.textContent = '就绪'; - } - } - - // ===== Sidebar Highlight ===== - // Update sidebar active highlight without re-rendering the entire tree - function updateSidebarHighlight() { - const tab = getActiveTab(); - const activePath = tab ? tab.filePath : null; - - // No folder open: manage independent files section - if (!currentRootPath) { - sidebarTree.innerHTML = ''; - const indepSection = renderIndependentFiles(); - if (indepSection) sidebarTree.appendChild(indepSection); - return; - } - - // Folder is open: re-render independent files section (files may have been added/removed) - const oldSection = sidebarTree.querySelector('.independent-files-section'); - const newSection = renderIndependentFiles(); - if (oldSection) oldSection.remove(); - if (newSection) sidebarTree.insertBefore(newSection, sidebarTree.firstChild); - - // Update folder tree items - const treeItems = sidebarTree.querySelectorAll('.tree-item:not(.independent-file-item)'); - treeItems.forEach(item => { - const itemPath = item.dataset.path; - if (itemPath) { - item.classList.toggle('active', itemPath === activePath); - } - }); - } - - // ===== Tab Operations ===== - function getActiveTab() { - return tabs.find(t => t.id === activeTabId) || null; - } - - function getTabIndex(tabId) { - return tabs.findIndex(t => t.id === tabId); - } - - // Save current editor state into the active tab - function saveCurrentTabState() { - const tab = getActiveTab(); - if (!tab) return; - tab.content = editor.value; - tab.scrollTop = editor.scrollTop; - tab.scrollLeft = editor.scrollLeft; - tab.selectionStart = editor.selectionStart; - tab.selectionEnd = editor.selectionEnd; - tab.previewScrollTop = previewPanel.scrollTop; - } - - // Load a tab's state into the editor - function loadTabState(tab) { - // 使用 execCommand('insertText') 替换内容,保留 undo/redo 历史 - // setRangeText 会清空 undo 栈,所以此处必须用 execCommand - _loadingTab = true; - editor.focus(); - editor.select(); - const inserted = document.execCommand('insertText', false, tab.content); - if (!inserted) { - // execCommand 被禁用时的 fallback(会丢失 undo 历史) - editor.value = tab.content; - } - lineCountCache = 0; - updateLineNumbers(); - renderMarkdown(tab.content); - updateFileSize(); - cachePreviewPositions(); - - // Restore scroll/selection on next frame - requestAnimationFrame(() => { - editor.scrollTop = tab.scrollTop; - editor.scrollLeft = tab.scrollLeft; - lineNumbers.scrollTop = tab.scrollTop; - editor.setSelectionRange(tab.selectionStart, tab.selectionEnd); - previewPanel.scrollTop = tab.previewScrollTop; - updateCursorPosition(); - }); - - // Update modified state - setModified(tab.isModified); - _loadingTab = false; - - // Notify main process about active file - if (typeof window.electronAPI !== 'undefined') { - window.electronAPI.tabSwitched(tab.filePath); - } - } - - function setModified(modified) { - const tab = getActiveTab(); - if (tab) { - tab.isModified = modified; - // Toggle class directly instead of rebuilding entire tab bar - const tabEl = tabList.querySelector(`.tab-item[data-tab-id="${tab.id}"]`); - if (tabEl) tabEl.classList.toggle('modified', modified); - } - updateTitle(); - } - - // Create a new tab and switch to it - function createNewTab(filePath, content) { - // Check if file is already open - if (filePath) { - const existing = tabs.find(t => t.filePath === filePath); - if (existing) { - switchToTab(existing.id); - return existing; - } - } - - const tab = createTab(filePath, content); - tabs.push(tab); - switchToTab(tab.id); - return tab; - } - - // Switch to a specific tab - function switchToTab(tabId) { - if (tabId === activeTabId) return; - - // Save current state - saveCurrentTabState(); - - // MRU: record previous tab before switching - if (activeTabId) { - mruTabStack = mruTabStack.filter(id => id !== activeTabId); - mruTabStack.unshift(activeTabId); - } - - // Switch - activeTabId = tabId; - const tab = getActiveTab(); - if (!tab) return; - - loadTabState(tab); - renderTabBar(); - updateTitle(); - updateSidebarHighlight(); - welcomeScreen.classList.add('hidden'); - } - - // Close a tab - function closeTab(tabId) { - const index = getTabIndex(tabId); - if (index === -1) return; - - const tab = tabs[index]; - - // If modified, confirm - if (tab.isModified) { - const name = tab.filePath ? getFileName(tab.filePath) : '未命名'; - if (!confirm(`"${name}" 尚未保存,确定要关闭吗?`)) return; - } - - // Remove tab - tabs.splice(index, 1); - // Clean MRU stack - mruTabStack = mruTabStack.filter(id => id !== tabId); - - // If we closed the active tab, switch to another - if (tabId === activeTabId) { - if (tabs.length === 0) { - // No tabs left - show welcome screen - activeTabId = null; - editor.value = ''; - preview.innerHTML = ''; - lineNumbers.innerHTML = ''; - lineCountCache = 0; - statusSize.textContent = ''; - statusSizeDivider.classList.remove('visible'); - welcomeScreen.classList.remove('hidden'); - document.title = 'MarkLite'; - statusText.textContent = '就绪'; - if (typeof window.electronAPI !== 'undefined') { - window.electronAPI.tabSwitched(null); - } - } else { - // Switch to nearest tab - const newIndex = Math.min(index, tabs.length - 1); - activeTabId = tabs[newIndex].id; - loadTabState(tabs[newIndex]); - } - } - - renderTabBar(); - updateTitle(); - updateSidebarHighlight(); - } - - // ===== File Size Limit ===== - const MAX_FILE_SIZE = 20 * 1024 * 1024; // 20MB - - // ===== File Operations ===== - async function handleOpenFile() { - if (typeof window.electronAPI !== 'undefined') { - const result = await window.electronAPI.openFile(); - if (result && !result.error) { - createNewTab(result.filePath, result.content); - } - } else { - const input = document.createElement('input'); - input.type = 'file'; - input.accept = '.md,.markdown,.txt'; - input.multiple = true; - input.onchange = (e) => { - Array.from(e.target.files).forEach(file => { - const ext = file.name.substring(file.name.lastIndexOf('.')).toLowerCase(); - if (!['.md', '.markdown', '.txt'].includes(ext)) return; - if (file.size > MAX_FILE_SIZE) { - alert(`"${file.name}" 过大(${formatBytes(file.size)}),暂不支持超过 20MB 的文件`); - return; - } - const reader = new FileReader(); - reader.onload = (ev) => { - createNewTab(file.name, ev.target.result); - }; - reader.readAsText(file); - }); - }; - input.click(); - } - } - - async function handleSave() { - const tab = getActiveTab(); - if (!tab) return; - - if (typeof window.electronAPI !== 'undefined') { - const result = await window.electronAPI.saveFile({ - filePath: tab.filePath, - content: editor.value - }); - if (result.success) { - tab.filePath = result.filePath; - tab.content = editor.value; - tab.isModified = false; - renderTabBar(); - updateTitle(); - updateSidebarHighlight(); - statusText.textContent = '已保存'; - setTimeout(() => updateTitle(), 2000); - } - } else { - const blob = new Blob([editor.value], { type: 'text/markdown' }); - const a = document.createElement('a'); - a.href = URL.createObjectURL(blob); - a.download = tab.filePath || 'untitled.md'; - a.click(); - setTimeout(() => URL.revokeObjectURL(a.href), 1000); - tab.isModified = false; - renderTabBar(); - updateTitle(); - } - } - - async function handleSaveAs() { - const tab = getActiveTab(); - if (!tab) return; - - if (typeof window.electronAPI !== 'undefined') { - const result = await window.electronAPI.saveFileAs({ content: editor.value }); - if (result.success) { - tab.filePath = result.filePath; - tab.content = editor.value; - tab.isModified = false; - renderTabBar(); - updateTitle(); - updateSidebarHighlight(); - statusText.textContent = '已保存'; - setTimeout(() => updateTitle(), 2000); - } - } else { - handleSave(); - } - } - - // ===== View Mode ===== - function setViewMode(mode) { - viewMode = mode; - const app = document.getElementById('app'); - app.classList.remove('mode-editor', 'mode-preview'); - btnSplit.classList.remove('active'); - btnEditor.classList.remove('active'); - btnPreview.classList.remove('active'); - - switch (mode) { - case 'split': - btnSplit.classList.add('active'); - break; - case 'editor': - btnEditor.classList.add('active'); - app.classList.add('mode-editor'); - break; - case 'preview': - btnPreview.classList.add('active'); - app.classList.add('mode-preview'); - renderMarkdown(editor.value); - break; - } - saveSetting('viewMode', mode); - } - - // ===== Resizer ===== - let isResizing = false; - - function initResizer() { - const settings = loadSettings(); - if (settings.splitRatio) { - editorPanel.style.flex = `0 0 ${settings.splitRatio}%`; - previewPanel.style.flex = `0 0 ${100 - settings.splitRatio}%`; - } - - resizer.addEventListener('mousedown', (e) => { - isResizing = true; - resizer.classList.add('active'); - document.body.style.cursor = 'col-resize'; - document.body.style.userSelect = 'none'; - e.preventDefault(); - }); - - document.addEventListener('mousemove', (e) => { - if (!isResizing) return; - const rect = contentWrapper.getBoundingClientRect(); - const pct = Math.max(20, Math.min(80, ((e.clientX - rect.left) / rect.width) * 100)); - editorPanel.style.flex = `0 0 ${pct}%`; - previewPanel.style.flex = `0 0 ${100 - pct}%`; - saveSetting('splitRatio', pct); - }); - - document.addEventListener('mouseup', () => { - if (isResizing) { - isResizing = false; - resizer.classList.remove('active'); - document.body.style.cursor = ''; - document.body.style.userSelect = ''; - } - }); - } - - // ===== Drag & Drop ===== - function initDragDrop() { - let dragCounter = 0; - - document.addEventListener('dragenter', (e) => { - e.preventDefault(); - e.stopPropagation(); - dragCounter++; - dropOverlay.classList.remove('hidden'); - }); - - document.addEventListener('dragleave', (e) => { - e.preventDefault(); - e.stopPropagation(); - dragCounter--; - if (dragCounter === 0) dropOverlay.classList.add('hidden'); - }); - - document.addEventListener('dragover', (e) => { - e.preventDefault(); - e.stopPropagation(); - }); - - document.addEventListener('drop', async (e) => { - e.preventDefault(); - e.stopPropagation(); - dragCounter = 0; - dropOverlay.classList.add('hidden'); - - const files = e.dataTransfer.files; - const allowedExts = ['.md', '.markdown', '.txt']; - let rejected = 0; - for (const file of files) { - const filePath = file.path; - const ext = filePath ? filePath.substring(filePath.lastIndexOf('.')).toLowerCase() : ''; - if (!allowedExts.includes(ext)) { rejected++; continue; } - // Electron 主进程已有文件大小检查,此处为浏览器模式兜底 - if (file.size > MAX_FILE_SIZE) { - showToast(`"${file.name}" 过大(${formatBytes(file.size)}),暂不支持超过 20MB 的文件`); - continue; - } - if (filePath && typeof window.electronAPI !== 'undefined') { - const result = await window.electronAPI.readFile(filePath); - if (result.success) { - createNewTab(filePath, result.content); - } - } else { - const reader = new FileReader(); - reader.onload = (ev) => createNewTab(file.name, ev.target.result); - reader.readAsText(file); - } - } - if (rejected > 0) { - showToast(`仅支持 .md / .markdown / .txt 文件,已忽略 ${rejected} 个文件`); - } - }); - } - - // ===== Keyboard Shortcuts ===== - function initKeyboard() { - document.addEventListener('keydown', (e) => { - if (e.ctrlKey && e.key === 'o') { e.preventDefault(); handleOpenFile(); } - if (e.ctrlKey && e.key === 's' && !e.shiftKey) { e.preventDefault(); handleSave(); } - if (e.ctrlKey && e.shiftKey && e.key === 'S') { e.preventDefault(); handleSaveAs(); } - if (e.ctrlKey && e.key === '1') { e.preventDefault(); setViewMode('split'); } - if (e.ctrlKey && e.key === '2') { e.preventDefault(); setViewMode('editor'); } - if (e.ctrlKey && e.key === '3') { e.preventDefault(); setViewMode('preview'); } - if (e.ctrlKey && e.key === 't') { e.preventDefault(); createNewTab(null, ''); } - if (e.ctrlKey && e.key === 'w') { e.preventDefault(); if (activeTabId) closeTab(activeTabId); } - // Ctrl+Tab / Ctrl+Shift+Tab to cycle tabs (MRU order) - if (e.ctrlKey && e.key === 'Tab') { - e.preventDefault(); - if (tabs.length > 1) { - if (e.shiftKey) { - // Ctrl+Shift+Tab: go back in MRU history - if (mruTabStack.length > 0) { - const targetId = mruTabStack.shift(); - // Verify target still exists - if (tabs.find(t => t.id === targetId)) { - switchToTab(targetId); - } - } - } else { - // Ctrl+Tab: forward in MRU (just switch to next in array as fallback) - const idx = getTabIndex(activeTabId); - const next = (idx + 1) % tabs.length; - switchToTab(tabs[next].id); - } - } - } - // Search & Replace - if (e.ctrlKey && e.key === 'f') { e.preventDefault(); openSearch(false); } - if (e.ctrlKey && e.key === 'h') { e.preventDefault(); openSearch(true); } - if (e.key === 'Escape' && !searchBar.classList.contains('hidden')) { e.preventDefault(); closeSearch(); } - if (e.key === 'Enter' && document.activeElement === searchInput) { - e.preventDefault(); - e.shiftKey ? findPrev() : findNext(); - } - if (e.altKey && e.key === 'c') { e.preventDefault(); toggleSearchOption('case'); } - if (e.altKey && e.key === 'r') { e.preventDefault(); toggleSearchOption('regex'); } - if (e.ctrlKey && e.shiftKey && e.key === 'H') { e.preventDefault(); replaceAll(); } - if (e.ctrlKey && e.shiftKey && e.key === 'G') { e.preventDefault(); replaceCurrent(); } - }); - } - - // ===== Tab key support ===== - function initEditorTab() { - editor.addEventListener('keydown', (e) => { - if (e.key === 'Tab') { - e.preventDefault(); - // setRangeText 是标准 API,execCommand 已废弃但能保留 undo 历史 - const start = editor.selectionStart; - const end = editor.selectionEnd; - if (start !== end) { - // 多行选区:批量缩进 - const lines = editor.value.substring(start, end).split('\n'); - const indented = lines.map(line => ' ' + line).join('\n'); - editor.setRangeText(indented, start, end, 'end'); - } else { - // 单光标:插入 4 空格 - editor.setRangeText(' ', start, end, 'end'); - } - scheduleUpdate(); - } - }); - } - - // ===== External File Modification ===== - function initFileWatch() { - if (typeof window.electronAPI === 'undefined') return; - - window.electronAPI.onExternalModification((filePath) => { - // Only show banner if the modified file is the active tab - const tab = getActiveTab(); - if (tab && tab.filePath === filePath) { - modifiedBanner.classList.remove('hidden'); - } - }); - - btnReload.addEventListener('click', async () => { - const tab = getActiveTab(); - if (!tab || !tab.filePath) return; - const result = await window.electronAPI.reloadFile(); - if (result.success) { - _loadingTab = true; - editor.value = result.content; - _loadingTab = false; - tab.content = result.content; - tab.isModified = false; - setModified(false); - lineCountCache = 0; - updateLineNumbers(); - renderMarkdown(result.content); - updateCursorPosition(); - updateFileSize(); - cachePreviewPositions(); - renderTabBar(); - updateTitle(); - } - modifiedBanner.classList.add('hidden'); - }); - - btnDismiss.addEventListener('click', () => { - modifiedBanner.classList.add('hidden'); - }); - } - - // ===== Unsaved Changes Warning ===== - function initUnsavedWarning() { - const hasUnsaved = () => tabs.some(t => t.isModified); - - if (typeof window.electronAPI === 'undefined') { - window.addEventListener('beforeunload', (e) => { - if (hasUnsaved()) { e.preventDefault(); e.returnValue = ''; } - }); - return; - } - - window.electronAPI.onConfirmClose(() => { - if (!hasUnsaved()) { - window.electronAPI.forceClose(); - return; - } - const shouldClose = confirm('有文件尚未保存,确定要关闭吗?'); - if (shouldClose) { - window.electronAPI.forceClose(); - } else { - window.electronAPI.cancelClose(); - } - }); - } - - // ===== Event Listeners ===== - function initEventListeners() { - editor.addEventListener('input', () => { - if (_loadingTab) { scheduleUpdate(); return; } // 加载中不标记修改 - const tab = getActiveTab(); - if (tab) { - tab.isModified = true; - setModified(true); - } - scheduleUpdate(); - }); - - editor.addEventListener('scroll', () => { - syncScroll(); - // 行号跟随编辑器滚动 - lineNumbers.scrollTop = editor.scrollTop; - // 大文件滚动时重新渲染虚拟行号 - if (lineCountCache > 2000) { - renderVirtualLineNumbers(lineCountCache); - } - // 搜索高亮跟随编辑器滚动更新位置 - if (searchHighlightsOverlay) { - searchHighlightsOverlay.style.top = -editor.scrollTop + 'px'; - } - }); - editor.addEventListener('click', updateCursorPosition); - editor.addEventListener('keyup', updateCursorPosition); - editor.addEventListener('select', updateCursorPosition); - - btnOpen.addEventListener('click', handleOpenFile); - btnSave.addEventListener('click', handleSave); - btnSplit.addEventListener('click', () => setViewMode('split')); - btnEditor.addEventListener('click', () => setViewMode('editor')); - btnPreview.addEventListener('click', () => setViewMode('preview')); - btnNewTab.addEventListener('click', () => createNewTab(null, '')); - - btnWelcomeOpen.addEventListener('click', handleOpenFile); - btnWelcomeNew.addEventListener('click', () => createNewTab(null, '')); - - if (typeof window.electronAPI !== 'undefined') { - // Remove old listeners first to prevent stacking - window.electronAPI.removeAllListeners('file:openInTab'); - window.electronAPI.removeAllListeners('menu:save'); - window.electronAPI.removeAllListeners('menu:saveAs'); - window.electronAPI.removeAllListeners('menu:viewMode'); - - // Main process sends file to open in a new tab - window.electronAPI.onFileOpenInTab((data) => { - createNewTab(data.filePath, data.content); - }); - - window.electronAPI.onMenuSave(() => handleSave()); - window.electronAPI.onMenuSaveAs(() => handleSaveAs()); - window.electronAPI.onViewModeChange((mode) => setViewMode(mode)); - } - } - - // ===== Search & Replace ===== - function openSearch(showReplace) { - searchBar.classList.remove('hidden'); - replaceRow.classList.toggle('hidden', !showReplace); - btnToggleReplace.classList.toggle('expanded', showReplace); - searchInput.focus(); - // Pre-fill with selected text - const selected = editor.value.substring(editor.selectionStart, editor.selectionEnd); - if (selected && !selected.includes('\n')) { - searchInput.value = selected; - } - doSearch(); - } - - function closeSearch() { - searchBar.classList.add('hidden'); - replaceRow.classList.add('hidden'); - btnToggleReplace.classList.remove('expanded'); - clearHighlights(); - searchMatches = []; - searchIndex = -1; - searchCount.textContent = ''; - editor.focus(); - } - - function toggleSearchOption(type) { - if (type === 'case') { - searchCaseSensitive = !searchCaseSensitive; - btnCase.classList.toggle('active', searchCaseSensitive); - } else { - searchUseRegex = !searchUseRegex; - btnRegex.classList.toggle('active', searchUseRegex); - } - doSearch(); - } - - function doSearch() { - clearHighlights(); - const text = searchInput.value; - if (!text) { - searchMatches = []; - searchIndex = -1; - searchCount.textContent = ''; - return; - } - searchMatches = findMatches(text); - if (searchMatches.length > 0) { - // Find the match closest to cursor - const cursor = editor.selectionStart; - searchIndex = searchMatches.findIndex(m => m.start >= cursor); - if (searchIndex === -1) searchIndex = 0; - scrollToMatch(searchIndex); - } else { - searchIndex = -1; - } - searchCount.textContent = searchMatches.length > 0 - ? `${searchIndex + 1}/${searchMatches.length}` - : '无结果'; - highlightMatches(); - } - - function findMatches(text) { - const content = editor.value; - const matches = []; - if (searchUseRegex) { - try { - const flags = searchCaseSensitive ? 'g' : 'gi'; - const regex = new RegExp(text, flags); - let m; - while ((m = regex.exec(content)) !== null) { - matches.push({ start: m.index, end: m.index + m[0].length }); - if (m[0].length === 0) regex.lastIndex++; - } - } catch { /* invalid regex */ } - } else { - const haystack = searchCaseSensitive ? content : content.toLowerCase(); - const needle = searchCaseSensitive ? text : text.toLowerCase(); - let idx = 0; - while ((idx = haystack.indexOf(needle, idx)) !== -1) { - matches.push({ start: idx, end: idx + needle.length }); - idx += needle.length; - } - } - return matches; - } - - // ===== Search Highlight Cache ===== - let cachedLineStarts = null; - let cachedLineStartsContent = null; - - // 二分查找:返回 pos 所在行号(O(log N) 替代原来的线性扫描 O(N)) - function getLineNumber(pos) { - if (!cachedLineStarts) return 0; - let lo = 0, hi = cachedLineStarts.length - 1; - while (lo < hi) { - const mid = (lo + hi + 1) >> 1; - if (cachedLineStarts[mid] <= pos) lo = mid; else hi = mid - 1; - } - return lo; - } - - function highlightMatches() { - clearHighlights(); - if (searchMatches.length === 0) return; - - const content = editor.value; - const lineHeight = getLineHeight(); - const editorStyle = getComputedStyle(editor); - const paddingTop = parseFloat(editorStyle.paddingTop); - const paddingLeft = parseFloat(editorStyle.paddingLeft); - - // 缓存 lineStarts:内容未变时跳过重建(O(N) → O(1)) - if (cachedLineStartsContent !== content) { - cachedLineStarts = [0]; - for (let i = 0; i < content.length; i++) { - if (content.charCodeAt(i) === 10) cachedLineStarts.push(i + 1); - } - cachedLineStartsContent = content; - } - const lineStarts = cachedLineStarts; - - function posToXY(pos) { - const line = getLineNumber(pos); - const col = pos - lineStarts[line]; - return { - top: line * lineHeight + paddingTop, - left: col * getCharWidth() + paddingLeft - }; - } - - const overlay = document.createElement('div'); - overlay.id = 'search-highlights'; - overlay.style.cssText = `position:absolute;top:${-editor.scrollTop}px;left:0;right:0;height:${editor.scrollHeight}px;pointer-events:none;overflow:visible;z-index:1;`; - const wrapper = document.getElementById('editor-wrapper'); - wrapper.style.position = 'relative'; - wrapper.appendChild(overlay); - searchHighlightsOverlay = overlay; - - for (let i = 0; i < searchMatches.length; i++) { - const m = searchMatches[i]; - const startPos = posToXY(m.start); - const endPos = posToXY(m.end); - const isCurrent = i === searchIndex; - const div = document.createElement('div'); - div.className = 'search-hl' + (isCurrent ? ' current' : ''); - div.style.cssText = `position:absolute;top:${startPos.top}px;left:${startPos.left}px;height:${lineHeight}px;width:${Math.max(endPos.left - startPos.left, 8)}px;`; - overlay.appendChild(div); - } - } - - function clearHighlights() { - const old = document.getElementById('search-highlights'); - if (old) old.remove(); - searchHighlightsOverlay = null; - } - - function scrollToMatch(index) { - if (index < 0 || index >= searchMatches.length) return; - searchIndex = index; - const m = searchMatches[index]; - editor.setSelectionRange(m.start, m.end); - // 复用缓存的 lineStarts + 二分查找(替代逐字符 O(N) 扫描) - const lineHeight = getLineHeight(); - if (!cachedLineStarts) { - const content = editor.value; - cachedLineStarts = [0]; - for (let i = 0; i < content.length; i++) { - if (content.charCodeAt(i) === 10) cachedLineStarts.push(i + 1); - } - cachedLineStartsContent = content; - } - const line = getLineNumber(m.start); - const matchTop = line * lineHeight; - const viewTop = editor.scrollTop; - const viewBottom = viewTop + editor.clientHeight; - if (matchTop < viewTop + 40 || matchTop > viewBottom - 40) { - editor.scrollTop = matchTop - editor.clientHeight / 2; - } - searchCount.textContent = `${index + 1}/${searchMatches.length}`; - highlightMatches(); - } - - function findNext() { - if (searchMatches.length === 0) return; - scrollToMatch((searchIndex + 1) % searchMatches.length); - } - - function findPrev() { - if (searchMatches.length === 0) return; - scrollToMatch((searchIndex - 1 + searchMatches.length) % searchMatches.length); - } - - function replaceCurrent() { - if (searchMatches.length === 0 || searchIndex < 0) return; - const m = searchMatches[searchIndex]; - const replacement = replaceInput.value; - // Use execCommand to preserve undo history - editor.setSelectionRange(m.start, m.end); - document.execCommand('insertText', false, replacement); - // Re-run search - doSearch(); - } - - function replaceAll() { - if (searchMatches.length === 0) return; - const replacement = replaceInput.value; - const content = editor.value; - // 拼接替换后的完整内容 - let newContent = ''; - let lastEnd = 0; - for (let i = searchMatches.length - 1; i >= 0; i--) { - newContent = content.substring(lastEnd, searchMatches[i].start) + replacement + newContent; - lastEnd = searchMatches[i].end; - } - newContent = content.substring(0, searchMatches[0].start) + newContent + content.substring(searchMatches[searchMatches.length - 1].end); - // 使用 select + execCommand 实现:一次原子操作进 undo 栈 - // Ctrl+Z 可一次性撤销全部替换 - editor.focus(); - editor.select(); - document.execCommand('insertText', false, newContent); - doSearch(); - } - - // ===== Sidebar (File Tree) ===== - function initSidebar() { - const settings = loadSettings(); - if (settings.sidebarCollapsed) sidebar.classList.add('collapsed'); - if (settings.sidebarWidth) { - sidebar.style.width = settings.sidebarWidth + 'px'; - } - - // Sidebar resize handle (#10) - const handle = document.createElement('div'); - handle.className = 'sidebar-resize-handle'; - sidebar.appendChild(handle); - let isSidebarResizing = false; - handle.addEventListener('mousedown', (e) => { - isSidebarResizing = true; - document.body.style.cursor = 'col-resize'; - document.body.style.userSelect = 'none'; - e.preventDefault(); - }); - document.addEventListener('mousemove', (e) => { - if (!isSidebarResizing) return; - const newWidth = Math.max(180, Math.min(500, e.clientX)); - sidebar.style.width = newWidth + 'px'; - saveSetting('sidebarWidth', newWidth); - }); - document.addEventListener('mouseup', () => { - if (isSidebarResizing) { - isSidebarResizing = false; - document.body.style.cursor = ''; - document.body.style.userSelect = ''; - } - }); - - btnOpenFolder.addEventListener('click', openFolder); - if (typeof window.electronAPI !== 'undefined') { - let dirRefreshTimer = null; - window.electronAPI.onDirChanged(() => { - if (!currentRootPath) return; - if (dirRefreshTimer) clearTimeout(dirRefreshTimer); - dirRefreshTimer = setTimeout(() => refreshTree(), 300); - }); - } - } - - async function openFolder() { - if (typeof window.electronAPI === 'undefined') return; - openFolderDialog(); - } - - async function openFolderDialog() { - if (typeof window.electronAPI !== 'undefined' && window.electronAPI.openFolderDialog) { - const result = await window.electronAPI.openFolderDialog(); - if (result) { - loadFolder(result); - } - } - } - - async function loadFolder(dirPath) { - if (typeof window.electronAPI === 'undefined') return; - currentRootPath = dirPath; - const result = await window.electronAPI.readDirTree(dirPath); - if (result.success) { - renderTree(result.tree, dirPath); - sidebar.classList.remove('collapsed'); - window.electronAPI.watchDir(dirPath); - } - } - - async function refreshTree() { - if (!currentRootPath) return; - const result = await window.electronAPI.readDirTree(currentRootPath); - if (result.success) { - renderTree(result.tree, currentRootPath); - } - } - - // Track expanded state - const expandedDirs = new Set(); - - function renderTree(tree, rootPath) { - sidebarTree.innerHTML = ''; - const rootNode = { name: getFileName(rootPath) || rootPath, path: rootPath, type: 'dir', children: tree }; - expandedDirs.add(rootPath); - const fragment = document.createDocumentFragment(); - buildTreeDOM(fragment, rootNode, 0); - sidebarTree.appendChild(fragment); - } - - function buildTreeDOM(parent, node, depth) { - const item = document.createElement('div'); - item.className = 'tree-item'; - item.style.paddingLeft = (8 + depth * 16) + 'px'; - - if (node.type === 'dir') { - const isExpanded = expandedDirs.has(node.path); - const arrow = document.createElement('span'); - arrow.className = 'tree-arrow' + (isExpanded ? ' expanded' : ''); - arrow.innerHTML = ''; - item.appendChild(arrow); - - const icon = document.createElement('span'); - icon.className = 'tree-icon'; - icon.innerHTML = ''; - item.appendChild(icon); - - const name = document.createElement('span'); - name.className = 'tree-name'; - name.textContent = node.name; - item.appendChild(name); - - parent.appendChild(item); - - if (isExpanded && node.children) { - for (const child of node.children) { - buildTreeDOM(parent, child, depth + 1); - } - } - - item.addEventListener('click', (e) => { - e.stopPropagation(); - if (expandedDirs.has(node.path)) { - expandedDirs.delete(node.path); - } else { - expandedDirs.add(node.path); - } - renderTree(getTreeData(), currentRootPath); - }); - } else { - // Spacer for alignment (no arrow) - const spacer = document.createElement('span'); - spacer.style.width = '16px'; - spacer.style.flexShrink = '0'; - item.appendChild(spacer); - - const icon = document.createElement('span'); - icon.className = 'tree-icon'; - icon.innerHTML = ''; - item.appendChild(icon); - - const name = document.createElement('span'); - name.className = 'tree-name'; - name.textContent = node.name; - item.appendChild(name); - - // Highlight if this file is open in active tab - const tab = getActiveTab(); - if (tab && tab.filePath === node.path) { - item.classList.add('active'); - } - item.dataset.path = node.path; - - parent.appendChild(item); - - item.addEventListener('click', async (e) => { - e.stopPropagation(); - // Check if already open - const existing = tabs.find(t => t.filePath === node.path); - if (existing) { - switchToTab(existing.id); - } else { - if (typeof window.electronAPI !== 'undefined') { - const result = await window.electronAPI.readFile(node.path); - if (result.success) { - createNewTab(node.path, result.content); - } - } - } - }); - } - } - - // Cache the last tree data for re-render - let lastTreeData = null; - - function getTreeData() { - return lastTreeData || []; - } - - // Build list of open files that are NOT inside currentRootPath - function getIndependentFiles() { - if (!tabs.length) return []; - return tabs.filter(t => { - if (!t.filePath) return false; // skip unnamed tabs - if (!currentRootPath) return true; // no folder open → all files are "independent" - // Check if file is inside the current root path - return !t.filePath.startsWith(currentRootPath); - }); - } - - function renderIndependentFiles() { - const files = getIndependentFiles(); - if (files.length === 0) return null; - - const section = document.createElement('div'); - section.className = 'independent-files-section'; - - const header = document.createElement('div'); - header.className = 'independent-files-header'; - header.textContent = '已打开的文件'; - section.appendChild(header); - - for (const tab of files) { - const item = document.createElement('div'); - item.className = 'tree-item independent-file-item'; - item.style.paddingLeft = '8px'; - item.dataset.path = tab.filePath; - - const icon = document.createElement('span'); - icon.className = 'tree-icon'; - icon.innerHTML = ''; - item.appendChild(icon); - - const name = document.createElement('span'); - name.className = 'tree-name'; - name.textContent = getFileName(tab.filePath); - item.appendChild(name); - - // Mark as modified - if (tab.isModified) { - const dot = document.createElement('span'); - dot.className = 'independent-modified-dot'; - dot.textContent = ' •'; - item.appendChild(dot); - } - - // Highlight if active - if (tab.id === activeTabId) { - item.classList.add('active'); - } - - item.addEventListener('click', (e) => { - e.stopPropagation(); - switchToTab(tab.id); - }); - - section.appendChild(item); - } - return section; - } - - // Override renderTree to cache data, add header, and prepend independent files - const _originalRenderTree = renderTree; - renderTree = function(tree, rootPath) { - lastTreeData = tree; - _originalRenderTree(tree, rootPath); - // Add folder tree header - const folderHeader = document.createElement('div'); - folderHeader.className = 'sidebar-section-header'; - folderHeader.textContent = '文件夹目录树'; - sidebarTree.insertBefore(folderHeader, sidebarTree.firstChild); - // Prepend independent files section - const indepSection = renderIndependentFiles(); - if (indepSection) { - sidebarTree.insertBefore(indepSection, sidebarTree.firstChild); - } - }; - - // ===== Search Bar Init ===== - function initSearchBar() { - searchInput.addEventListener('input', doSearch); - btnToggleReplace.addEventListener('click', () => { - const isVisible = !replaceRow.classList.contains('hidden'); - replaceRow.classList.toggle('hidden'); - btnToggleReplace.classList.toggle('expanded', !isVisible); - if (!isVisible) replaceInput.focus(); - }); - btnCase.addEventListener('click', () => toggleSearchOption('case')); - btnRegex.addEventListener('click', () => toggleSearchOption('regex')); - btnNext.addEventListener('click', findNext); - btnPrev.addEventListener('click', findPrev); - btnSearchClose.addEventListener('click', closeSearch); - btnReplace.addEventListener('click', replaceCurrent); - btnReplaceAll.addEventListener('click', replaceAll); - } - - // ===== Initialize ===== - function init() { - initMarked(); - initDarkMode(); - initResizer(); - initDragDrop(); - initKeyboard(); - initEditorTab(); - initPreviewLinks(); - initEventListeners(); - initFileWatch(); - initUnsavedWarning(); - initSidebar(); - initSearchBar(); - - const settings = loadSettings(); - setViewMode(settings.viewMode || 'split'); - } - - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', init); - } else { - init(); - } -})(); diff --git a/renderer/style.css b/renderer/style.css deleted file mode 100644 index 0de275d..0000000 --- a/renderer/style.css +++ /dev/null @@ -1,1119 +0,0 @@ -/* ===== Reset & Base ===== */ -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -:root { - --primary: #1a73e8; - --primary-light: #e8f0fe; - --primary-dark: #1557b0; - --bg: #ffffff; - --bg-secondary: #f8f9fa; - --bg-tertiary: #f1f3f4; - --text: #333333; - --text-secondary: #5f6368; - --text-tertiary: #9aa0a6; - --border: #e1e4e8; - --border-light: #f0f0f0; - --code-bg: #f6f8fa; - --shadow: 0 1px 3px rgba(0, 0, 0, 0.08); - --shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.1); - --radius: 6px; - --toolbar-height: 44px; - --statusbar-height: 28px; - --sidebar-width: 240px; - --sidebar-bg: var(--bg-secondary); - --sidebar-border: var(--border); - --sidebar-hover: var(--bg-tertiary); - --sidebar-active: var(--primary-light); - --search-bg: var(--bg-secondary); - --search-border: var(--border); - --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; - --font-mono: "Cascadia Code", "Fira Code", "JetBrains Mono", Consolas, "Courier New", monospace; -} - -/* ===== Dark Theme ===== */ -:root.dark { - --primary: #8ab4f8; - --primary-light: #1a3a5c; - --primary-dark: #aecbfa; - --bg: #1e1e1e; - --bg-secondary: #252526; - --bg-tertiary: #2d2d2d; - --text: #d4d4d4; - --text-secondary: #9e9e9e; - --text-tertiary: #6e6e6e; - --border: #3e3e3e; - --border-light: #333333; - --code-bg: #2d2d2d; - --shadow: 0 1px 3px rgba(0, 0, 0, 0.3); - --shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.4); -} - -html, body { - height: 100%; - font-family: var(--font-ui); - font-size: 14px; - color: var(--text); - background: var(--bg); - overflow: hidden; - user-select: none; -} - -#app { - display: flex; - flex-direction: column; - height: 100vh; -} - -/* ===== Toolbar ===== */ -#toolbar { - height: var(--toolbar-height); - background: var(--bg); - border-bottom: 1px solid var(--border); - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 8px; - flex-shrink: 0; - z-index: 10; -} - -.toolbar-left, -.toolbar-right { - display: flex; - align-items: center; - gap: 2px; -} - -.toolbar-btn { - display: flex; - align-items: center; - gap: 5px; - padding: 6px 12px; - border: none; - background: transparent; - color: var(--text-secondary); - font-size: 13px; - font-family: var(--font-ui); - border-radius: var(--radius); - cursor: pointer; - transition: all 0.15s ease; - white-space: nowrap; -} - -.toolbar-btn:hover { - background: var(--bg-tertiary); - color: var(--text); -} - -.toolbar-btn.active { - background: var(--primary-light); - color: var(--primary); -} - -.toolbar-btn svg { - flex-shrink: 0; -} - -.toolbar-divider { - width: 1px; - height: 24px; - background: var(--border); - margin: 0 6px; -} - -/* ===== Modified Banner ===== */ -#modified-banner { - display: flex; - align-items: center; - gap: 12px; - padding: 6px 12px; - background: #fff3cd; - border-bottom: 1px solid #ffc107; - font-size: 13px; - color: #856404; - flex-shrink: 0; -} - -:root.dark #modified-banner { - background: #3a3000; - border-bottom-color: #665500; - color: #ffd54f; -} - -#modified-banner.hidden { - display: none; -} - -.banner-btn { - padding: 2px 10px; - border: 1px solid #ffc107; - border-radius: 4px; - background: transparent; - color: #856404; - font-size: 12px; - cursor: pointer; - font-family: var(--font-ui); -} - -:root.dark .banner-btn { - border-color: #665500; - color: #ffd54f; -} - -.banner-btn:hover { - background: #ffc107; - color: #000; -} - -:root.dark .banner-btn:hover { - background: #665500; - color: #fff; -} - -/* ===== Tab Bar ===== */ -#tab-bar { - height: 36px; - background: var(--bg-secondary); - border-bottom: 1px solid var(--border); - display: flex; - align-items: flex-end; - padding: 0 4px; - flex-shrink: 0; - overflow-x: auto; - overflow-y: hidden; -} - -#tab-bar::-webkit-scrollbar { - height: 0; -} - -#tab-list { - display: flex; - align-items: flex-end; - gap: 1px; - flex: 1; - min-width: 0; - overflow-x: auto; - overflow-y: hidden; -} - -#tab-list::-webkit-scrollbar { - height: 0; -} - -.tab-item { - display: flex; - align-items: center; - gap: 6px; - padding: 6px 12px; - background: transparent; - border: none; - border-bottom: 2px solid transparent; - color: var(--text-secondary); - font-size: 12px; - font-family: var(--font-ui); - cursor: pointer; - white-space: nowrap; - max-width: 180px; - min-width: 60px; - flex-shrink: 0; - transition: all 0.15s ease; - position: relative; -} - -.tab-item:hover { - color: var(--text); - background: var(--bg-tertiary); -} - -.tab-item.active { - color: var(--text); - background: var(--bg); - border-bottom-color: var(--primary); -} - -.tab-item.modified .tab-name::after { - content: ' •'; - color: var(--primary); -} - -.tab-name { - overflow: hidden; - text-overflow: ellipsis; - pointer-events: none; -} - -.tab-close { - display: flex; - align-items: center; - justify-content: center; - width: 16px; - height: 16px; - border: none; - background: transparent; - color: var(--text-tertiary); - border-radius: 3px; - cursor: pointer; - flex-shrink: 0; - padding: 0; - opacity: 0; - transition: all 0.1s ease; -} - -.tab-item:hover .tab-close, -.tab-item.active .tab-close { - opacity: 1; -} - -.tab-close:hover { - background: var(--border); - color: var(--text); -} - -.tab-add-btn { - display: flex; - align-items: center; - justify-content: center; - width: 28px; - height: 28px; - border: none; - background: transparent; - color: var(--text-secondary); - border-radius: var(--radius); - cursor: pointer; - margin-left: 2px; - margin-bottom: 4px; - flex-shrink: 0; - transition: all 0.15s ease; -} - -.tab-add-btn:hover { - background: var(--bg-tertiary); - color: var(--text); -} - -/* ===== Main Content ===== */ -#workspace { - flex: 1; - display: flex; - flex-direction: row; - overflow: hidden; - min-height: 0; -} - -#main-content { - flex: 1; - display: flex; - flex-direction: column; - overflow: hidden; - position: relative; - min-width: 0; -} - -#content-wrapper { - flex: 1; - display: flex; - flex-direction: row; - overflow: hidden; - min-height: 0; -} - -/* ===== Editor Panel ===== */ -#editor-panel { - flex: 1; - display: flex; - flex-direction: column; - min-width: 0; - border-right: 1px solid var(--border); -} - -#editor-wrapper { - flex: 1; - display: flex; - overflow: hidden; - position: relative; -} - -#line-numbers { - width: 50px; - background: var(--bg-secondary); - border-right: 1px solid var(--border-light); - padding: 12px 0; - text-align: right; - font-family: var(--font-mono); - font-size: 13px; - line-height: 1.6; - color: var(--text-tertiary); - overflow: hidden; - user-select: none; - flex-shrink: 0; -} - -#line-numbers .line-num { - padding-right: 12px; - height: 20.8px; -} - -#editor { - flex: 1; - width: 100%; - padding: 12px 16px; - border: none; - outline: none; - resize: none; - font-family: var(--font-mono); - font-size: 13px; - line-height: 1.6; - color: var(--text); - background: var(--bg); - tab-size: 4; - overflow-y: auto; - user-select: text; -} - -#editor::placeholder { - color: var(--text-tertiary); -} - -/* ===== Resizer ===== */ -#resizer { - width: 4px; - background: var(--border); - cursor: col-resize; - transition: background 0.15s ease; - flex-shrink: 0; -} - -#resizer:hover, -#resizer.active { - background: var(--primary); -} - -/* ===== Preview Panel ===== */ -#preview-panel { - flex: 1; - overflow-y: auto; - min-width: 0; - background: var(--bg); -} - -#preview { - padding: 24px 32px; - max-width: 900px; - margin: 0 auto; - user-select: text; - cursor: text; -} - -/* ===== Markdown Body Styles ===== */ -.markdown-body { - font-family: var(--font-ui); - font-size: 15px; - line-height: 1.7; - color: var(--text); - word-wrap: break-word; -} - -.markdown-body h1, -.markdown-body h2, -.markdown-body h3, -.markdown-body h4, -.markdown-body h5, -.markdown-body h6 { - margin-top: 24px; - margin-bottom: 16px; - font-weight: 600; - line-height: 1.25; - color: var(--text); -} - -.markdown-body h1 { - font-size: 2em; - padding-bottom: 0.3em; - border-bottom: 1px solid var(--border); -} - -.markdown-body h2 { - font-size: 1.5em; - padding-bottom: 0.3em; - border-bottom: 1px solid var(--border-light); -} - -.markdown-body h3 { font-size: 1.25em; } -.markdown-body h4 { font-size: 1em; } -.markdown-body h5 { font-size: 0.875em; } -.markdown-body h6 { font-size: 0.85em; color: var(--text-secondary); } - -.markdown-body p { - margin-top: 0; - margin-bottom: 16px; -} - -.markdown-body a { - color: var(--primary); - text-decoration: none; - cursor: pointer; -} - -.markdown-body a:hover { - text-decoration: underline; -} - -.markdown-body strong { font-weight: 600; } - -.markdown-body img { - max-width: 100%; - height: auto; - border-radius: var(--radius); - margin: 8px 0; -} - -.markdown-body hr { - height: 2px; - background: var(--border); - border: none; - margin: 24px 0; - border-radius: 1px; -} - -.markdown-body blockquote { - margin: 0 0 16px 0; - padding: 4px 16px; - border-left: 4px solid var(--primary); - color: var(--text-secondary); - background: var(--bg-secondary); - border-radius: 0 var(--radius) var(--radius) 0; -} - -.markdown-body blockquote p:last-child { - margin-bottom: 0; -} - -.markdown-body ul, -.markdown-body ol { - margin-top: 0; - margin-bottom: 16px; - padding-left: 2em; -} - -.markdown-body li { - margin-top: 4px; -} - -.markdown-body li + li { - margin-top: 4px; -} - -.markdown-body code { - font-family: var(--font-mono); - font-size: 0.9em; - background: var(--code-bg); - padding: 2px 6px; - border-radius: 4px; - color: #e83e8c; -} - -:root.dark .markdown-body code { - color: #f48fb1; -} - -.markdown-body pre { - margin-top: 0; - margin-bottom: 16px; - padding: 16px; - background: var(--code-bg); - border-radius: var(--radius); - overflow-x: auto; - border: 1px solid var(--border-light); -} - -.markdown-body pre code { - padding: 0; - background: transparent; - color: inherit; - font-size: 13px; - line-height: 1.5; -} - -.markdown-body table { - border-collapse: collapse; - width: 100%; - margin-bottom: 16px; - overflow-x: auto; - display: block; -} - -.markdown-body table th, -.markdown-body table td { - padding: 8px 16px; - border: 1px solid var(--border); - text-align: left; -} - -.markdown-body table th { - font-weight: 600; - background: var(--bg-secondary); -} - -.markdown-body table tr:nth-child(even) { - background: var(--bg-secondary); -} - -.markdown-body input[type="checkbox"] { - margin-right: 6px; - accent-color: var(--primary); -} - -/* ===== Status Bar ===== */ -#statusbar { - height: var(--statusbar-height); - background: var(--bg-secondary); - border-top: 1px solid var(--border); - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 12px; - font-size: 12px; - color: var(--text-secondary); - flex-shrink: 0; -} - -.status-left, -.status-right { - display: flex; - align-items: center; - gap: 8px; -} - -.status-divider { - color: var(--border); -} - -.status-size-divider { - display: none; -} - -.status-size-divider.visible { - display: inline; -} - -/* ===== Drop Overlay ===== */ -#drop-overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(26, 115, 232, 0.1); - backdrop-filter: blur(4px); - display: flex; - align-items: center; - justify-content: center; - z-index: 1000; - border: 3px dashed var(--primary); - margin: 8px; - border-radius: 12px; -} - -#drop-overlay.hidden { - display: none; -} - -.drop-content { - text-align: center; - color: var(--primary); -} - -.drop-content svg { - margin-bottom: 12px; - opacity: 0.7; -} - -.drop-content p { - font-size: 18px; - font-weight: 500; -} - -/* ===== Welcome Screen ===== */ -#welcome-screen { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - display: flex; - align-items: center; - justify-content: center; - background: var(--bg); - z-index: 5; -} - -#welcome-screen.hidden { - display: none; -} - -.welcome-content { - text-align: center; - max-width: 480px; - padding: 40px; -} - -.welcome-icon { - margin-bottom: 24px; -} - -.welcome-content h1 { - font-size: 28px; - font-weight: 600; - color: var(--text); - margin-bottom: 8px; -} - -.welcome-content > p { - font-size: 16px; - color: var(--text-secondary); - margin-bottom: 32px; -} - -.welcome-actions { - display: flex; - gap: 12px; - justify-content: center; - margin-bottom: 32px; -} - -.welcome-btn { - display: flex; - align-items: center; - gap: 8px; - padding: 10px 24px; - border: none; - border-radius: var(--radius); - font-size: 14px; - font-family: var(--font-ui); - font-weight: 500; - cursor: pointer; - transition: all 0.15s ease; -} - -.welcome-btn.primary { - background: var(--primary); - color: white; -} - -.welcome-btn.primary:hover { - background: var(--primary-dark); - box-shadow: var(--shadow-lg); -} - -.welcome-btn.secondary { - background: var(--bg-secondary); - color: var(--text); - border: 1px solid var(--border); -} - -.welcome-btn.secondary:hover { - background: var(--bg-tertiary); -} - -.welcome-tips { - text-align: left; - background: var(--bg-secondary); - border-radius: var(--radius); - padding: 16px 20px; - border: 1px solid var(--border-light); -} - -.welcome-tips p { - font-size: 13px; - color: var(--text-secondary); - margin-bottom: 6px; -} - -.welcome-tips p:last-child { - margin-bottom: 0; -} - -/* ===== Sidebar ===== */ -#sidebar { - width: var(--sidebar-width); - min-width: 180px; - max-width: 500px; - background: var(--sidebar-bg); - border-right: 1px solid var(--sidebar-border); - display: flex; - flex-direction: column; - flex-shrink: 0; - overflow: hidden; - user-select: none; - position: relative; -} - -#sidebar.collapsed { - display: none; -} - -#sidebar-header { - display: flex; - align-items: center; - justify-content: space-between; - padding: 8px 12px; - border-bottom: 1px solid var(--sidebar-border); - flex-shrink: 0; -} - -#sidebar-title { - font-size: 12px; - font-weight: 600; - color: var(--text-secondary); - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.sidebar-header-btn { - display: flex; - align-items: center; - justify-content: center; - width: 24px; - height: 24px; - border: none; - background: transparent; - color: var(--text-secondary); - border-radius: 4px; - cursor: pointer; - transition: all 0.15s ease; -} - -.sidebar-header-btn:hover { - background: var(--sidebar-hover); - color: var(--text); -} - -#sidebar-tree { - flex: 1; - overflow-y: auto; - overflow-x: hidden; - padding: 4px 0; -} - -.tree-item { - display: flex; - align-items: center; - padding: 3px 8px 3px 0; - cursor: pointer; - font-size: 13px; - color: var(--text); - white-space: nowrap; - transition: background 0.1s ease; - border-radius: 0; -} - -.tree-item:hover { - background: var(--sidebar-hover); -} - -.tree-item.active { - background: var(--sidebar-active); - color: var(--primary); - font-weight: 500; -} - -.tree-indent { - flex-shrink: 0; -} - -.tree-arrow { - display: flex; - align-items: center; - justify-content: center; - width: 16px; - height: 16px; - flex-shrink: 0; - color: var(--text-tertiary); - transition: transform 0.15s ease; -} - -.tree-arrow.expanded { - transform: rotate(90deg); -} - -.tree-icon { - display: flex; - align-items: center; - justify-content: center; - width: 16px; - height: 16px; - flex-shrink: 0; - margin-right: 4px; -} - -.tree-icon svg { - width: 14px; - height: 14px; -} - -.tree-name { - overflow: hidden; - text-overflow: ellipsis; -} - -/* ===== Independent Files Section ===== */ -.independent-files-section { - border-bottom: 1px solid var(--border); - margin-bottom: 4px; - padding-bottom: 4px; -} - -/* ===== Sidebar Section Headers ===== */ -.sidebar-section-header, -.independent-files-header { - font-size: 11px; - font-weight: 600; - color: var(--text-tertiary); - text-transform: uppercase; - letter-spacing: 0.5px; - padding: 8px 12px 4px 12px; -} - -.independent-file-item .independent-modified-dot { - color: var(--primary); - font-size: 14px; - margin-left: 4px; -} - -/* ===== Search & Replace Bar ===== */ -#btn-toggle-replace { - font-size: 10px; - transition: transform 0.15s ease; -} - -#btn-toggle-replace.expanded { - transform: rotate(90deg); -} - -#search-bar { - background: var(--search-bg); - border-bottom: 1px solid var(--search-border); - padding: 6px 10px; - flex-shrink: 0; -} - -#search-bar.hidden { - display: none; -} - -.search-row, -#replace-row { - display: flex; - align-items: center; - gap: 4px; -} - -#replace-row { - margin-top: 4px; -} - -#replace-row.hidden { - display: none; -} - -#search-input, -#replace-input { - flex: 1; - min-width: 0; - height: 26px; - padding: 0 8px; - border: 1px solid var(--border); - border-radius: 4px; - background: var(--bg); - color: var(--text); - font-size: 13px; - font-family: var(--font-ui); - outline: none; - transition: border-color 0.15s ease; -} - -#search-input:focus, -#replace-input:focus { - border-color: var(--primary); -} - -#search-count { - font-size: 11px; - color: var(--text-tertiary); - white-space: nowrap; - min-width: 40px; - text-align: center; -} - -.search-opt-btn { - display: flex; - align-items: center; - justify-content: center; - min-width: 26px; - height: 26px; - padding: 0 4px; - border: 1px solid var(--border); - border-radius: 4px; - background: transparent; - color: var(--text-secondary); - font-size: 11px; - font-weight: 600; - font-family: var(--font-mono); - cursor: pointer; - transition: all 0.15s ease; -} - -.search-opt-btn:hover { - background: var(--bg-tertiary); -} - -.search-opt-btn.active { - background: var(--primary-light); - color: var(--primary); - border-color: var(--primary); -} - -.search-nav-btn { - display: flex; - align-items: center; - justify-content: center; - width: 26px; - height: 26px; - border: none; - background: transparent; - color: var(--text-secondary); - border-radius: 4px; - cursor: pointer; - font-size: 14px; - transition: all 0.15s ease; -} - -.search-nav-btn:hover { - background: var(--bg-tertiary); - color: var(--text); -} - -.replace-btn { - height: 26px; - padding: 0 10px; - border: 1px solid var(--border); - border-radius: 4px; - background: transparent; - color: var(--text-secondary); - font-size: 12px; - font-family: var(--font-ui); - cursor: pointer; - white-space: nowrap; - transition: all 0.15s ease; -} - -.replace-btn:hover { - background: var(--bg-tertiary); - color: var(--text); -} - -/* ===== Search Highlight Overlays ===== */ -.search-hl { - background: rgba(255, 220, 0, 0.35); - border-radius: 2px; -} - -.search-hl.current { - background: rgba(255, 150, 0, 0.55); -} - -:root.dark .search-hl { - background: rgba(255, 220, 0, 0.25); -} - -:root.dark .search-hl.current { - background: rgba(255, 150, 0, 0.4); -} - -/* ===== View Modes ===== */ -#app.mode-editor #preview-panel, -#app.mode-editor #resizer { - display: none; -} - -#app.mode-preview #editor-panel, -#app.mode-preview #resizer { - display: none; -} - -/* ===== Scrollbar ===== */ -::-webkit-scrollbar { - width: 8px; - height: 8px; -} - -::-webkit-scrollbar-track { - background: transparent; -} - -::-webkit-scrollbar-thumb { - background: var(--border); - border-radius: 4px; -} - -::-webkit-scrollbar-thumb:hover { - background: var(--text-tertiary); -} - -/* ===== Animations ===== */ -@keyframes fadeIn { - from { opacity: 0; transform: translateY(8px); } - to { opacity: 1; transform: translateY(0); } -} - -.welcome-content { - animation: fadeIn 0.3s ease; -} - -/* ===== Toast Notification ===== */ -#toast-notification { - position: fixed; - bottom: 40px; - left: 50%; - transform: translateX(-50%) translateY(20px); - background: var(--text); - color: var(--bg); - padding: 8px 20px; - border-radius: 6px; - font-size: 13px; - font-family: var(--font-ui); - box-shadow: var(--shadow-lg); - opacity: 0; - pointer-events: none; - transition: opacity 0.3s ease, transform 0.3s ease; - z-index: 9999; - max-width: 480px; - text-align: center; -} - -#toast-notification.show { - opacity: 1; - transform: translateX(-50%) translateY(0); - pointer-events: auto; -} - -/* ===== Sidebar Resize Handle ===== */ -.sidebar-resize-handle { - position: absolute; - top: 0; - right: -2px; - width: 4px; - height: 100%; - cursor: col-resize; - z-index: 5; -} - -.sidebar-resize-handle:hover, -.sidebar-resize-handle:active { - background: var(--primary); -}