texlite 0.9.4 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DESIGN.md +12 -14
- package/OPERATIONS.md +12 -6
- package/README.md +70 -41
- package/README.zh-CN.md +59 -34
- package/dist/client/assets/{AdminUsers-B12FJUMy.js → AdminUsers-BExOMZsW.js} +1 -1
- package/dist/client/assets/{CitationLibraryDialog-BTmnCP4V.js → CitationLibraryDialog-tVD3i2gg.js} +1 -1
- package/dist/client/assets/Dashboard-DRt4rjKP.js +2 -0
- package/dist/client/assets/{GitDialog--MoUIW0n.js → GitDialog-CjDCi1uh.js} +1 -1
- package/dist/client/assets/{HistoryDialog-LgKbjsTZ.js → HistoryDialog-Pa9mK3Ky.js} +1 -1
- package/dist/client/assets/{LatexEditor-Dj2zIaQm.js → LatexEditor-8r486VeG.js} +2 -2
- package/dist/client/assets/PdfPreview-CMkO72I5.js +1 -0
- package/dist/client/assets/{ProjectIconPickerDialog-GzRuM0oQ.js → ProjectIconPickerDialog-B52xbSyr.js} +1 -1
- package/dist/client/assets/{ProjectNavigationDialogs-BiArHmQ9.js → ProjectNavigationDialogs-isGMXCfG.js} +1 -1
- package/dist/client/assets/ProjectSettings-Br_kJ113.js +1 -0
- package/dist/client/assets/ProjectWorkspace-CcbrdCy8.js +32 -0
- package/dist/client/assets/{SelectionHistoryDialog-Bpv6nvrC.js → SelectionHistoryDialog-ZvAhIJMy.js} +2 -2
- package/dist/client/assets/{SystemMetricsDialog-hJQATmd4.js → SystemMetricsDialog-D4ouU4HI.js} +1 -1
- package/dist/client/assets/{TagManagementDialog-BHC8qULq.js → TagManagementDialog-qhZfHgTr.js} +1 -1
- package/dist/client/assets/{WordCountDialog-DZhhO94k.js → WordCountDialog-tFhMCGyn.js} +1 -1
- package/dist/client/assets/check-DKIW1zpR.js +1 -0
- package/dist/client/assets/chktex-tM1XXPk2.js +3 -0
- package/dist/client/assets/{hard-drive-BWZnOgnm.js → hard-drive-CkIPwUSV.js} +1 -1
- package/dist/client/assets/index-90X2GUd_.css +1 -0
- package/dist/client/assets/index-CqBmQAzW.js +10 -0
- package/dist/client/assets/{index-kTamGfTl.js → index-DTYEGzB7.js} +1 -1
- package/dist/client/assets/{key-round-CoDwyVJc.js → key-round-BEnQo7IM.js} +1 -1
- package/dist/client/assets/{minimize-2-D100opW2.js → minimize-2-CLuDohEf.js} +1 -1
- package/dist/client/assets/{minus-DDTYB-Oz.js → minus-BpuvzV2m.js} +1 -1
- package/dist/client/assets/{plus-BVXOlQXP.js → plus-BFr75l91.js} +1 -1
- package/dist/client/assets/{refresh-cw-LtwnqlWh.js → refresh-cw-DyA4NKh7.js} +1 -1
- package/dist/client/assets/{search-DXo_aAp0.js → search-Nu4OcY_n.js} +1 -1
- package/dist/client/assets/{sigma-BgvHGPto.js → sigma-B-wjepsY.js} +1 -1
- package/dist/client/assets/{spellCheck-BtRppKcC.js → spellCheck-C-bNJsIU.js} +1 -1
- package/dist/client/assets/{tags-m9kppdi0.js → tags-BSA08jK3.js} +1 -1
- package/dist/client/assets/{type-YO4aprqE.js → type-BCdIbDmF.js} +1 -1
- package/dist/client/assets/{user-plus-MRmKeDtX.js → user-plus-gFwY-NA3.js} +1 -1
- package/dist/client/assets/{x-eisRQJv_.js → x-Cspw_pa4.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/app.js +8 -0
- package/dist/server/chktex.js +377 -0
- package/dist/server/collaboration.js +6 -0
- package/dist/server/db.js +6 -1
- package/dist/server/environment.js +1 -0
- package/dist/server/history.js +4 -4
- package/dist/server/i18n.js +12 -2
- package/dist/server/projectImportUploads.js +133 -0
- package/dist/server/routes/projectFiles.js +3 -0
- package/dist/server/routes/projectShared.js +1 -0
- package/dist/server/routes/projects.js +87 -15
- package/dist/shared/writingChecks.js +4 -0
- package/package.json +1 -1
- package/dist/client/assets/Dashboard-JA5_M3TK.js +0 -2
- package/dist/client/assets/PdfPreview-C_W7w360.js +0 -1
- package/dist/client/assets/ProjectSettings-DgJohWUv.js +0 -1
- package/dist/client/assets/ProjectWorkspace-C6sYiBF2.js +0 -32
- package/dist/client/assets/check-C1db8iNn.js +0 -1
- package/dist/client/assets/index-BiwJj0Np.css +0 -1
- package/dist/client/assets/index-p1NHkGGG.js +0 -12
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as F}from"./index-
|
|
1
|
+
import{c as F}from"./index-CqBmQAzW.js";import{g as B}from"./react-BVUjbTTn.js";const z=F("Clock3",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["polyline",{points:"12 6 12 12 16.5 12",key:"1aq6pp"}]]);var R={exports:{}},C;function L(){return C||(C=1,(function(T){var f=function(){this.Diff_Timeout=1,this.Diff_EditCost=4,this.Match_Threshold=.5,this.Match_Distance=1e3,this.Patch_DeleteThreshold=.5,this.Patch_Margin=4,this.Match_MaxBits=32},p=-1,M=1,_=0;f.Diff=function(r,n){return[r,n]},f.prototype.diff_main=function(r,n,e,t){typeof t>"u"&&(this.Diff_Timeout<=0?t=Number.MAX_VALUE:t=new Date().getTime()+this.Diff_Timeout*1e3);var a=t;if(r==null||n==null)throw new Error("Null input. (diff_main)");if(r==n)return r?[new f.Diff(_,r)]:[];typeof e>"u"&&(e=!0);var i=e,s=this.diff_commonPrefix(r,n),h=r.substring(0,s);r=r.substring(s),n=n.substring(s),s=this.diff_commonSuffix(r,n);var l=r.substring(r.length-s);r=r.substring(0,r.length-s),n=n.substring(0,n.length-s);var g=this.diff_compute_(r,n,i,a);return h&&g.unshift(new f.Diff(_,h)),l&&g.push(new f.Diff(_,l)),this.diff_cleanupMerge(g),g},f.prototype.diff_compute_=function(r,n,e,t){var a;if(!r)return[new f.Diff(M,n)];if(!n)return[new f.Diff(p,r)];var i=r.length>n.length?r:n,s=r.length>n.length?n:r,h=i.indexOf(s);if(h!=-1)return a=[new f.Diff(M,i.substring(0,h)),new f.Diff(_,s),new f.Diff(M,i.substring(h+s.length))],r.length>n.length&&(a[0][0]=a[2][0]=p),a;if(s.length==1)return[new f.Diff(p,r),new f.Diff(M,n)];var l=this.diff_halfMatch_(r,n);if(l){var g=l[0],v=l[1],u=l[2],o=l[3],c=l[4],b=this.diff_main(g,u,e,t),w=this.diff_main(v,o,e,t);return b.concat([new f.Diff(_,c)],w)}return e&&r.length>100&&n.length>100?this.diff_lineMode_(r,n,t):this.diff_bisect_(r,n,t)},f.prototype.diff_lineMode_=function(r,n,e){var t=this.diff_linesToChars_(r,n);r=t.chars1,n=t.chars2;var a=t.lineArray,i=this.diff_main(r,n,!1,e);this.diff_charsToLines_(i,a),this.diff_cleanupSemantic(i),i.push(new f.Diff(_,""));for(var s=0,h=0,l=0,g="",v="";s<i.length;){switch(i[s][0]){case M:l++,v+=i[s][1];break;case p:h++,g+=i[s][1];break;case _:if(h>=1&&l>=1){i.splice(s-h-l,h+l),s=s-h-l;for(var u=this.diff_main(g,v,!1,e),o=u.length-1;o>=0;o--)i.splice(s,0,u[o]);s=s+u.length}l=0,h=0,g="",v="";break}s++}return i.pop(),i},f.prototype.diff_bisect_=function(r,n,e){for(var t=r.length,a=n.length,i=Math.ceil((t+a)/2),s=i,h=2*i,l=new Array(h),g=new Array(h),v=0;v<h;v++)l[v]=-1,g[v]=-1;l[s+1]=0,g[s+1]=0;for(var u=t-a,o=u%2!=0,c=0,b=0,w=0,I=0,m=0;m<i&&!(new Date().getTime()>e);m++){for(var D=-m+c;D<=m-b;D+=2){var A=s+D,k;D==-m||D!=m&&l[A-1]<l[A+1]?k=l[A+1]:k=l[A-1]+1;for(var y=k-D;k<t&&y<a&&r.charAt(k)==n.charAt(y);)k++,y++;if(l[A]=k,k>t)b+=2;else if(y>a)c+=2;else if(o){var E=s+u-D;if(E>=0&&E<h&&g[E]!=-1){var P=t-g[E];if(k>=P)return this.diff_bisectSplit_(r,n,k,y,e)}}}for(var d=-m+w;d<=m-I;d+=2){var E=s+d,P;d==-m||d!=m&&g[E-1]<g[E+1]?P=g[E+1]:P=g[E-1]+1;for(var S=P-d;P<t&&S<a&&r.charAt(t-P-1)==n.charAt(a-S-1);)P++,S++;if(g[E]=P,P>t)I+=2;else if(S>a)w+=2;else if(!o){var A=s+u-d;if(A>=0&&A<h&&l[A]!=-1){var k=l[A],y=s+k-A;if(P=t-P,k>=P)return this.diff_bisectSplit_(r,n,k,y,e)}}}}return[new f.Diff(p,r),new f.Diff(M,n)]},f.prototype.diff_bisectSplit_=function(r,n,e,t,a){var i=r.substring(0,e),s=n.substring(0,t),h=r.substring(e),l=n.substring(t),g=this.diff_main(i,s,!1,a),v=this.diff_main(h,l,!1,a);return g.concat(v)},f.prototype.diff_linesToChars_=function(r,n){var e=[],t={};e[0]="";function a(l){for(var g="",v=0,u=-1,o=e.length;u<l.length-1;){u=l.indexOf(`
|
|
2
2
|
`,v),u==-1&&(u=l.length-1);var c=l.substring(v,u+1);(t.hasOwnProperty?t.hasOwnProperty(c):t[c]!==void 0)?g+=String.fromCharCode(t[c]):(o==i&&(c=l.substring(v),u=l.length),g+=String.fromCharCode(o),t[c]=o,e[o++]=c),v=u+1}return g}var i=4e4,s=a(r);i=65535;var h=a(n);return{chars1:s,chars2:h,lineArray:e}},f.prototype.diff_charsToLines_=function(r,n){for(var e=0;e<r.length;e++){for(var t=r[e][1],a=[],i=0;i<t.length;i++)a[i]=n[t.charCodeAt(i)];r[e][1]=a.join("")}},f.prototype.diff_commonPrefix=function(r,n){if(!r||!n||r.charAt(0)!=n.charAt(0))return 0;for(var e=0,t=Math.min(r.length,n.length),a=t,i=0;e<a;)r.substring(i,a)==n.substring(i,a)?(e=a,i=e):t=a,a=Math.floor((t-e)/2+e);return a},f.prototype.diff_commonSuffix=function(r,n){if(!r||!n||r.charAt(r.length-1)!=n.charAt(n.length-1))return 0;for(var e=0,t=Math.min(r.length,n.length),a=t,i=0;e<a;)r.substring(r.length-a,r.length-i)==n.substring(n.length-a,n.length-i)?(e=a,i=e):t=a,a=Math.floor((t-e)/2+e);return a},f.prototype.diff_commonOverlap_=function(r,n){var e=r.length,t=n.length;if(e==0||t==0)return 0;e>t?r=r.substring(e-t):e<t&&(n=n.substring(0,e));var a=Math.min(e,t);if(r==n)return a;for(var i=0,s=1;;){var h=r.substring(a-s),l=n.indexOf(h);if(l==-1)return i;s+=l,(l==0||r.substring(a-s)==n.substring(0,s))&&(i=s,s++)}},f.prototype.diff_halfMatch_=function(r,n){if(this.Diff_Timeout<=0)return null;var e=r.length>n.length?r:n,t=r.length>n.length?n:r;if(e.length<4||t.length*2<e.length)return null;var a=this;function i(b,w,I){for(var m=b.substring(I,I+Math.floor(b.length/4)),D=-1,A="",k,y,E,P;(D=w.indexOf(m,D+1))!=-1;){var d=a.diff_commonPrefix(b.substring(I),w.substring(D)),S=a.diff_commonSuffix(b.substring(0,I),w.substring(0,D));A.length<S+d&&(A=w.substring(D-S,D)+w.substring(D,D+d),k=b.substring(0,I-S),y=b.substring(I+d),E=w.substring(0,D-S),P=w.substring(D+d))}return A.length*2>=b.length?[k,y,E,P,A]:null}var s=i(e,t,Math.ceil(e.length/4)),h=i(e,t,Math.ceil(e.length/2)),l;if(!s&&!h)return null;h?s?l=s[4].length>h[4].length?s:h:l=h:l=s;var g,v,u,o;r.length>n.length?(g=l[0],v=l[1],u=l[2],o=l[3]):(u=l[0],o=l[1],g=l[2],v=l[3]);var c=l[4];return[g,v,u,o,c]},f.prototype.diff_cleanupSemantic=function(r){for(var n=!1,e=[],t=0,a=null,i=0,s=0,h=0,l=0,g=0;i<r.length;)r[i][0]==_?(e[t++]=i,s=l,h=g,l=0,g=0,a=r[i][1]):(r[i][0]==M?l+=r[i][1].length:g+=r[i][1].length,a&&a.length<=Math.max(s,h)&&a.length<=Math.max(l,g)&&(r.splice(e[t-1],0,new f.Diff(p,a)),r[e[t-1]+1][0]=M,t--,t--,i=t>0?e[t-1]:-1,s=0,h=0,l=0,g=0,a=null,n=!0)),i++;for(n&&this.diff_cleanupMerge(r),this.diff_cleanupSemanticLossless(r),i=1;i<r.length;){if(r[i-1][0]==p&&r[i][0]==M){var v=r[i-1][1],u=r[i][1],o=this.diff_commonOverlap_(v,u),c=this.diff_commonOverlap_(u,v);o>=c?(o>=v.length/2||o>=u.length/2)&&(r.splice(i,0,new f.Diff(_,u.substring(0,o))),r[i-1][1]=v.substring(0,v.length-o),r[i+1][1]=u.substring(o),i++):(c>=v.length/2||c>=u.length/2)&&(r.splice(i,0,new f.Diff(_,v.substring(0,c))),r[i-1][0]=M,r[i-1][1]=u.substring(0,u.length-c),r[i+1][0]=p,r[i+1][1]=v.substring(c),i++),i++}i++}},f.prototype.diff_cleanupSemanticLossless=function(r){function n(c,b){if(!c||!b)return 6;var w=c.charAt(c.length-1),I=b.charAt(0),m=w.match(f.nonAlphaNumericRegex_),D=I.match(f.nonAlphaNumericRegex_),A=m&&w.match(f.whitespaceRegex_),k=D&&I.match(f.whitespaceRegex_),y=A&&w.match(f.linebreakRegex_),E=k&&I.match(f.linebreakRegex_),P=y&&c.match(f.blanklineEndRegex_),d=E&&b.match(f.blanklineStartRegex_);return P||d?5:y||E?4:m&&!A&&k?3:A||k?2:m||D?1:0}for(var e=1;e<r.length-1;){if(r[e-1][0]==_&&r[e+1][0]==_){var t=r[e-1][1],a=r[e][1],i=r[e+1][1],s=this.diff_commonSuffix(t,a);if(s){var h=a.substring(a.length-s);t=t.substring(0,t.length-s),a=h+a.substring(0,a.length-s),i=h+i}for(var l=t,g=a,v=i,u=n(t,a)+n(a,i);a.charAt(0)===i.charAt(0);){t+=a.charAt(0),a=a.substring(1)+i.charAt(0),i=i.substring(1);var o=n(t,a)+n(a,i);o>=u&&(u=o,l=t,g=a,v=i)}r[e-1][1]!=l&&(l?r[e-1][1]=l:(r.splice(e-1,1),e--),r[e][1]=g,v?r[e+1][1]=v:(r.splice(e+1,1),e--))}e++}},f.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/,f.whitespaceRegex_=/\s/,f.linebreakRegex_=/[\r\n]/,f.blanklineEndRegex_=/\n\r?\n$/,f.blanklineStartRegex_=/^\r?\n\r?\n/,f.prototype.diff_cleanupEfficiency=function(r){for(var n=!1,e=[],t=0,a=null,i=0,s=!1,h=!1,l=!1,g=!1;i<r.length;)r[i][0]==_?(r[i][1].length<this.Diff_EditCost&&(l||g)?(e[t++]=i,s=l,h=g,a=r[i][1]):(t=0,a=null),l=g=!1):(r[i][0]==p?g=!0:l=!0,a&&(s&&h&&l&&g||a.length<this.Diff_EditCost/2&&s+h+l+g==3)&&(r.splice(e[t-1],0,new f.Diff(p,a)),r[e[t-1]+1][0]=M,t--,a=null,s&&h?(l=g=!0,t=0):(t--,i=t>0?e[t-1]:-1,l=g=!1),n=!0)),i++;n&&this.diff_cleanupMerge(r)},f.prototype.diff_cleanupMerge=function(r){r.push(new f.Diff(_,""));for(var n=0,e=0,t=0,a="",i="",s;n<r.length;)switch(r[n][0]){case M:t++,i+=r[n][1],n++;break;case p:e++,a+=r[n][1],n++;break;case _:e+t>1?(e!==0&&t!==0&&(s=this.diff_commonPrefix(i,a),s!==0&&(n-e-t>0&&r[n-e-t-1][0]==_?r[n-e-t-1][1]+=i.substring(0,s):(r.splice(0,0,new f.Diff(_,i.substring(0,s))),n++),i=i.substring(s),a=a.substring(s)),s=this.diff_commonSuffix(i,a),s!==0&&(r[n][1]=i.substring(i.length-s)+r[n][1],i=i.substring(0,i.length-s),a=a.substring(0,a.length-s))),n-=e+t,r.splice(n,e+t),a.length&&(r.splice(n,0,new f.Diff(p,a)),n++),i.length&&(r.splice(n,0,new f.Diff(M,i)),n++),n++):n!==0&&r[n-1][0]==_?(r[n-1][1]+=r[n][1],r.splice(n,1)):n++,t=0,e=0,a="",i="";break}r[r.length-1][1]===""&&r.pop();var h=!1;for(n=1;n<r.length-1;)r[n-1][0]==_&&r[n+1][0]==_&&(r[n][1].substring(r[n][1].length-r[n-1][1].length)==r[n-1][1]?(r[n][1]=r[n-1][1]+r[n][1].substring(0,r[n][1].length-r[n-1][1].length),r[n+1][1]=r[n-1][1]+r[n+1][1],r.splice(n-1,1),h=!0):r[n][1].substring(0,r[n+1][1].length)==r[n+1][1]&&(r[n-1][1]+=r[n+1][1],r[n][1]=r[n][1].substring(r[n+1][1].length)+r[n+1][1],r.splice(n+1,1),h=!0)),n++;h&&this.diff_cleanupMerge(r)},f.prototype.diff_xIndex=function(r,n){var e=0,t=0,a=0,i=0,s;for(s=0;s<r.length&&(r[s][0]!==M&&(e+=r[s][1].length),r[s][0]!==p&&(t+=r[s][1].length),!(e>n));s++)a=e,i=t;return r.length!=s&&r[s][0]===p?i:i+(n-a)},f.prototype.diff_prettyHtml=function(r){for(var n=[],e=/&/g,t=/</g,a=/>/g,i=/\n/g,s=0;s<r.length;s++){var h=r[s][0],l=r[s][1],g=l.replace(e,"&").replace(t,"<").replace(a,">").replace(i,"¶<br>");switch(h){case M:n[s]='<ins style="background:#e6ffe6;">'+g+"</ins>";break;case p:n[s]='<del style="background:#ffe6e6;">'+g+"</del>";break;case _:n[s]="<span>"+g+"</span>";break}}return n.join("")},f.prototype.diff_text1=function(r){for(var n=[],e=0;e<r.length;e++)r[e][0]!==M&&(n[e]=r[e][1]);return n.join("")},f.prototype.diff_text2=function(r){for(var n=[],e=0;e<r.length;e++)r[e][0]!==p&&(n[e]=r[e][1]);return n.join("")},f.prototype.diff_levenshtein=function(r){for(var n=0,e=0,t=0,a=0;a<r.length;a++){var i=r[a][0],s=r[a][1];switch(i){case M:e+=s.length;break;case p:t+=s.length;break;case _:n+=Math.max(e,t),e=0,t=0;break}}return n+=Math.max(e,t),n},f.prototype.diff_toDelta=function(r){for(var n=[],e=0;e<r.length;e++)switch(r[e][0]){case M:n[e]="+"+encodeURI(r[e][1]);break;case p:n[e]="-"+r[e][1].length;break;case _:n[e]="="+r[e][1].length;break}return n.join(" ").replace(/%20/g," ")},f.prototype.diff_fromDelta=function(r,n){for(var e=[],t=0,a=0,i=n.split(/\t/g),s=0;s<i.length;s++){var h=i[s].substring(1);switch(i[s].charAt(0)){case"+":try{e[t++]=new f.Diff(M,decodeURI(h))}catch{throw new Error("Illegal escape in diff_fromDelta: "+h)}break;case"-":case"=":var l=parseInt(h,10);if(isNaN(l)||l<0)throw new Error("Invalid number in diff_fromDelta: "+h);var g=r.substring(a,a+=l);i[s].charAt(0)=="="?e[t++]=new f.Diff(_,g):e[t++]=new f.Diff(p,g);break;default:if(i[s])throw new Error("Invalid diff operation in diff_fromDelta: "+i[s])}}if(a!=r.length)throw new Error("Delta length ("+a+") does not equal source text length ("+r.length+").");return e},f.prototype.match_main=function(r,n,e){if(r==null||n==null||e==null)throw new Error("Null input. (match_main)");return e=Math.max(0,Math.min(e,r.length)),r==n?0:r.length?r.substring(e,e+n.length)==n?e:this.match_bitap_(r,n,e):-1},f.prototype.match_bitap_=function(r,n,e){if(n.length>this.Match_MaxBits)throw new Error("Pattern too long for this browser.");var t=this.match_alphabet_(n),a=this;function i(k,y){var E=k/n.length,P=Math.abs(e-y);return a.Match_Distance?E+P/a.Match_Distance:P?1:E}var s=this.Match_Threshold,h=r.indexOf(n,e);h!=-1&&(s=Math.min(i(0,h),s),h=r.lastIndexOf(n,e+n.length),h!=-1&&(s=Math.min(i(0,h),s)));var l=1<<n.length-1;h=-1;for(var g,v,u=n.length+r.length,o,c=0;c<n.length;c++){for(g=0,v=u;g<v;)i(c,e+v)<=s?g=v:u=v,v=Math.floor((u-g)/2+g);u=v;var b=Math.max(1,e-v+1),w=Math.min(e+v,r.length)+n.length,I=Array(w+2);I[w+1]=(1<<c)-1;for(var m=w;m>=b;m--){var D=t[r.charAt(m-1)];if(c===0?I[m]=(I[m+1]<<1|1)&D:I[m]=(I[m+1]<<1|1)&D|((o[m+1]|o[m])<<1|1)|o[m+1],I[m]&l){var A=i(c,m-1);if(A<=s)if(s=A,h=m-1,h>e)b=Math.max(1,2*e-h);else break}}if(i(c+1,e)>s)break;o=I}return h},f.prototype.match_alphabet_=function(r){for(var n={},e=0;e<r.length;e++)n[r.charAt(e)]=0;for(var e=0;e<r.length;e++)n[r.charAt(e)]|=1<<r.length-e-1;return n},f.prototype.patch_addContext_=function(r,n){if(n.length!=0){if(r.start2===null)throw Error("patch not initialized");for(var e=n.substring(r.start2,r.start2+r.length1),t=0;n.indexOf(e)!=n.lastIndexOf(e)&&e.length<this.Match_MaxBits-this.Patch_Margin-this.Patch_Margin;)t+=this.Patch_Margin,e=n.substring(r.start2-t,r.start2+r.length1+t);t+=this.Patch_Margin;var a=n.substring(r.start2-t,r.start2);a&&r.diffs.unshift(new f.Diff(_,a));var i=n.substring(r.start2+r.length1,r.start2+r.length1+t);i&&r.diffs.push(new f.Diff(_,i)),r.start1-=a.length,r.start2-=a.length,r.length1+=a.length+i.length,r.length2+=a.length+i.length}},f.prototype.patch_make=function(r,n,e){var t,a;if(typeof r=="string"&&typeof n=="string"&&typeof e>"u")t=r,a=this.diff_main(t,n,!0),a.length>2&&(this.diff_cleanupSemantic(a),this.diff_cleanupEfficiency(a));else if(r&&typeof r=="object"&&typeof n>"u"&&typeof e>"u")a=r,t=this.diff_text1(a);else if(typeof r=="string"&&n&&typeof n=="object"&&typeof e>"u")t=r,a=n;else if(typeof r=="string"&&typeof n=="string"&&e&&typeof e=="object")t=r,a=e;else throw new Error("Unknown call format to patch_make.");if(a.length===0)return[];for(var i=[],s=new f.patch_obj,h=0,l=0,g=0,v=t,u=t,o=0;o<a.length;o++){var c=a[o][0],b=a[o][1];switch(!h&&c!==_&&(s.start1=l,s.start2=g),c){case M:s.diffs[h++]=a[o],s.length2+=b.length,u=u.substring(0,g)+b+u.substring(g);break;case p:s.length1+=b.length,s.diffs[h++]=a[o],u=u.substring(0,g)+u.substring(g+b.length);break;case _:b.length<=2*this.Patch_Margin&&h&&a.length!=o+1?(s.diffs[h++]=a[o],s.length1+=b.length,s.length2+=b.length):b.length>=2*this.Patch_Margin&&h&&(this.patch_addContext_(s,v),i.push(s),s=new f.patch_obj,h=0,v=u,l=g);break}c!==M&&(l+=b.length),c!==p&&(g+=b.length)}return h&&(this.patch_addContext_(s,v),i.push(s)),i},f.prototype.patch_deepCopy=function(r){for(var n=[],e=0;e<r.length;e++){var t=r[e],a=new f.patch_obj;a.diffs=[];for(var i=0;i<t.diffs.length;i++)a.diffs[i]=new f.Diff(t.diffs[i][0],t.diffs[i][1]);a.start1=t.start1,a.start2=t.start2,a.length1=t.length1,a.length2=t.length2,n[e]=a}return n},f.prototype.patch_apply=function(r,n){if(r.length==0)return[n,[]];r=this.patch_deepCopy(r);var e=this.patch_addPadding(r);n=e+n+e,this.patch_splitMax(r);for(var t=0,a=[],i=0;i<r.length;i++){var s=r[i].start2+t,h=this.diff_text1(r[i].diffs),l,g=-1;if(h.length>this.Match_MaxBits?(l=this.match_main(n,h.substring(0,this.Match_MaxBits),s),l!=-1&&(g=this.match_main(n,h.substring(h.length-this.Match_MaxBits),s+h.length-this.Match_MaxBits),(g==-1||l>=g)&&(l=-1))):l=this.match_main(n,h,s),l==-1)a[i]=!1,t-=r[i].length2-r[i].length1;else{a[i]=!0,t=l-s;var v;if(g==-1?v=n.substring(l,l+h.length):v=n.substring(l,g+this.Match_MaxBits),h==v)n=n.substring(0,l)+this.diff_text2(r[i].diffs)+n.substring(l+h.length);else{var u=this.diff_main(h,v,!1);if(h.length>this.Match_MaxBits&&this.diff_levenshtein(u)/h.length>this.Patch_DeleteThreshold)a[i]=!1;else{this.diff_cleanupSemanticLossless(u);for(var o=0,c,b=0;b<r[i].diffs.length;b++){var w=r[i].diffs[b];w[0]!==_&&(c=this.diff_xIndex(u,o)),w[0]===M?n=n.substring(0,l+c)+w[1]+n.substring(l+c):w[0]===p&&(n=n.substring(0,l+c)+n.substring(l+this.diff_xIndex(u,o+w[1].length))),w[0]!==p&&(o+=w[1].length)}}}}}return n=n.substring(e.length,n.length-e.length),[n,a]},f.prototype.patch_addPadding=function(r){for(var n=this.Patch_Margin,e="",t=1;t<=n;t++)e+=String.fromCharCode(t);for(var t=0;t<r.length;t++)r[t].start1+=n,r[t].start2+=n;var a=r[0],i=a.diffs;if(i.length==0||i[0][0]!=_)i.unshift(new f.Diff(_,e)),a.start1-=n,a.start2-=n,a.length1+=n,a.length2+=n;else if(n>i[0][1].length){var s=n-i[0][1].length;i[0][1]=e.substring(i[0][1].length)+i[0][1],a.start1-=s,a.start2-=s,a.length1+=s,a.length2+=s}if(a=r[r.length-1],i=a.diffs,i.length==0||i[i.length-1][0]!=_)i.push(new f.Diff(_,e)),a.length1+=n,a.length2+=n;else if(n>i[i.length-1][1].length){var s=n-i[i.length-1][1].length;i[i.length-1][1]+=e.substring(0,s),a.length1+=s,a.length2+=s}return e},f.prototype.patch_splitMax=function(r){for(var n=this.Match_MaxBits,e=0;e<r.length;e++)if(!(r[e].length1<=n)){var t=r[e];r.splice(e--,1);for(var a=t.start1,i=t.start2,s="";t.diffs.length!==0;){var h=new f.patch_obj,l=!0;for(h.start1=a-s.length,h.start2=i-s.length,s!==""&&(h.length1=h.length2=s.length,h.diffs.push(new f.Diff(_,s)));t.diffs.length!==0&&h.length1<n-this.Patch_Margin;){var g=t.diffs[0][0],v=t.diffs[0][1];g===M?(h.length2+=v.length,i+=v.length,h.diffs.push(t.diffs.shift()),l=!1):g===p&&h.diffs.length==1&&h.diffs[0][0]==_&&v.length>2*n?(h.length1+=v.length,a+=v.length,l=!1,h.diffs.push(new f.Diff(g,v)),t.diffs.shift()):(v=v.substring(0,n-h.length1-this.Patch_Margin),h.length1+=v.length,a+=v.length,g===_?(h.length2+=v.length,i+=v.length):l=!1,h.diffs.push(new f.Diff(g,v)),v==t.diffs[0][1]?t.diffs.shift():t.diffs[0][1]=t.diffs[0][1].substring(v.length))}s=this.diff_text2(h.diffs),s=s.substring(s.length-this.Patch_Margin);var u=this.diff_text1(t.diffs).substring(0,this.Patch_Margin);u!==""&&(h.length1+=u.length,h.length2+=u.length,h.diffs.length!==0&&h.diffs[h.diffs.length-1][0]===_?h.diffs[h.diffs.length-1][1]+=u:h.diffs.push(new f.Diff(_,u))),l||r.splice(++e,0,h)}}},f.prototype.patch_toText=function(r){for(var n=[],e=0;e<r.length;e++)n[e]=r[e];return n.join("")},f.prototype.patch_fromText=function(r){var n=[];if(!r)return n;for(var e=r.split(`
|
|
3
3
|
`),t=0,a=/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/;t<e.length;){var i=e[t].match(a);if(!i)throw new Error("Invalid patch string: "+e[t]);var s=new f.patch_obj;for(n.push(s),s.start1=parseInt(i[1],10),i[2]===""?(s.start1--,s.length1=1):i[2]=="0"?s.length1=0:(s.start1--,s.length1=parseInt(i[2],10)),s.start2=parseInt(i[3],10),i[4]===""?(s.start2--,s.length2=1):i[4]=="0"?s.length2=0:(s.start2--,s.length2=parseInt(i[4],10)),t++;t<e.length;){var h=e[t].charAt(0);try{var l=decodeURI(e[t].substring(1))}catch{throw new Error("Illegal escape in patch_fromText: "+l)}if(h=="-")s.diffs.push(new f.Diff(p,l));else if(h=="+")s.diffs.push(new f.Diff(M,l));else if(h==" ")s.diffs.push(new f.Diff(_,l));else{if(h=="@")break;if(h!=="")throw new Error('Invalid patch mode "'+h+'" in: '+l)}t++}}return n},f.patch_obj=function(){this.diffs=[],this.start1=null,this.start2=null,this.length1=0,this.length2=0},f.patch_obj.prototype.toString=function(){var r,n;this.length1===0?r=this.start1+",0":this.length1==1?r=this.start1+1:r=this.start1+1+","+this.length1,this.length2===0?n=this.start2+",0":this.length2==1?n=this.start2+1:n=this.start2+1+","+this.length2;for(var e=["@@ -"+r+" +"+n+` @@
|
|
4
4
|
`],t,a=0;a<this.diffs.length;a++){switch(this.diffs[a][0]){case M:t="+";break;case p:t="-";break;case _:t=" ";break}e[a+1]=t+encodeURI(this.diffs[a][1])+`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as a}from"./index-
|
|
1
|
+
import{c as a}from"./index-CqBmQAzW.js";const c=a("KeyRound",[["path",{d:"M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z",key:"1s6t7t"}],["circle",{cx:"16.5",cy:"7.5",r:".5",fill:"currentColor",key:"w0ekpg"}]]);export{c as K};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as e}from"./index-
|
|
1
|
+
import{c as e}from"./index-CqBmQAzW.js";const n=e("Minimize2",[["polyline",{points:"4 14 10 14 10 20",key:"11kfnr"}],["polyline",{points:"20 10 14 10 14 4",key:"rlmsce"}],["line",{x1:"14",x2:"21",y1:"10",y2:"3",key:"o5lafz"}],["line",{x1:"3",x2:"10",y1:"21",y2:"14",key:"1atl0r"}]]);export{n as M};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as e}from"./index-
|
|
1
|
+
import{c as e}from"./index-CqBmQAzW.js";const n=e("Maximize2",[["polyline",{points:"15 3 21 3 21 9",key:"mznyad"}],["polyline",{points:"9 21 3 21 3 15",key:"1avn1i"}],["line",{x1:"21",x2:"14",y1:"3",y2:"10",key:"ota7mn"}],["line",{x1:"3",x2:"10",y1:"21",y2:"14",key:"1atl0r"}]]);const a=e("Minus",[["path",{d:"M5 12h14",key:"1ays0h"}]]);export{a as M,n as a};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as e}from"./index-
|
|
1
|
+
import{c as e}from"./index-CqBmQAzW.js";const a=e("Plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);export{a as P};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as e}from"./index-
|
|
1
|
+
import{c as e}from"./index-CqBmQAzW.js";const t=e("RefreshCw",[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]]);export{t as R};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c}from"./index-
|
|
1
|
+
import{c}from"./index-CqBmQAzW.js";const r=c("Search",[["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}],["path",{d:"m21 21-4.3-4.3",key:"1qie3q"}]]);export{r as S};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as a}from"./index-
|
|
1
|
+
import{c as a}from"./index-CqBmQAzW.js";const e=a("Sigma",[["path",{d:"M18 7V5a1 1 0 0 0-1-1H6.5a.5.5 0 0 0-.4.8l4.5 6a2 2 0 0 1 0 2.4l-4.5 6a.5.5 0 0 0 .4.8H17a1 1 0 0 0 1-1v-2",key:"wuwx1p"}]]);export{e as S};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as w,A as L}from"./index-
|
|
1
|
+
import{g as w,A as L}from"./index-CqBmQAzW.js";import{s as y,c as S}from"./ProjectWorkspace-CcbrdCy8.js";import"./react-BVUjbTTn.js";import"./check-DKIW1zpR.js";import"./x-Cspw_pa4.js";import"./search-Nu4OcY_n.js";import"./user-plus-gFwY-NA3.js";import"./refresh-cw-DyA4NKh7.js";const k=5,f=new Map,C=12,x=S();let E=0;class p extends Error{constructor(){super("A newer writing check replaced this request."),this.name="HarperLintSupersededError"}}function I(e){return e instanceof p}function $(e){const t=[0];let r=0;for(const n of e)r+=n.length,t.push(r);return t}function d(e){return[...new Set(e.map(t=>t.trim()).filter(Boolean))].sort((t,r)=>t.localeCompare(r)).join("\0")}async function v(e,t,r,n){try{return(await w(`/api/projects/${e}/spellcheck`,{method:"POST",body:JSON.stringify({path:t,source:r,clientId:x,sequence:n})})).lints}catch(o){throw o instanceof L&&o.code==="SPELLCHECK_SUPERSEDED"?new p:o}}function A(e,t,r){if(!t.problem)return null;const n={from:t.start,to:t.end},o={from:r[t.start]??-1,to:r[t.end]??-1},i=c=>c.from>=0&&c.to>c.from&&c.to<=e.length,a=c=>i(c)&&e.slice(c.from,c.to)===t.problem;return a(o)?o:a(n)?n:null}function H(e,t,r){const n=A(e,t,r);if(!n)return null;const{from:o,to:i}=n,a=e.slice(o,i);if(!a.trim()||!/[A-Za-z]/.test(a)||t.kind==="Formatting")return null;const c=t.kind==="Spelling"||t.kind==="Typo"?"spelling":"grammar",u=t.suggestions.filter((m,s,l)=>s<k&&l.indexOf(m)===s);return{from:o,to:i,word:a,kind:c,message:t.message,suggestions:u}}function h(e,t){let r=2166136261;for(let n=0;n<t.length;n+=1)r^=t.charCodeAt(n),r=Math.imul(r,16777619);return`${e}\0${t.length}:${r>>>0}`}function g(e,t,r){const n=h(e,t),o=f.get(n);return!o||o.path!==e||o.source!==t||o.dictionary!==r?null:(f.delete(n),f.set(n,o),o.issues)}function R(e,t,r,n){const o=h(e,t);for(f.set(o,{path:e,source:t,dictionary:r,issues:n});f.size>C;){const i=f.keys().next().value;if(i===void 0)break;f.delete(i)}}async function b(e,t,r,n="main.tex"){const o=d(t),i=g(n,e,o);if(i)return i;const a=$(e),c=new Set(t.map(s=>s.trim().toLocaleLowerCase("en-US")).filter(Boolean)),u=new Set,m=r.map(s=>H(e,s,a)).filter(s=>!!s).filter(s=>s.kind!=="spelling"||!c.has(s.word.trim().toLocaleLowerCase("en-US"))).filter(s=>{const l=`${s.from}:${s.to}:${s.kind}`;return u.has(l)?!1:(u.add(l),!0)}).sort((s,l)=>s.from-l.from||s.to-l.to);return R(n,e,o,m),m}async function P(e,t,r,n){const o=d(n),i=g(t,r,o);if(i)return i;const a=await v(e,t,r,++E);return b(r,n,a,t)}function N(e,t,r,n=[]){return y(t)?P(e,t,r,n):Promise.resolve([])}export{p as HarperLintSupersededError,I as isHarperLintSupersededError,N as lintLatex,b as mapLatexLints};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as a}from"./index-
|
|
1
|
+
import{c as a}from"./index-CqBmQAzW.js";const e=a("Tags",[["path",{d:"m15 5 6.3 6.3a2.4 2.4 0 0 1 0 3.4L17 19",key:"1cbfv1"}],["path",{d:"M9.586 5.586A2 2 0 0 0 8.172 5H3a1 1 0 0 0-1 1v5.172a2 2 0 0 0 .586 1.414L8.29 18.29a2.426 2.426 0 0 0 3.42 0l3.58-3.58a2.426 2.426 0 0 0 0-3.42z",key:"135mg7"}],["circle",{cx:"6.5",cy:"9.5",r:".5",fill:"currentColor",key:"5pm5xn"}]]);export{e as T};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as e}from"./index-
|
|
1
|
+
import{c as e}from"./index-CqBmQAzW.js";const n=e("Type",[["polyline",{points:"4 7 4 4 20 4 20 7",key:"1nosan"}],["line",{x1:"9",x2:"15",y1:"20",y2:"20",key:"swin9y"}],["line",{x1:"12",x2:"12",y1:"4",y2:"20",key:"1tx1rr"}]]);export{n as T};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as e}from"./index-
|
|
1
|
+
import{c as e}from"./index-CqBmQAzW.js";const c=e("UserPlus",[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}],["line",{x1:"19",x2:"19",y1:"8",y2:"14",key:"1bvyxn"}],["line",{x1:"22",x2:"16",y1:"11",y2:"11",key:"1shjgl"}]]);export{c as U};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as a}from"./index-
|
|
1
|
+
import{c as a}from"./index-CqBmQAzW.js";const t=a("ArrowLeft",[["path",{d:"m12 19-7-7 7-7",key:"1l729n"}],["path",{d:"M19 12H5",key:"x3x0zl"}]]);const h=a("AtSign",[["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}],["path",{d:"M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-4 8",key:"7n84p3"}]]);const y=a("BookMarked",[["path",{d:"M10 2v8l3-3 3 3V2",key:"sqw3rj"}],["path",{d:"M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20",key:"k3hazp"}]]);const k=a("BookOpen",[["path",{d:"M12 7v14",key:"1akyts"}],["path",{d:"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z",key:"ruj8y"}]]);const d=a("ChevronLeft",[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]]);const p=a("ChevronRight",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);const c=a("Download",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"7 10 12 15 17 10",key:"2ggqvy"}],["line",{x1:"12",x2:"12",y1:"15",y2:"3",key:"1vk2je"}]]);const s=a("FileArchive",[["path",{d:"M10 12v-1",key:"v7bkov"}],["path",{d:"M10 18v-2",key:"1cjy8d"}],["path",{d:"M10 7V6",key:"dljcrl"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M15.5 22H18a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v16a2 2 0 0 0 .274 1.01",key:"gkbcor"}],["circle",{cx:"10",cy:"20",r:"2",key:"1xzdoj"}]]);const r=a("FileCode2",[["path",{d:"M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4",key:"1pf5j1"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"m5 12-3 3 3 3",key:"oke12k"}],["path",{d:"m9 18 3-3-3-3",key:"112psh"}]]);const o=a("FileSearch",[["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M4.268 21a2 2 0 0 0 1.727 1H18a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v3",key:"ms7g94"}],["path",{d:"m9 18-1.5-1.5",key:"1j6qii"}],["circle",{cx:"5",cy:"14",r:"3",key:"ufru5t"}]]);const l=a("FileSpreadsheet",[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",key:"1rqfz7"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M8 13h2",key:"yr2amv"}],["path",{d:"M14 13h2",key:"un5t4a"}],["path",{d:"M8 17h2",key:"2yhykz"}],["path",{d:"M14 17h2",key:"10kma7"}]]);const n=a("FileText",[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",key:"1rqfz7"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]]);const M=a("FolderPlus",[["path",{d:"M12 10v6",key:"1bos4e"}],["path",{d:"M9 13h6",key:"1uhe8q"}],["path",{d:"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z",key:"1kt360"}]]);const i=a("Folder",[["path",{d:"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z",key:"1kt360"}]]);const v=a("GitBranch",[["line",{x1:"6",x2:"6",y1:"3",y2:"15",key:"17qcm7"}],["circle",{cx:"18",cy:"6",r:"3",key:"1h7g24"}],["circle",{cx:"6",cy:"18",r:"3",key:"fqmcym"}],["path",{d:"M18 9a9 9 0 0 1-9 9",key:"n2h4wq"}]]);const x=a("ListTree",[["path",{d:"M21 12h-8",key:"1bmf0i"}],["path",{d:"M21 6H8",key:"1pqkrb"}],["path",{d:"M21 18h-8",key:"1tm79t"}],["path",{d:"M3 6v4c0 1.1.9 2 2 2h3",key:"1ywdgy"}],["path",{d:"M3 10v6c0 1.1.9 2 2 2h3",key:"2wc746"}]]);const m=a("MessageSquare",[["path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z",key:"1lielz"}]]);const H=a("NotepadText",[["path",{d:"M8 2v4",key:"1cmpym"}],["path",{d:"M12 2v4",key:"3427ic"}],["path",{d:"M16 2v4",key:"4m81vk"}],["rect",{width:"16",height:"18",x:"4",y:"4",rx:"2",key:"1u9h20"}],["path",{d:"M8 10h6",key:"3oa6kw"}],["path",{d:"M8 14h8",key:"1fgep2"}],["path",{d:"M8 18h5",key:"17enja"}]]);const q=a("Pencil",[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]]);const u=a("ScrollText",[["path",{d:"M15 12h-5",key:"r7krc0"}],["path",{d:"M15 8h-5",key:"1khuty"}],["path",{d:"M19 17V5a2 2 0 0 0-2-2H4",key:"zz82l3"}],["path",{d:"M8 21h12a2 2 0 0 0 2-2v-1a1 1 0 0 0-1-1H11a1 1 0 0 0-1 1v1a2 2 0 1 1-4 0V5a2 2 0 1 0-4 0v2a1 1 0 0 0 1 1h3",key:"1ph1d7"}]]);const g=a("Trash2",[["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6",key:"4alrt4"}],["path",{d:"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2",key:"v07s0e"}],["line",{x1:"10",x2:"10",y1:"11",y2:"17",key:"1uufr5"}],["line",{x1:"14",x2:"14",y1:"11",y2:"17",key:"xtxkd"}]]);const f=a("TriangleAlert",[["path",{d:"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",key:"wmoenq"}],["path",{d:"M12 9v4",key:"juzpu7"}],["path",{d:"M12 17h.01",key:"p32p05"}]]);const b=a("Upload",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"17 8 12 3 7 8",key:"t8dd8p"}],["line",{x1:"12",x2:"12",y1:"3",y2:"15",key:"widbto"}]]);const w=a("Users",[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["path",{d:"M16 3.13a4 4 0 0 1 0 7.75",key:"1da9ce"}]]);const z=a("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);export{h as A,y as B,p as C,c as D,o as F,v as G,x as L,m as M,H as N,q as P,u as S,g as T,w as U,z as X,i as a,l as b,r as c,k as d,n as e,t as f,b as g,M as h,d as i,s as j,f as k};
|
package/dist/client/index.html
CHANGED
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/iosevka@5.2.5/400.css" />
|
|
13
13
|
<link rel="icon" type="image/svg+xml" href="logo.svg" />
|
|
14
14
|
<title>TexLite</title>
|
|
15
|
-
<script type="module" crossorigin src="./assets/index-
|
|
15
|
+
<script type="module" crossorigin src="./assets/index-CqBmQAzW.js"></script>
|
|
16
16
|
<link rel="modulepreload" crossorigin href="./assets/react-BVUjbTTn.js">
|
|
17
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
17
|
+
<link rel="stylesheet" crossorigin href="./assets/index-90X2GUd_.css">
|
|
18
18
|
</head>
|
|
19
19
|
<body>
|
|
20
20
|
<div id="root"></div>
|
package/dist/server/app.js
CHANGED
|
@@ -37,6 +37,7 @@ import { registerSystemRoutes } from "./routes/system.js";
|
|
|
37
37
|
import { registerUserManagementRoutes } from "./routes/users.js";
|
|
38
38
|
import { registerWordCountRoutes } from "./routes/wordCount.js";
|
|
39
39
|
import { HarperService } from "./harper.js";
|
|
40
|
+
import { ChktexService } from "./chktex.js";
|
|
40
41
|
import { TexcountService } from "./texcount.js";
|
|
41
42
|
import { basePathHref, basePathPrefix, withoutBasePath } from "../shared/basePath.js";
|
|
42
43
|
// Retained public helper for callers and tests; implementation lives with the file routes.
|
|
@@ -86,10 +87,15 @@ export async function buildApp(config, db, options = {}) {
|
|
|
86
87
|
const latexCompletions = new LatexCompletionService(config);
|
|
87
88
|
const projectOutlines = new ProjectOutlineService(config);
|
|
88
89
|
const harper = new HarperService();
|
|
90
|
+
const chktex = new ChktexService();
|
|
89
91
|
const texcount = new TexcountService();
|
|
90
92
|
// Probe the optional host Harper CLI without delaying startup. Its absence is
|
|
91
93
|
// supported: the browser spellchecker remains the writing-check fallback.
|
|
92
94
|
void harper.preload().catch((error) => app.log.info({ err: error }, "Optional Harper CLI is unavailable"));
|
|
95
|
+
// ChkTeX is optional and disabled by default. Probe it in the background so
|
|
96
|
+
// enabling the project setting does not make the first editor request pay a
|
|
97
|
+
// process-discovery cost.
|
|
98
|
+
void chktex.preload().catch((error) => app.log.info({ err: error }, "Optional ChkTeX command is unavailable"));
|
|
93
99
|
const failedSnapshots = new Set();
|
|
94
100
|
const failedEdits = new Map();
|
|
95
101
|
const signalHistory = (id) => collaboration.setHistoryWarning(id, failedSnapshots.has(id) || failedEdits.has(id));
|
|
@@ -175,6 +181,7 @@ export async function buildApp(config, db, options = {}) {
|
|
|
175
181
|
historyRetention.dispose();
|
|
176
182
|
editRetry.dispose();
|
|
177
183
|
await harper.dispose();
|
|
184
|
+
await chktex.dispose();
|
|
178
185
|
await texcount.dispose();
|
|
179
186
|
});
|
|
180
187
|
await app.register(cookie, { hook: "onRequest" });
|
|
@@ -288,6 +295,7 @@ export async function buildApp(config, db, options = {}) {
|
|
|
288
295
|
latexCompletions,
|
|
289
296
|
projectOutlines,
|
|
290
297
|
harper,
|
|
298
|
+
chktex,
|
|
291
299
|
recordHistory
|
|
292
300
|
});
|
|
293
301
|
registerWordCountRoutes(routes, { config, db, projectMutations, texcount });
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { detachedProcessGroup, killProcessGroup } from "./processTree.js";
|
|
4
|
+
const commandProbeTimeoutMs = 5_000;
|
|
5
|
+
const checkTimeoutMs = 5_000;
|
|
6
|
+
const maxOutputBytes = 2 * 1024 * 1024;
|
|
7
|
+
const maxCachedSourceBytes = 512 * 1024;
|
|
8
|
+
const maxCachedResults = 24;
|
|
9
|
+
const cacheTtlMs = 15_000;
|
|
10
|
+
const unavailableRetryMs = 15_000;
|
|
11
|
+
const laneSequenceRetentionMs = 10 * 60_000;
|
|
12
|
+
const maxTrackedLaneSequences = 512;
|
|
13
|
+
const maxConcurrency = 8;
|
|
14
|
+
// ChkTeX does not append a record separator to a custom -f format. Without
|
|
15
|
+
// this newline, consecutive diagnostics run together and only the first one
|
|
16
|
+
// survives parseChktexOutput().
|
|
17
|
+
const outputFormat = "%f|%l|%c|%d|%n|%m\n";
|
|
18
|
+
export class ChktexUnavailableError extends Error {
|
|
19
|
+
constructor(message) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = "ChktexUnavailableError";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** A newer idle revision replaced a check which had not started yet. */
|
|
25
|
+
export class ChktexLintSupersededError extends Error {
|
|
26
|
+
constructor() {
|
|
27
|
+
super("A newer ChkTeX check replaced this request.");
|
|
28
|
+
this.name = "ChktexLintSupersededError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parse ChkTeX's machine-readable format. Only the first five separators
|
|
33
|
+
* have meaning, so a `|` in the human message is preserved rather than
|
|
34
|
+
* making the whole result invalid.
|
|
35
|
+
*/
|
|
36
|
+
export function parseChktexOutput(output) {
|
|
37
|
+
const lints = [];
|
|
38
|
+
const seen = new Set();
|
|
39
|
+
for (const line of output.split(/\r?\n/u)) {
|
|
40
|
+
const match = /^([^|]*)\|(\d+)\|(\d+)\|(-?\d+)\|(\d+)\|(.*)$/u.exec(line);
|
|
41
|
+
if (!match)
|
|
42
|
+
continue;
|
|
43
|
+
const lineNumber = Number(match[2]);
|
|
44
|
+
const column = Number(match[3]);
|
|
45
|
+
const length = Math.max(1, Number(match[4]));
|
|
46
|
+
const number = Number(match[5]);
|
|
47
|
+
const message = match[6].trim();
|
|
48
|
+
if (!Number.isSafeInteger(lineNumber) || lineNumber < 1 || !Number.isSafeInteger(column) || column < 1 || !message)
|
|
49
|
+
continue;
|
|
50
|
+
const key = `${lineNumber}:${column}:${length}:${number}:${message}`;
|
|
51
|
+
if (seen.has(key))
|
|
52
|
+
continue;
|
|
53
|
+
seen.add(key);
|
|
54
|
+
lints.push({ line: lineNumber, column, length, number: Number.isSafeInteger(number) ? number : null, message });
|
|
55
|
+
}
|
|
56
|
+
return lints;
|
|
57
|
+
}
|
|
58
|
+
function cacheKey(source, filePath) {
|
|
59
|
+
return createHash("sha256").update(filePath.toLowerCase()).update("\0").update(source).digest("base64url");
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Optional host-side ChkTeX integration. ChkTeX is intentionally run as a
|
|
63
|
+
* bounded, process-wide queue: at most eight projects/users consume a checker
|
|
64
|
+
* process at once, and a newer revision replaces obsolete waiting work in its
|
|
65
|
+
* own browser lane. The caller still debounces edits; this is the server-side
|
|
66
|
+
* backstop for multiple tabs and collaborators.
|
|
67
|
+
*/
|
|
68
|
+
export class ChktexService {
|
|
69
|
+
command;
|
|
70
|
+
availability = "unknown";
|
|
71
|
+
lastUnavailableAt = 0;
|
|
72
|
+
probePromise = null;
|
|
73
|
+
queued = new Set();
|
|
74
|
+
waitingByLane = new Map();
|
|
75
|
+
latestSequenceByLane = new Map();
|
|
76
|
+
inFlight = new Map();
|
|
77
|
+
scheduledByKey = new Map();
|
|
78
|
+
cache = new Map();
|
|
79
|
+
activeChildren = new Set();
|
|
80
|
+
activeOperations = new Set();
|
|
81
|
+
activeCount = 0;
|
|
82
|
+
disposed = false;
|
|
83
|
+
constructor(command = "chktex") {
|
|
84
|
+
this.command = command;
|
|
85
|
+
}
|
|
86
|
+
async preload() {
|
|
87
|
+
await this.ensureAvailable();
|
|
88
|
+
}
|
|
89
|
+
async lint(source, filePath = "main.tex", lane, sequence) {
|
|
90
|
+
if (this.disposed)
|
|
91
|
+
throw new ChktexUnavailableError("ChkTeX service stopped.");
|
|
92
|
+
const key = cacheKey(source, filePath);
|
|
93
|
+
const laneKey = lane || null;
|
|
94
|
+
if (laneKey && sequence !== undefined)
|
|
95
|
+
this.acceptLaneSequence(laneKey, sequence, key);
|
|
96
|
+
const waiting = laneKey ? this.waitingByLane.get(laneKey) : undefined;
|
|
97
|
+
if (waiting?.key === key)
|
|
98
|
+
return waiting.promise;
|
|
99
|
+
if (laneKey && waiting)
|
|
100
|
+
this.releaseWaitingLane(laneKey, waiting);
|
|
101
|
+
const cacheable = Buffer.byteLength(source, "utf8") <= maxCachedSourceBytes;
|
|
102
|
+
if (cacheable) {
|
|
103
|
+
const cached = this.cachedResult(key);
|
|
104
|
+
if (cached)
|
|
105
|
+
return cached;
|
|
106
|
+
}
|
|
107
|
+
const existing = this.inFlight.get(key);
|
|
108
|
+
if (existing) {
|
|
109
|
+
const scheduled = this.scheduledByKey.get(key);
|
|
110
|
+
if (laneKey && scheduled)
|
|
111
|
+
this.addWaitingLane(scheduled, laneKey);
|
|
112
|
+
else if (scheduled && !scheduled.started)
|
|
113
|
+
scheduled.hasUnscopedWaiter = true;
|
|
114
|
+
return existing;
|
|
115
|
+
}
|
|
116
|
+
let resolve;
|
|
117
|
+
let reject;
|
|
118
|
+
const operation = new Promise((resolveOperation, rejectOperation) => {
|
|
119
|
+
resolve = resolveOperation;
|
|
120
|
+
reject = rejectOperation;
|
|
121
|
+
});
|
|
122
|
+
const scheduled = {
|
|
123
|
+
key, source, filePath, started: false, cancelled: false,
|
|
124
|
+
lanes: laneKey ? new Set([laneKey]) : new Set(), hasUnscopedWaiter: laneKey === null,
|
|
125
|
+
promise: operation, resolve, reject
|
|
126
|
+
};
|
|
127
|
+
this.inFlight.set(key, operation);
|
|
128
|
+
this.scheduledByKey.set(key, scheduled);
|
|
129
|
+
if (laneKey)
|
|
130
|
+
this.waitingByLane.set(laneKey, scheduled);
|
|
131
|
+
this.queued.add(scheduled);
|
|
132
|
+
this.drain();
|
|
133
|
+
void operation.then((lints) => { if (cacheable)
|
|
134
|
+
this.cacheResult(key, lints); }, () => undefined).finally(() => {
|
|
135
|
+
if (this.inFlight.get(key) === operation)
|
|
136
|
+
this.inFlight.delete(key);
|
|
137
|
+
if (this.scheduledByKey.get(key) === scheduled)
|
|
138
|
+
this.scheduledByKey.delete(key);
|
|
139
|
+
});
|
|
140
|
+
return operation;
|
|
141
|
+
}
|
|
142
|
+
async dispose() {
|
|
143
|
+
this.disposed = true;
|
|
144
|
+
const stopped = new ChktexUnavailableError("ChkTeX service stopped.");
|
|
145
|
+
for (const scheduled of [...this.queued]) {
|
|
146
|
+
if (scheduled.started || scheduled.cancelled)
|
|
147
|
+
continue;
|
|
148
|
+
scheduled.cancelled = true;
|
|
149
|
+
this.discardQueued(scheduled);
|
|
150
|
+
scheduled.reject(stopped);
|
|
151
|
+
}
|
|
152
|
+
this.waitingByLane.clear();
|
|
153
|
+
this.latestSequenceByLane.clear();
|
|
154
|
+
for (const child of this.activeChildren)
|
|
155
|
+
killProcessGroup(child, "SIGTERM");
|
|
156
|
+
await Promise.allSettled([...this.activeOperations]);
|
|
157
|
+
await this.probePromise?.catch(() => undefined);
|
|
158
|
+
this.inFlight.clear();
|
|
159
|
+
this.scheduledByKey.clear();
|
|
160
|
+
this.cache.clear();
|
|
161
|
+
}
|
|
162
|
+
addWaitingLane(scheduled, lane) {
|
|
163
|
+
if (scheduled.started || scheduled.cancelled)
|
|
164
|
+
return;
|
|
165
|
+
scheduled.lanes.add(lane);
|
|
166
|
+
this.waitingByLane.set(lane, scheduled);
|
|
167
|
+
}
|
|
168
|
+
releaseWaitingLane(lane, scheduled) {
|
|
169
|
+
if (this.waitingByLane.get(lane) === scheduled)
|
|
170
|
+
this.waitingByLane.delete(lane);
|
|
171
|
+
scheduled.lanes.delete(lane);
|
|
172
|
+
if (scheduled.started || scheduled.cancelled || scheduled.hasUnscopedWaiter || scheduled.lanes.size > 0)
|
|
173
|
+
return;
|
|
174
|
+
this.cancelScheduled(scheduled);
|
|
175
|
+
}
|
|
176
|
+
cancelScheduled(scheduled) {
|
|
177
|
+
if (scheduled.started || scheduled.cancelled)
|
|
178
|
+
return;
|
|
179
|
+
scheduled.cancelled = true;
|
|
180
|
+
for (const lane of scheduled.lanes)
|
|
181
|
+
if (this.waitingByLane.get(lane) === scheduled)
|
|
182
|
+
this.waitingByLane.delete(lane);
|
|
183
|
+
scheduled.lanes.clear();
|
|
184
|
+
if (this.inFlight.get(scheduled.key) === scheduled.promise)
|
|
185
|
+
this.inFlight.delete(scheduled.key);
|
|
186
|
+
if (this.scheduledByKey.get(scheduled.key) === scheduled)
|
|
187
|
+
this.scheduledByKey.delete(scheduled.key);
|
|
188
|
+
this.discardQueued(scheduled);
|
|
189
|
+
scheduled.reject(new ChktexLintSupersededError());
|
|
190
|
+
}
|
|
191
|
+
discardQueued(scheduled) {
|
|
192
|
+
this.queued.delete(scheduled);
|
|
193
|
+
scheduled.source = "";
|
|
194
|
+
scheduled.filePath = "";
|
|
195
|
+
}
|
|
196
|
+
acceptLaneSequence(lane, sequence, key) {
|
|
197
|
+
if (!Number.isSafeInteger(sequence) || sequence <= 0)
|
|
198
|
+
throw new ChktexLintSupersededError();
|
|
199
|
+
const now = Date.now();
|
|
200
|
+
for (const [knownLane, state] of this.latestSequenceByLane) {
|
|
201
|
+
if (now - state.seenAt > laneSequenceRetentionMs)
|
|
202
|
+
this.latestSequenceByLane.delete(knownLane);
|
|
203
|
+
}
|
|
204
|
+
const previous = this.latestSequenceByLane.get(lane);
|
|
205
|
+
if (previous && (sequence < previous.sequence || (sequence === previous.sequence && previous.key !== key))) {
|
|
206
|
+
throw new ChktexLintSupersededError();
|
|
207
|
+
}
|
|
208
|
+
this.latestSequenceByLane.delete(lane);
|
|
209
|
+
this.latestSequenceByLane.set(lane, { sequence, key, seenAt: now });
|
|
210
|
+
while (this.latestSequenceByLane.size > maxTrackedLaneSequences) {
|
|
211
|
+
const oldest = this.latestSequenceByLane.keys().next().value;
|
|
212
|
+
if (oldest === undefined)
|
|
213
|
+
break;
|
|
214
|
+
this.latestSequenceByLane.delete(oldest);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
drain() {
|
|
218
|
+
while (!this.disposed && this.activeCount < maxConcurrency) {
|
|
219
|
+
const scheduled = this.queued.values().next().value;
|
|
220
|
+
if (!scheduled)
|
|
221
|
+
return;
|
|
222
|
+
this.queued.delete(scheduled);
|
|
223
|
+
if (scheduled.cancelled)
|
|
224
|
+
continue;
|
|
225
|
+
scheduled.started = true;
|
|
226
|
+
for (const lane of scheduled.lanes)
|
|
227
|
+
if (this.waitingByLane.get(lane) === scheduled)
|
|
228
|
+
this.waitingByLane.delete(lane);
|
|
229
|
+
scheduled.lanes.clear();
|
|
230
|
+
this.activeCount += 1;
|
|
231
|
+
let operation;
|
|
232
|
+
operation = this.runScheduled(scheduled).finally(() => {
|
|
233
|
+
this.activeCount -= 1;
|
|
234
|
+
this.activeOperations.delete(operation);
|
|
235
|
+
this.drain();
|
|
236
|
+
});
|
|
237
|
+
this.activeOperations.add(operation);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
async runScheduled(scheduled) {
|
|
241
|
+
try {
|
|
242
|
+
scheduled.resolve(await this.lintOnce(scheduled.source, scheduled.filePath));
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
scheduled.reject(error);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
async ensureAvailable() {
|
|
249
|
+
if (this.disposed)
|
|
250
|
+
throw new ChktexUnavailableError("ChkTeX service stopped.");
|
|
251
|
+
if (this.availability === "available")
|
|
252
|
+
return;
|
|
253
|
+
if (this.availability === "unavailable" && Date.now() - this.lastUnavailableAt < unavailableRetryMs) {
|
|
254
|
+
throw new ChktexUnavailableError(`The optional ${this.command} command is not available.`);
|
|
255
|
+
}
|
|
256
|
+
if (this.probePromise)
|
|
257
|
+
return this.probePromise;
|
|
258
|
+
this.probePromise = this.runCommand(["--version"], "", commandProbeTimeoutMs, 64 * 1024)
|
|
259
|
+
.then(({ code, stdout, stderr }) => {
|
|
260
|
+
if (code !== 0)
|
|
261
|
+
throw new Error((stderr || stdout).trim() || `${this.command} exited with code ${code}`);
|
|
262
|
+
this.availability = "available";
|
|
263
|
+
})
|
|
264
|
+
.catch((error) => {
|
|
265
|
+
this.availability = "unavailable";
|
|
266
|
+
this.lastUnavailableAt = Date.now();
|
|
267
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
268
|
+
throw new ChktexUnavailableError(`The optional ${this.command} command is unavailable: ${detail}`);
|
|
269
|
+
})
|
|
270
|
+
.finally(() => { this.probePromise = null; });
|
|
271
|
+
return this.probePromise;
|
|
272
|
+
}
|
|
273
|
+
async lintOnce(source, filePath) {
|
|
274
|
+
await this.ensureAvailable();
|
|
275
|
+
// With no filename ChkTeX reads stdin. Passing `-` is interpreted as a
|
|
276
|
+
// literal filename by ChkTeX 1.7.x and silently produces no diagnostics.
|
|
277
|
+
// Only the active editor buffer is submitted. Disable ChkTeX's recursive
|
|
278
|
+
// \input traversal so diagnostics from another file cannot be mapped onto
|
|
279
|
+
// this buffer's line and column numbers.
|
|
280
|
+
const result = await this.runCommand(["-q", "-I0", "-f", outputFormat], source, checkTimeoutMs, maxOutputBytes);
|
|
281
|
+
// ChkTeX commonly exits with 2 when it found warnings. Some packaged
|
|
282
|
+
// releases use 1 for the same condition, so a structured diagnostic also
|
|
283
|
+
// makes either status successful; a non-zero status without diagnostics is
|
|
284
|
+
// still an execution failure.
|
|
285
|
+
const lints = parseChktexOutput(result.stdout);
|
|
286
|
+
const expectedDiagnosticExit = (result.code === 1 || result.code === 2) && lints.length > 0;
|
|
287
|
+
if (result.code !== 0 && !expectedDiagnosticExit) {
|
|
288
|
+
const detail = result.stderr.trim() || result.stdout.trim();
|
|
289
|
+
throw new Error(detail || `${this.command} exited with code ${result.code}`);
|
|
290
|
+
}
|
|
291
|
+
return lints;
|
|
292
|
+
}
|
|
293
|
+
cachedResult(key) {
|
|
294
|
+
const cached = this.cache.get(key);
|
|
295
|
+
if (!cached || cached.expiresAt < Date.now()) {
|
|
296
|
+
this.cache.delete(key);
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
this.cache.delete(key);
|
|
300
|
+
this.cache.set(key, cached);
|
|
301
|
+
return cached.lints;
|
|
302
|
+
}
|
|
303
|
+
cacheResult(key, lints) {
|
|
304
|
+
this.cache.set(key, { expiresAt: Date.now() + cacheTtlMs, lints });
|
|
305
|
+
while (this.cache.size > maxCachedResults) {
|
|
306
|
+
const oldest = this.cache.keys().next().value;
|
|
307
|
+
if (oldest === undefined)
|
|
308
|
+
break;
|
|
309
|
+
this.cache.delete(oldest);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
runCommand(args, input, timeoutMs, outputLimit) {
|
|
313
|
+
return new Promise((resolve, reject) => {
|
|
314
|
+
if (this.disposed) {
|
|
315
|
+
reject(new ChktexUnavailableError("ChkTeX service stopped."));
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
let child;
|
|
319
|
+
try {
|
|
320
|
+
child = spawn(this.command, args, {
|
|
321
|
+
env: { ...process.env, LC_ALL: "C" }, shell: false, detached: detachedProcessGroup(),
|
|
322
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
reject(error);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
this.activeChildren.add(child);
|
|
330
|
+
const stdout = [];
|
|
331
|
+
const stderr = [];
|
|
332
|
+
let outputBytes = 0;
|
|
333
|
+
let settled = false;
|
|
334
|
+
let timedOut = false;
|
|
335
|
+
const finish = (callback) => {
|
|
336
|
+
if (settled)
|
|
337
|
+
return;
|
|
338
|
+
settled = true;
|
|
339
|
+
clearTimeout(timer);
|
|
340
|
+
this.activeChildren.delete(child);
|
|
341
|
+
callback();
|
|
342
|
+
};
|
|
343
|
+
const terminate = (error) => {
|
|
344
|
+
killProcessGroup(child);
|
|
345
|
+
finish(() => reject(error));
|
|
346
|
+
};
|
|
347
|
+
const timer = setTimeout(() => {
|
|
348
|
+
timedOut = true;
|
|
349
|
+
killProcessGroup(child);
|
|
350
|
+
}, timeoutMs);
|
|
351
|
+
const collect = (target) => (chunk) => {
|
|
352
|
+
outputBytes += chunk.length;
|
|
353
|
+
if (outputBytes > outputLimit) {
|
|
354
|
+
terminate(new Error(`${this.command} produced too much output.`));
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
target.push(chunk);
|
|
358
|
+
};
|
|
359
|
+
child.stdout?.on("data", collect(stdout));
|
|
360
|
+
child.stderr?.on("data", collect(stderr));
|
|
361
|
+
child.stdin?.on("error", (error) => terminate(error));
|
|
362
|
+
child.once("error", (error) => finish(() => {
|
|
363
|
+
if (timedOut)
|
|
364
|
+
return reject(new Error(`${this.command} timed out after ${Math.ceil(timeoutMs / 1000)} seconds.`));
|
|
365
|
+
if (error.code === "ENOENT")
|
|
366
|
+
return reject(new ChktexUnavailableError(`The optional ${this.command} command is not available.`));
|
|
367
|
+
reject(error);
|
|
368
|
+
}));
|
|
369
|
+
child.once("close", (code) => finish(() => {
|
|
370
|
+
if (timedOut)
|
|
371
|
+
return reject(new Error(`${this.command} timed out after ${Math.ceil(timeoutMs / 1000)} seconds.`));
|
|
372
|
+
resolve({ code, stdout: Buffer.concat(stdout).toString("utf8"), stderr: Buffer.concat(stderr).toString("utf8") });
|
|
373
|
+
}));
|
|
374
|
+
child.stdin?.end(input);
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
}
|
|
@@ -416,6 +416,12 @@ export class CollaborationService {
|
|
|
416
416
|
return;
|
|
417
417
|
room.doc.transact(() => room.meta.set("dictionaryRevision", randomUUID()), META_ORIGIN);
|
|
418
418
|
}
|
|
419
|
+
signalChktexSetting(projectId) {
|
|
420
|
+
const room = this.rooms.get(projectId);
|
|
421
|
+
if (!room)
|
|
422
|
+
return;
|
|
423
|
+
room.doc.transact(() => room.meta.set("chktexSettingsRevision", randomUUID()), META_ORIGIN);
|
|
424
|
+
}
|
|
419
425
|
signalCompileState(projectId, state) {
|
|
420
426
|
const room = this.rooms.get(projectId);
|
|
421
427
|
if (!room)
|
package/dist/server/db.js
CHANGED
|
@@ -13,7 +13,12 @@ const migrationsTable = "texlite_schema_migrations";
|
|
|
13
13
|
const databaseMigrations = [
|
|
14
14
|
// Append future migrations below this entry. Never insert before or modify
|
|
15
15
|
// the released baseline: recorded databases will intentionally skip it.
|
|
16
|
-
{ version: 1, name: "baseline_schema_and_legacy_upgrade", apply: applyBaselineMigration }
|
|
16
|
+
{ version: 1, name: "baseline_schema_and_legacy_upgrade", apply: applyBaselineMigration },
|
|
17
|
+
{ version: 2, name: "add_project_chktex_enabled", apply: (db) => {
|
|
18
|
+
if (!missingColumn(db, "projects", "chktex_enabled"))
|
|
19
|
+
return;
|
|
20
|
+
db.exec("ALTER TABLE projects ADD COLUMN chktex_enabled INTEGER NOT NULL DEFAULT 0 CHECK (chktex_enabled IN (0, 1))");
|
|
21
|
+
} }
|
|
17
22
|
];
|
|
18
23
|
export function openDatabase(config) {
|
|
19
24
|
fs.mkdirSync(config.dataDir, { recursive: true, mode: 0o700 });
|