From 89005c8baef04ac5b4d9f1f24bed21880424244c Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Sat, 4 Jul 2026 22:38:19 +0300 Subject: [PATCH 01/18] support for displaying images in webview --- .../server/frontend/dist/assets/index.css | 2 +- .../server/frontend/dist/assets/index.js | 2 +- frontends/server/frontend/editor.js | 101 +++++++++++++++++- frontends/server/main.lisp | 83 +++++++++++++- src/display/physical-line.lisp | 12 +-- src/internal-packages.lisp | 1 + 6 files changed, 181 insertions(+), 20 deletions(-) diff --git a/frontends/server/frontend/dist/assets/index.css b/frontends/server/frontend/dist/assets/index.css index 3dfcc503b..d88bed8c2 100644 --- a/frontends/server/frontend/dist/assets/index.css +++ b/frontends/server/frontend/dist/assets/index.css @@ -1 +1 @@ -@keyframes lem-cursor-blink{0%,to{opacity:1}50%{opacity:0}}.lem-cursor{position:absolute;pointer-events:none;z-index:300;animation:lem-cursor-blink 1s step-end infinite;overflow:hidden;white-space:pre;line-height:1;box-sizing:border-box}.lem-editor__floating-window--bordered{padding:10px;border:none;border-radius:8px;box-shadow:4px 4px 16px #000,0 0 0 1px #80808033;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.lem-editor__mode-line{border:none;border-radius:4px;box-shadow:0 0 0 1px #80808080}.lem-editor__vertical-border{width:10px;background:linear-gradient(to right,transparent 4px,rgba(128,128,128,.5) 4px 6px,transparent 5px)}.lem-editor__horizontal-border{height:10px;background:linear-gradient(to bottom,transparent 0px,rgba(128,128,128,.5) 3px 5px,transparent 2px)} +@keyframes lem-cursor-blink{0%,to{opacity:1}50%{opacity:0}}.lem-cursor{pointer-events:none;z-index:300;white-space:pre;box-sizing:border-box;line-height:1;animation:1s step-end infinite lem-cursor-blink;position:absolute;overflow:hidden}.lem-editor__floating-window--bordered{-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border:none;border-radius:8px;padding:10px;box-shadow:4px 4px 16px #000,0 0 0 1px #80808033}.lem-editor__mode-line{border:none;border-radius:4px;box-shadow:0 0 0 1px #80808080}.lem-editor__vertical-border{background:linear-gradient(90deg,#0000 4px,#80808080 4px 6px,#0000 5px);width:10px}.lem-editor__horizontal-border{background:linear-gradient(#0000 0,#80808080 3px 5px,#0000 2px);height:10px} diff --git a/frontends/server/frontend/dist/assets/index.js b/frontends/server/frontend/dist/assets/index.js index a036fd0e9..1cc125100 100644 --- a/frontends/server/frontend/dist/assets/index.js +++ b/frontends/server/frontend/dist/assets/index.js @@ -1 +1 @@ -(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))i(n);new MutationObserver(n=>{for(const s of n)if(s.type==="childList")for(const r of s.addedNodes)r.tagName==="LINK"&&r.rel==="modulepreload"&&i(r)}).observe(document,{childList:!0,subtree:!0});function t(n){const s={};return n.integrity&&(s.integrity=n.integrity),n.referrerPolicy&&(s.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?s.credentials="include":n.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function i(n){if(n.ep)return;n.ep=!0;const s=t(n);fetch(n.href,s)}})();var dist={},client={},models={},hasRequiredModels;function requireModels(){return hasRequiredModels||(hasRequiredModels=1,function(o){var e=models&&models.__extends||function(){var u=function(h,a){return u=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(c,p){c.__proto__=p}||function(c,p){for(var w in p)Object.prototype.hasOwnProperty.call(p,w)&&(c[w]=p[w])},u(h,a)};return function(h,a){if(typeof a!="function"&&a!==null)throw new TypeError("Class extends value "+String(a)+" is not a constructor or null");u(h,a);function c(){this.constructor=h}h.prototype=a===null?Object.create(a):(c.prototype=a.prototype,new c)}}();Object.defineProperty(o,"__esModule",{value:!0}),o.createJSONRPCNotification=o.createJSONRPCRequest=o.createJSONRPCSuccessResponse=o.createJSONRPCErrorResponse=o.JSONRPCErrorCode=o.JSONRPCErrorException=o.isJSONRPCResponses=o.isJSONRPCResponse=o.isJSONRPCRequests=o.isJSONRPCRequest=o.isJSONRPCID=o.JSONRPC=void 0,o.JSONRPC="2.0";var t=function(u){return typeof u=="string"||typeof u=="number"||u===null};o.isJSONRPCID=t;var i=function(u){return u.jsonrpc===o.JSONRPC&&u.method!==void 0&&u.result===void 0&&u.error===void 0};o.isJSONRPCRequest=i;var n=function(u){return Array.isArray(u)&&u.every(o.isJSONRPCRequest)};o.isJSONRPCRequests=n;var s=function(u){return u.jsonrpc===o.JSONRPC&&u.id!==void 0&&(u.result!==void 0||u.error!==void 0)};o.isJSONRPCResponse=s;var r=function(u){return Array.isArray(u)&&u.every(o.isJSONRPCResponse)};o.isJSONRPCResponses=r;var l=function(u,h,a){var c={code:u,message:h};return a!=null&&(c.data=a),c},f=function(u){e(h,u);function h(a,c,p){var w=u.call(this,a)||this;return Object.setPrototypeOf(w,h.prototype),w.code=c,w.data=p,w}return h.prototype.toObject=function(){return l(this.code,this.message,this.data)},h}(Error);o.JSONRPCErrorException=f,function(u){u[u.ParseError=-32700]="ParseError",u[u.InvalidRequest=-32600]="InvalidRequest",u[u.MethodNotFound=-32601]="MethodNotFound",u[u.InvalidParams=-32602]="InvalidParams",u[u.InternalError=-32603]="InternalError"}(o.JSONRPCErrorCode||(o.JSONRPCErrorCode={}));var d=function(u,h,a,c){return{jsonrpc:o.JSONRPC,id:u,error:l(h,a,c)}};o.createJSONRPCErrorResponse=d;var y=function(u,h){return{jsonrpc:o.JSONRPC,id:u,result:h??null}};o.createJSONRPCSuccessResponse=y;var v=function(u,h,a){return{jsonrpc:o.JSONRPC,id:u,method:h,params:a}};o.createJSONRPCRequest=v;var N=function(u,h){return{jsonrpc:o.JSONRPC,method:u,params:h}};o.createJSONRPCNotification=N}(models)),models}var internal={},hasRequiredInternal;function requireInternal(){return hasRequiredInternal||(hasRequiredInternal=1,Object.defineProperty(internal,"__esModule",{value:!0}),internal.DefaultErrorCode=void 0,internal.DefaultErrorCode=0),internal}var hasRequiredClient;function requireClient(){if(hasRequiredClient)return client;hasRequiredClient=1;var o=client&&client.__awaiter||function(r,l,f,d){function y(v){return v instanceof f?v:new f(function(N){N(v)})}return new(f||(f=Promise))(function(v,N){function u(c){try{a(d.next(c))}catch(p){N(p)}}function h(c){try{a(d.throw(c))}catch(p){N(p)}}function a(c){c.done?v(c.value):y(c.value).then(u,h)}a((d=d.apply(r,l||[])).next())})},e=client&&client.__generator||function(r,l){var f={label:0,sent:function(){if(v[0]&1)throw v[1];return v[1]},trys:[],ops:[]},d,y,v,N;return N={next:u(0),throw:u(1),return:u(2)},typeof Symbol=="function"&&(N[Symbol.iterator]=function(){return this}),N;function u(a){return function(c){return h([a,c])}}function h(a){if(d)throw new TypeError("Generator is already executing.");for(;N&&(N=0,a[0]&&(f=0)),f;)try{if(d=1,y&&(v=a[0]&2?y.return:a[0]?y.throw||((v=y.return)&&v.call(y),0):y.next)&&!(v=v.call(y,a[1])).done)return v;switch(y=0,v&&(a=[a[0]&2,v.value]),a[0]){case 0:case 1:v=a;break;case 4:return f.label++,{value:a[1],done:!1};case 5:f.label++,y=a[1],a=[0];continue;case 7:a=f.ops.pop(),f.trys.pop();continue;default:if(v=f.trys,!(v=v.length>0&&v[v.length-1])&&(a[0]===6||a[0]===2)){f=0;continue}if(a[0]===3&&(!v||a[1]>v[0]&&a[1]0&&m[m.length-1])&&(A[0]===6||A[0]===2)){p=0;continue}if(A[0]===3&&(!m||A[1]>m[0]&&A[1]0&&d[d.length-1])&&(u[0]===6||u[0]===2)){r=0;continue}if(u[0]===3&&(!d||u[1]>d[0]&&u[1]{const[t,i,n]=e;this.requestInternal(t,i,n)}),this.messageQueue=[]}request(e,t,i){this.webSocket.readyState===WebSocket.OPEN?this.requestInternal(e,t,i):this.messageQueue.push([e,t,i])}notify(e,t){switch(this.webSocket.readyState){case WebSocket.OPEN:this.serverAndClient.notify(e,t);break}}connect(e){this.closed||(console.log("connect",this.url),this.webSocket=new WebSocket(this.url),this.serverAndClient||(this.serverAndClient=new distExports.JSONRPCServerAndClient(new distExports.JSONRPCServer,new distExports.JSONRPCClient(t=>{try{return this.webSocket.send(JSON.stringify(t)),Promise.resolve()}catch(i){return Promise.reject(i)}}))),this.webSocket.onmessage=t=>{this.serverAndClient.receiveAndSend(JSON.parse(t.data.toString()))},this.webSocket.onopen=()=>{console.log("WebSocket connection established"),this.connectionEstablished=!0,this.onConnected&&this.onConnected(),this.requestMessageQueue()},this.webSocket.onclose=t=>{console.error("WebScoket closed",t),this.serverAndClient.rejectAllPendingRequests(`Connection is closed (${t.reason}).`),this.connectionEstablished&&this.onClosed(),this.timerId=setTimeout(()=>{this.connect()},3e3)},this.webSocket.onerror=t=>{console.error("WebSocket error:",t),this.webSocket.close()})}}const modifierKeys=["Shift","Control","Alt","Meta","CapsLock"],convertKeyTable={Enter:"Return",ArrowRight:"Right",ArrowLeft:"Left",ArrowUp:"Up",ArrowDown:"Down","¡":"1","™":"2","£":"3","¢":"4","∞":"5","§":"6","¶":"7","•":"8",ª:"9",º:"0","–":"-","≠":"=","“":"[","‘":"]","«":"\\","…":";",æ:"'","≤":",","≥":".","÷":"/","⁄":"!","€":"@","‹":"#","›":"$",fi:"%",fl:"^","‡":"&","°":"*","·":"(","‚":")","—":"_","±":"+","”":"{","’":"}","»":"|",Ú:":",Æ:'"',"¯":"<","˘":">","¿":"?",œ:"q","∑":"w","´":"e","®":"r","†":"t","¥":"y","¨":"u","ˆ":"i",ø:"o",π:"p",å:"a",ß:"s","∂":"d",ƒ:"f","©":"g","˙":"h","∆":"j","˚":"k","¬":"l",Ω:"z","≈":"x",ç:"c","√":"v","∫":"b","˜":"n",µ:"m",Œ:"Q","„":"W","´":"E","‰":"R","ˇ":"T",Á:"Y","¨":"U","ˆ":"I",Ø:"O","∏":"P",Å:"A",Í:"S",Î:"D",Ï:"F","˝":"G",Ó:"H",Ô:"J","":"K",Ò:"L","¸":"Z","˛":"X",Ç:"C","◊":"V",ı:"B","˜":"N",Â:"M"};function getKey(o){return o.altKey?convertKeyTable[o.key]||(o.code.startsWith("Key")?o.code[3].toLowerCase():null)||o.key:convertKeyTable[o.key]||o.key}function convertKeyEvent(o){return modifierKeys.indexOf(o.key)!==-1?null:{key:getKey(o),ctrl:o.ctrlKey,meta:o.altKey,super:o.metaKey,shift:o.shiftKey}}var defs=[[0,31,"N"],[32,126,"Na"],[127,160,"N"],[161,161,"A"],[162,163,"Na"],[164,164,"A"],[165,166,"Na"],[167,168,"A"],[169,169,"N"],[170,170,"A"],[171,171,"N"],[172,172,"Na"],[173,174,"A"],[175,175,"Na"],[176,180,"A"],[181,181,"N"],[182,186,"A"],[187,187,"N"],[188,191,"A"],[192,197,"N"],[198,198,"A"],[199,207,"N"],[208,208,"A"],[209,214,"N"],[215,216,"A"],[217,221,"N"],[222,225,"A"],[226,229,"N"],[230,230,"A"],[231,231,"N"],[232,234,"A"],[235,235,"N"],[236,237,"A"],[238,239,"N"],[240,240,"A"],[241,241,"N"],[242,243,"A"],[244,246,"N"],[247,250,"A"],[251,251,"N"],[252,252,"A"],[253,253,"N"],[254,254,"A"],[255,256,"N"],[257,257,"A"],[258,272,"N"],[273,273,"A"],[274,274,"N"],[275,275,"A"],[276,282,"N"],[283,283,"A"],[284,293,"N"],[294,295,"A"],[296,298,"N"],[299,299,"A"],[300,304,"N"],[305,307,"A"],[308,311,"N"],[312,312,"A"],[313,318,"N"],[319,322,"A"],[323,323,"N"],[324,324,"A"],[325,327,"N"],[328,331,"A"],[332,332,"N"],[333,333,"A"],[334,337,"N"],[338,339,"A"],[340,357,"N"],[358,359,"A"],[360,362,"N"],[363,363,"A"],[364,461,"N"],[462,462,"A"],[463,463,"N"],[464,464,"A"],[465,465,"N"],[466,466,"A"],[467,467,"N"],[468,468,"A"],[469,469,"N"],[470,470,"A"],[471,471,"N"],[472,472,"A"],[473,473,"N"],[474,474,"A"],[475,475,"N"],[476,476,"A"],[477,592,"N"],[593,593,"A"],[594,608,"N"],[609,609,"A"],[610,707,"N"],[708,708,"A"],[709,710,"N"],[711,711,"A"],[712,712,"N"],[713,715,"A"],[716,716,"N"],[717,717,"A"],[718,719,"N"],[720,720,"A"],[721,727,"N"],[728,731,"A"],[732,732,"N"],[733,733,"A"],[734,734,"N"],[735,735,"A"],[736,767,"N"],[768,879,"A"],[880,912,"N"],[913,929,"A"],[930,930,"N"],[931,937,"A"],[938,944,"N"],[945,961,"A"],[962,962,"N"],[963,969,"A"],[970,1024,"N"],[1025,1025,"A"],[1026,1039,"N"],[1040,1103,"A"],[1104,1104,"N"],[1105,1105,"A"],[1106,4351,"N"],[4352,4447,"W"],[4448,8207,"N"],[8208,8208,"A"],[8209,8210,"N"],[8211,8214,"A"],[8215,8215,"N"],[8216,8217,"A"],[8218,8219,"N"],[8220,8221,"A"],[8222,8223,"N"],[8224,8226,"A"],[8227,8227,"N"],[8228,8231,"A"],[8232,8239,"N"],[8240,8240,"A"],[8241,8241,"N"],[8242,8243,"A"],[8244,8244,"N"],[8245,8245,"A"],[8246,8250,"N"],[8251,8251,"A"],[8252,8253,"N"],[8254,8254,"A"],[8255,8307,"N"],[8308,8308,"A"],[8309,8318,"N"],[8319,8319,"A"],[8320,8320,"N"],[8321,8324,"A"],[8325,8360,"N"],[8361,8361,"H"],[8362,8363,"N"],[8364,8364,"A"],[8365,8450,"N"],[8451,8451,"A"],[8452,8452,"N"],[8453,8453,"A"],[8454,8456,"N"],[8457,8457,"A"],[8458,8466,"N"],[8467,8467,"A"],[8468,8469,"N"],[8470,8470,"A"],[8471,8480,"N"],[8481,8482,"A"],[8483,8485,"N"],[8486,8486,"A"],[8487,8490,"N"],[8491,8491,"A"],[8492,8530,"N"],[8531,8532,"A"],[8533,8538,"N"],[8539,8542,"A"],[8543,8543,"N"],[8544,8555,"A"],[8556,8559,"N"],[8560,8569,"A"],[8570,8584,"N"],[8585,8585,"A"],[8586,8591,"N"],[8592,8601,"A"],[8602,8631,"N"],[8632,8633,"A"],[8634,8657,"N"],[8658,8658,"A"],[8659,8659,"N"],[8660,8660,"A"],[8661,8678,"N"],[8679,8679,"A"],[8680,8703,"N"],[8704,8704,"A"],[8705,8705,"N"],[8706,8707,"A"],[8708,8710,"N"],[8711,8712,"A"],[8713,8714,"N"],[8715,8715,"A"],[8716,8718,"N"],[8719,8719,"A"],[8720,8720,"N"],[8721,8721,"A"],[8722,8724,"N"],[8725,8725,"A"],[8726,8729,"N"],[8730,8730,"A"],[8731,8732,"N"],[8733,8736,"A"],[8737,8738,"N"],[8739,8739,"A"],[8740,8740,"N"],[8741,8741,"A"],[8742,8742,"N"],[8743,8748,"A"],[8749,8749,"N"],[8750,8750,"A"],[8751,8755,"N"],[8756,8759,"A"],[8760,8763,"N"],[8764,8765,"A"],[8766,8775,"N"],[8776,8776,"A"],[8777,8779,"N"],[8780,8780,"A"],[8781,8785,"N"],[8786,8786,"A"],[8787,8799,"N"],[8800,8801,"A"],[8802,8803,"N"],[8804,8807,"A"],[8808,8809,"N"],[8810,8811,"A"],[8812,8813,"N"],[8814,8815,"A"],[8816,8833,"N"],[8834,8835,"A"],[8836,8837,"N"],[8838,8839,"A"],[8840,8852,"N"],[8853,8853,"A"],[8854,8856,"N"],[8857,8857,"A"],[8858,8868,"N"],[8869,8869,"A"],[8870,8894,"N"],[8895,8895,"A"],[8896,8977,"N"],[8978,8978,"A"],[8979,8985,"N"],[8986,8987,"W"],[8988,9e3,"N"],[9001,9002,"W"],[9003,9192,"N"],[9193,9196,"W"],[9197,9199,"N"],[9200,9200,"W"],[9201,9202,"N"],[9203,9203,"W"],[9204,9311,"N"],[9312,9449,"A"],[9450,9450,"N"],[9451,9547,"A"],[9548,9551,"N"],[9552,9587,"A"],[9588,9599,"N"],[9600,9615,"A"],[9616,9617,"N"],[9618,9621,"A"],[9622,9631,"N"],[9632,9633,"A"],[9634,9634,"N"],[9635,9641,"A"],[9642,9649,"N"],[9650,9651,"A"],[9652,9653,"N"],[9654,9655,"A"],[9656,9659,"N"],[9660,9661,"A"],[9662,9663,"N"],[9664,9665,"A"],[9666,9669,"N"],[9670,9672,"A"],[9673,9674,"N"],[9675,9675,"A"],[9676,9677,"N"],[9678,9681,"A"],[9682,9697,"N"],[9698,9701,"A"],[9702,9710,"N"],[9711,9711,"A"],[9712,9724,"N"],[9725,9726,"W"],[9727,9732,"N"],[9733,9734,"A"],[9735,9736,"N"],[9737,9737,"A"],[9738,9741,"N"],[9742,9743,"A"],[9744,9747,"N"],[9748,9749,"W"],[9750,9755,"N"],[9756,9756,"A"],[9757,9757,"N"],[9758,9758,"A"],[9759,9791,"N"],[9792,9792,"A"],[9793,9793,"N"],[9794,9794,"A"],[9795,9799,"N"],[9800,9811,"W"],[9812,9823,"N"],[9824,9825,"A"],[9826,9826,"N"],[9827,9829,"A"],[9830,9830,"N"],[9831,9834,"A"],[9835,9835,"N"],[9836,9837,"A"],[9838,9838,"N"],[9839,9839,"A"],[9840,9854,"N"],[9855,9855,"W"],[9856,9874,"N"],[9875,9875,"W"],[9876,9885,"N"],[9886,9887,"A"],[9888,9888,"N"],[9889,9889,"W"],[9890,9897,"N"],[9898,9899,"W"],[9900,9916,"N"],[9917,9918,"W"],[9919,9919,"A"],[9920,9923,"N"],[9924,9925,"W"],[9926,9933,"A"],[9934,9934,"W"],[9935,9939,"A"],[9940,9940,"W"],[9941,9953,"A"],[9954,9954,"N"],[9955,9955,"A"],[9956,9959,"N"],[9960,9961,"A"],[9962,9962,"W"],[9963,9969,"A"],[9970,9971,"W"],[9972,9972,"A"],[9973,9973,"W"],[9974,9977,"A"],[9978,9978,"W"],[9979,9980,"A"],[9981,9981,"W"],[9982,9983,"A"],[9984,9988,"N"],[9989,9989,"W"],[9990,9993,"N"],[9994,9995,"W"],[9996,10023,"N"],[10024,10024,"W"],[10025,10044,"N"],[10045,10045,"A"],[10046,10059,"N"],[10060,10060,"W"],[10061,10061,"N"],[10062,10062,"W"],[10063,10066,"N"],[10067,10069,"W"],[10070,10070,"N"],[10071,10071,"W"],[10072,10101,"N"],[10102,10111,"A"],[10112,10132,"N"],[10133,10135,"W"],[10136,10159,"N"],[10160,10160,"W"],[10161,10174,"N"],[10175,10175,"W"],[10176,10213,"N"],[10214,10221,"Na"],[10222,10628,"N"],[10629,10630,"Na"],[10631,11034,"N"],[11035,11036,"W"],[11037,11087,"N"],[11088,11088,"W"],[11089,11092,"N"],[11093,11093,"W"],[11094,11097,"A"],[11098,11903,"N"],[11904,11929,"W"],[11930,11930,"N"],[11931,12019,"W"],[12020,12031,"N"],[12032,12245,"W"],[12246,12271,"N"],[12272,12287,"W"],[12288,12288,"F"],[12289,12350,"W"],[12351,12352,"N"],[12353,12438,"W"],[12439,12440,"N"],[12441,12543,"W"],[12544,12548,"N"],[12549,12591,"W"],[12592,12592,"N"],[12593,12686,"W"],[12687,12687,"N"],[12688,12771,"W"],[12772,12782,"N"],[12783,12830,"W"],[12831,12831,"N"],[12832,12871,"W"],[12872,12879,"A"],[12880,19903,"W"],[19904,19967,"N"],[19968,42124,"W"],[42125,42127,"N"],[42128,42182,"W"],[42183,43359,"N"],[43360,43388,"W"],[43389,44031,"N"],[44032,55203,"W"],[55204,57343,"N"],[57344,63743,"A"],[63744,64255,"W"],[64256,65023,"N"],[65024,65039,"A"],[65040,65049,"W"],[65050,65071,"N"],[65072,65106,"W"],[65107,65107,"N"],[65108,65126,"W"],[65127,65127,"N"],[65128,65131,"W"],[65132,65280,"N"],[65281,65376,"F"],[65377,65470,"H"],[65471,65473,"N"],[65474,65479,"H"],[65480,65481,"N"],[65482,65487,"H"],[65488,65489,"N"],[65490,65495,"H"],[65496,65497,"N"],[65498,65500,"H"],[65501,65503,"N"],[65504,65510,"F"],[65511,65511,"N"],[65512,65518,"H"],[65519,65532,"N"],[65533,65533,"A"],[65534,94175,"N"],[94176,94180,"W"],[94181,94191,"N"],[94192,94193,"W"],[94194,94207,"N"],[94208,100343,"W"],[100344,100351,"N"],[100352,101589,"W"],[101590,101631,"N"],[101632,101640,"W"],[101641,110575,"N"],[110576,110579,"W"],[110580,110580,"N"],[110581,110587,"W"],[110588,110588,"N"],[110589,110590,"W"],[110591,110591,"N"],[110592,110882,"W"],[110883,110897,"N"],[110898,110898,"W"],[110899,110927,"N"],[110928,110930,"W"],[110931,110932,"N"],[110933,110933,"W"],[110934,110947,"N"],[110948,110951,"W"],[110952,110959,"N"],[110960,111355,"W"],[111356,126979,"N"],[126980,126980,"W"],[126981,127182,"N"],[127183,127183,"W"],[127184,127231,"N"],[127232,127242,"A"],[127243,127247,"N"],[127248,127277,"A"],[127278,127279,"N"],[127280,127337,"A"],[127338,127343,"N"],[127344,127373,"A"],[127374,127374,"W"],[127375,127376,"A"],[127377,127386,"W"],[127387,127404,"A"],[127405,127487,"N"],[127488,127490,"W"],[127491,127503,"N"],[127504,127547,"W"],[127548,127551,"N"],[127552,127560,"W"],[127561,127567,"N"],[127568,127569,"W"],[127570,127583,"N"],[127584,127589,"W"],[127590,127743,"N"],[127744,127776,"W"],[127777,127788,"N"],[127789,127797,"W"],[127798,127798,"N"],[127799,127868,"W"],[127869,127869,"N"],[127870,127891,"W"],[127892,127903,"N"],[127904,127946,"W"],[127947,127950,"N"],[127951,127955,"W"],[127956,127967,"N"],[127968,127984,"W"],[127985,127987,"N"],[127988,127988,"W"],[127989,127991,"N"],[127992,128062,"W"],[128063,128063,"N"],[128064,128064,"W"],[128065,128065,"N"],[128066,128252,"W"],[128253,128254,"N"],[128255,128317,"W"],[128318,128330,"N"],[128331,128334,"W"],[128335,128335,"N"],[128336,128359,"W"],[128360,128377,"N"],[128378,128378,"W"],[128379,128404,"N"],[128405,128406,"W"],[128407,128419,"N"],[128420,128420,"W"],[128421,128506,"N"],[128507,128591,"W"],[128592,128639,"N"],[128640,128709,"W"],[128710,128715,"N"],[128716,128716,"W"],[128717,128719,"N"],[128720,128722,"W"],[128723,128724,"N"],[128725,128727,"W"],[128728,128731,"N"],[128732,128735,"W"],[128736,128746,"N"],[128747,128748,"W"],[128749,128755,"N"],[128756,128764,"W"],[128765,128991,"N"],[128992,129003,"W"],[129004,129007,"N"],[129008,129008,"W"],[129009,129291,"N"],[129292,129338,"W"],[129339,129339,"N"],[129340,129349,"W"],[129350,129350,"N"],[129351,129535,"W"],[129536,129647,"N"],[129648,129660,"W"],[129661,129663,"N"],[129664,129672,"W"],[129673,129679,"N"],[129680,129725,"W"],[129726,129726,"N"],[129727,129733,"W"],[129734,129741,"N"],[129742,129755,"W"],[129756,129759,"N"],[129760,129768,"W"],[129769,129775,"N"],[129776,129784,"W"],[129785,131071,"N"],[131072,196605,"W"],[196606,196607,"N"],[196608,262141,"W"],[262142,917759,"N"],[917760,917999,"A"],[918e3,983039,"N"],[983040,1048573,"A"],[1048574,1048575,"N"],[1048576,1114109,"A"],[1114110,1114111,"N"]];function getEAWOfCodePoint(o){let e=0,t=defs.length-1;for(;e!==t;){const i=e+(t-e>>1),[n,s,r]=defs[i];if(os)e=i+1;else return r}return defs[e][2]}function getEAW(o,e=0){const t=o.codePointAt(e);if(t!==void 0)return getEAWOfCodePoint(t)}const textOffsetY=5,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function isWideChar(o){switch(getEAW(o)){case"F":case"W":return!0;case"A":default:return!1}}function isMacOS(){return window.navigator.userAgent.indexOf("Mac OS X")!==-1}function computeFontSize(o){const t=document.createElement("canvas").getContext("2d");t.font=o;const i=t.measureText("W");return[Math.floor(i.width),Math.round(i.fontBoundingBoxAscent+textOffsetY+(i.emHeightDescent||0))]}function drawBlock({ctx:o,x:e,y:t,width:i,height:n,style:s}){o.fillStyle=s,o.fillRect(e,t,i,n)}function drawText({ctx:o,x:e,y:t,text:i,font:n,style:s,option:r}){t+=Math.round(textOffsetY),o.fillStyle=s,o.font=n,o.textBaseline="top";for(const l of i)isWideChar(l)?(o.fillText(l,e,t,r.fontWidth*2),e+=r.fontWidth*2):(o.fillText(l,e,t,r.fontWidth),e+=r.fontWidth)}function drawHorizontalLine({ctx:o,x:e,y:t,width:i,style:n,lineWidth:s=1}){o.strokeStyle=n,o.lineWidth=s,o.setLineDash=[],o.beginPath(),o.moveTo(e,t),o.lineTo(e+i,t),o.stroke()}class Option{constructor({fontName:e,fontSize:t}){this.setFont(e,t),this.foreground="#cccccc",this.background="#2d2d2d"}setFont(e,t){const i=t+"px "+e,[n,s]=computeFontSize(i);this.fontName=e,this.fontSize=t,this.fontWidth=n,this.fontHeight=s,this.font=i}}function getLemEditorElement(){return document.getElementById("lem-editor")}function normalizeWheelDelta(o,e,t,i){switch(t){case 0:return{dx:o/i,dy:e/i};case 2:return{dx:o*20,dy:e*20};default:return{dx:o,dy:e}}}function extractWholeLines(o,e){const t=Math.trunc(o),i=Math.trunc(e);return{scrollX:t,scrollY:i,remainderX:o-t,remainderY:e-i}}function cursorPosition(o,e){const[t,i]=e.getDisplayRectangle(),n=o.clientX-t,s=o.clientY-i;return{pixelX:n,pixelY:s,x:Math.floor(n/e.option.fontWidth),y:Math.floor(s/e.option.fontHeight)}}function makeWheelHandler(o){let e={x:0,y:0},t=!1,i={pixelX:0,pixelY:0,x:0,y:0};return n=>{n.preventDefault(),i=cursorPosition(n,o);const{dx:s,dy:r}=normalizeWheelDelta(n.deltaX,n.deltaY,n.deltaMode,o.option.fontHeight);e={x:e.x+s,y:e.y+r},t||(t=!0,requestAnimationFrame(()=>{t=!1;const{scrollX:l,scrollY:f,remainderX:d,remainderY:y}=extractWholeLines(e.x,e.y);e={x:d,y},(l!==0||f!==0)&&o.jsonrpc.notify("input",{kind:"wheel",value:{...i,wheelX:-l,wheelY:-f}})}))}}function addMouseEventListeners({dom:o,editor:e,isDraggable:t,draggableStyle:i}){o.addEventListener("contextmenu",r=>{r.preventDefault()});const n=(r,l)=>{r.preventDefault();const[f,d]=e.getDisplayRectangle(),y=r.clientX-f,v=r.clientY-d,N=Math.floor(y/e.option.fontWidth),u=Math.floor(v/e.option.fontHeight);e.jsonrpc.notify("input",{kind:l,value:{x:N,y:u,pixelX:y,pixelY:v,button:r.button,clicks:r.detail}})};o.addEventListener("mousedown",r=>{t&&(document.body.style.cursor=i),e.focusHiddenInput(),n(r,"mousedown")}),o.addEventListener("mouseup",r=>{t&&(document.body.style.cursor="default"),n(r,"mouseup")});let s=0;o.addEventListener("mousemove",r=>{r.preventDefault();const l=Date.now();if(l-s>50){s=l;const[f,d]=e.getDisplayRectangle(),y=r.clientX-f,v=r.clientY-d,N=Math.floor(y/e.option.fontWidth),u=Math.floor(v/e.option.fontHeight);e.jsonrpc.notify("input",{kind:"mousemove",value:{x:N,y:u,pixelX:y,pixelY:v,button:r.buttons===0?null:r.buttons-1}})}}),t&&(o.addEventListener("mouseover",()=>{document.body.style.cursor=i}),o.addEventListener("mouseout",r=>{r.buttons!==1&&(document.body.style.cursor="default")})),o.addEventListener("wheel",makeWheelHandler(e))}const zIndexTable={"floating-window":200,modeline:100,"vertical-border":100,"horizontal-border":101};function zindex(o){return zIndexTable[o]||0}const borderOffsetX=5,borderOffsetY=10;class BaseSurface{constructor({editor:o}){this.editor=o,this.mainDOM=null,this.wrapper=null}delete(){this.wrapper?getLemEditorElement().removeChild(this.wrapper):getLemEditorElement().removeChild(this.mainDOM)}setupDOM({dom:o,isFloating:e,border:t,cssClassName:i}){this.mainDOM=o,e&&t?(this.wrapper=document.createElement("div"),i&&(this.wrapper.className=i),this.wrapper.style.position="absolute",this.wrapper.style.backgroundColor=this.editor.option.background,this.wrapper.style.zIndex=zindex("floating-window"),this.wrapper.appendChild(o),getLemEditorElement().appendChild(this.wrapper)):(i&&(o.className=i),getLemEditorElement().appendChild(o))}move(o,e,t,i){const[n,s]=this.editor.getDisplayRectangle(),r=t!=null?Math.floor(n+t):Math.floor(n+o*this.editor.option.fontWidth),l=i!=null?Math.floor(s+i):Math.floor(s+e*this.editor.option.fontHeight);this.wrapper?(this.wrapper.style.left=r-borderOffsetX+"px",this.wrapper.style.top=l-borderOffsetY+"px",this.mainDOM.style.left=borderOffsetX+"px",this.mainDOM.style.top=borderOffsetY+"px"):(this.mainDOM.style.left=r+"px",this.mainDOM.style.top=l+"px")}_resize(o,e,t,i){const n=window.devicePixelRatio||1,s=t??o*this.editor.option.fontWidth,r=i??e*this.editor.option.fontHeight;this.mainDOM.width=s*n,this.mainDOM.height=r*n,this.mainDOM.style.width=s+"px",this.mainDOM.style.height=r+"px",this.wrapper&&(this.wrapper.style.width=s+borderOffsetX*2+"px",this.wrapper.style.height=r+borderOffsetY*2+"px")}drawBlock(o,e,t,i,n){}drawText(o,e,t,i,n){}touch(){}evalIn(code){return eval(code)}}class CanvasSurface extends BaseSurface{constructor({editor:e,view:t,x:i,y:n,width:s,height:r,styles:l,isFloating:f,border:d,cssClassName:y}){super({editor:e});const v=this.setupCanvas(l);this.setupDOM({dom:v,isFloating:f,border:d,cssClassName:y}),this.move(i,n),this.resize(s,r),this.drawingQueue=[],addMouseEventListeners({dom:v,editor:e})}setupCanvas(e){const t=document.createElement("canvas");if(t.style.position="absolute",e)for(let i in e)t.style[i]=e[i];return t}resize(e,t,i,n){this._resize(e,t,i,n);const s=window.devicePixelRatio||1;this.mainDOM.getContext("2d").scale(s,s)}drawBlock(e,t,i,n,s){const r=this.editor.option;this.drawingQueue.push(function(l){drawBlock({ctx:l,x:e*r.fontWidth,y:t*r.fontHeight,width:i*r.fontWidth,height:n*r.fontHeight,style:s})})}drawText(e,t,i,n,s,r){const l=this.editor.option;this.drawingQueue.push(function(f){if(r=r?`${l.fontSize}px ${r}`:l.font,!s)drawBlock({ctx:f,x:e*l.fontWidth,y:t*l.fontHeight,width:n*l.fontWidth,height:l.fontHeight,style:l.background}),drawText({ctx:f,x:e*l.fontWidth,y:t*l.fontHeight,text:i,style:l.foreground,font:r,option:l});else{let{foreground:d,background:y,bold:v,reverse:N,underline:u,cursor:h}=s;if(d||(d=l.foreground),y||(y=l.background),N){const p=y;y=d,d=p}h&&(y=l.background);const a=e*l.fontWidth,c=t*l.fontHeight;drawBlock({ctx:f,x:a,y:c,width:n*l.fontWidth,height:l.fontHeight,style:y}),drawText({ctx:f,x:a,y:c,text:i,style:d,font:v?"bold "+r:r,option:l}),u&&drawHorizontalLine({ctx:f,x:a,y:c+l.fontHeight-2,width:n*l.fontWidth,style:typeof u=="string"?u:d,lineWidth:2})}})}touch(){const e=this.mainDOM.getContext("2d");for(let t of this.drawingQueue)t(e);this.drawingQueue=[]}activate(){this.mainDOM.dataset.store="active"}deactivate(){this.mainDOM.dataset.store="inactive"}}class HTMLSurface extends BaseSurface{constructor({editor:e,x:t,y:i,width:n,height:s,styles:r,option:l,isFloating:f,border:d,html:y}){super({editor:e});const v=document.createElement("iframe");this.setupDOM({dom:v,isFloating:f,border:d}),v.style.position="absolute",v.style.backgroundColor=l.background,v.setAttribute("sandbox","allow-scripts allow-same-origin"),v.srcdoc=y,v.addEventListener("load",()=>{const N=v.contentWindow;N.invokeLem=(u,h)=>parent.postMessage({type:"invoke-lem",method:u,args:h})}),this.iframe=v,this.move(t,i),this.resize(n,s)}resize(e,t,i,n){this._resize(e,t,i,n)}update(e){const t=this.iframe.contentWindow.scrollY;this.iframe.srcdoc=e,this.iframe.onload=()=>{this.iframe.onload=null,this.iframe.contentWindow.scrollTo(0,t)}}evalIn(e){return this.iframe.contentWindow.eval(e)}}class VerticalBorder{constructor({x:e,y:t,height:i,option:n,editor:s}){this.option=n,this.editor=s,this.line=document.createElement("div"),this.line.className="lem-editor__vertical-border",this.line.style.height=i*n.fontHeight+"px",this.line.style.position="absolute",this.line.style.zIndex=zindex("vertical-border"),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:s,isDraggable:!0,draggableStyle:"col-resize"})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){const[i,n]=this.editor.getDisplayRectangle();this.line.style.left=Math.floor(i+e*this.option.fontWidth-this.option.fontWidth/2)+"px",this.line.style.top=n+t*this.option.fontHeight+"px"}resize(e){this.line.style.height=e*this.option.fontHeight+"px"}}class HorizontalBorder{constructor({x:e,y:t,width:i,option:n,editor:s}){this.option=n,this.editor=s,this.line=document.createElement("div"),this.line.className="lem-editor__horizontal-border",this.line.style.width=i*n.fontWidth+"px",this.line.style.position="absolute",this.line.style.zIndex=zindex("horizontal-border"),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:s,isDraggable:!0,draggableStyle:"row-resize"})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){const[i,n]=this.editor.getDisplayRectangle();this.line.style.left=i+e*this.option.fontWidth+"px",this.line.style.top=Math.floor(n+t*this.option.fontHeight-4)+"px"}resize(e){this.line.style.width=e*this.option.fontWidth+"px"}}const viewStyles={header:()=>{},tile:()=>{},floating:o=>({boxSizing:"border-box",borderColor:o.foreground,backgroundColor:o.background})};function getViewStyle(o,e){return viewStyles[o](e)||{}}class View{constructor({id:e,x:t,y:i,width:n,height:s,pixelX:r,pixelY:l,pixelWidth:f,pixelHeight:d,useModeline:y,kind:v,type:N,content:u,border:h,borderShape:a,option:c,editor:p}){switch(this.option=c,this.id=e,this.x=t,this.y=i,this.width=n,this.height=s,this.pixelX=r,this.pixelY=l,this.pixelWidth=f,this.pixelHeight=d,this.useModeline=y,this.kind=v,this.type=N,this.border=h,this.borderShape=a,this.editor=p,this.bottomBar=null,this.leftsideBar=null,v){case"tile":this.mainSurface=this.makeSurface(N,u),this.leftSideBar=new VerticalBorder({x:t,y:i,height:s+(y?1:0),option:c,editor:p}),y||(this.bottomBar=new HorizontalBorder({x:t,y:i+s-1,width:n,option:c,editor:p}));break;case"header":this.mainSurface=this.makeSurface(N,u);break;case"floating":this.mainSurface=this.makeSurface(N,u),a==="left-border"&&(this.leftSideBar=new VerticalBorder({x:t,y:i,height:s,option:c,editor:p}));break}this.modelineSurface=y?this.makeModelineSurface():null,v==="floating"&&(r!=null||l!=null)&&this.move(t,i,r,l)}delete(){this.mainSurface.delete(),this.modelineSurface&&this.modelineSurface.delete(),this.leftSideBar&&this.leftSideBar.delete(),this.bottomBar&&this.bottomBar.delete()}move(e,t,i,n){if(this.x=e,this.y=t,this.pixelX=i,this.pixelY=n,this.mainSurface.move(e,t,i,n),this.modelineSurface){const s=n!=null&&this.pixelHeight!=null?n+this.pixelHeight:null;this.modelineSurface.move(e,t+this.height,i,s)}this.leftSideBar&&this.leftSideBar.move(e,t),this.bottomBar&&this.bottomBar.move(e,t+this.height)}resize(e,t,i,n){if(this.width=e,this.height=t,this.pixelWidth=i,this.pixelHeight=n,this.mainSurface.resize(e,t,i,n),this.modelineSurface){const s=this.pixelY!=null&&n!=null?this.pixelY+n:null;this.modelineSurface.move(this.x,this.y+this.height,this.pixelX,s),this.modelineSurface.resize(e,1)}this.leftSideBar&&this.leftSideBar.resize(t+(this.modelineSurface?1:0)),this.bottomBar&&this.bottomBar.resize(e)}clear(){this.mainSurface.drawBlock(0,0,this.width,this.height,this.option.background)}clearEol(e,t){this.mainSurface.drawBlock(e,t,this.width-e,1,this.option.background)}clearEob(e,t){this.mainSurface.drawBlock(e,t,this.width,this.height-t,this.option.background)}print(e,t,i,n,s,r){this.mainSurface.drawText(e,t,i,n,s,r)}printToModeline(e,t,i,n,s){this.modelineSurface&&this.modelineSurface.drawText(e,t,i,n,s)}touch(e){this.mainSurface.touch(),this.modelineSurface&&(this.modelineSurface.touch(),e?this.modelineSurface.activate():this.modelineSurface.deactivate())}makeSurface(e,t){switch(e){case"html":return this.makeHTMLSurface(t);case"editor":return this.makeEditorSurface();default:console.error(`unknown type: ${e}`)}}makeHTMLSurface(e){return new HTMLSurface({editor:this.editor,x:this.x,y:this.y,width:this.width,height:this.height,styles:getViewStyle(this.kind,this.option),option:this.option,isFloating:this.kind==="floating",border:this.border,html:e})}makeEditorSurface(){const e=this.borderShape==="left-border"?0:this.border,t=this.kind==="floating";return new CanvasSurface({option:this.editor.option,x:this.x,y:this.y,width:this.width,height:this.height,styles:getViewStyle(this.kind,this.option),editor:this.editor,border:e,isFloating:t,view:this,cssClassName:t&&e?"lem-editor__floating-window--bordered":null})}makeModelineSurface(){const e=new CanvasSurface({option:this.editor.option,x:this.x,y:this.y+this.height,width:this.width,height:1,editor:this.editor,view:this,styles:{zIndex:zindex("modeline")},cssClassName:"lem-editor__mode-line"});return addMouseEventListeners({dom:e.mainDOM,editor:this.editor,isDraggable:!0,draggableStyle:"row-resize"}),e}changeToHTMLContent(e){this.mainSurface.constructor.name==="HTMLSurface"?this.mainSurface.update(e):(this.mainSurface.delete(),this.mainSurface=this.makeHTMLSurface(e))}changeToEditorContent(){this.mainSurface.delete(),this.mainSurface=this.makeEditorSurface()}evalIn(e){return this.mainSurface.evalIn(e)}}function isPasteKeyEvent(o){return isMacOS()?o.metaKey&&o.key==="v":o.ctrlKey&&o.shiftKey&&o.key==="V"}class Input{constructor(e){const t=e.option;this.editor=e,this.composition=!1,this.ignoreKeydownAfterCompositionend=!1,this.span=document.createElement("span"),this.span.style.color=t.foreground,this.span.style.backgroundColor=t.background,this.span.style.position="absolute",this.span.style.zIndex=1e6,this.span.style.top="0",this.span.style.left="0",this.span.style.font=t.font,this.input=document.createElement("input"),this.input.style.backgroundColor="transparent",this.input.style.color="transparent",this.input.style.width="0",this.input.style.padding="0",this.input.style.margin="0",this.input.style.border="none",this.input.style.position="absolute",this.input.style.zIndex="-10",this.input.style.top="0",this.input.style.left="0",this.input.style.font=t.font,this.input.addEventListener("blur",i=>{this.input.focus()}),this.input.addEventListener("input",i=>{this.composition===!1&&(this.input.value="",this.span.innerHTML="",this.input.style.width="0",isMacOS()||this.editor.emitInputString(i.data))}),this.input.addEventListener("paste",async i=>{i.preventDefault();const n=i.clipboardData||window.Clipboard.data,s=n?.getData("text")??n?.getData("text/plain");if(s&&s.length>0){this.editor.emitInputString(s);return}try{if(navigator.clipboard?.readText){const r=await navigator.clipboard.readText();if(r&&r.length>0){this.editor.emitInputString(r);return}}}catch(r){console.warn("clipboard.readText() failed:",r)}alert("Paste failed (permission/environment restriction")}),this.input.addEventListener("keydown",i=>{if(!isPasteKeyEvent(i)&&!(i.isComposing||this.composition)&&i.key!=="Process"){if(this.ignoreKeydownAfterCompositionend&&(isSafari||isMacOS())){i.preventDefault(),this.ignoreKeydownAfterCompositionend=!1;return}if(!(!isMacOS()&&!i.ctrlKey&&!i.altKey&&i.key.length===1)&&(i.preventDefault(),i.isComposing!==!0&&i.code!==""))return setTimeout(()=>{this.composition||(this.editor.emitInput(i),this.input.value="")},0),!1}}),this.input.addEventListener("compositionstart",i=>{this.composition=!0,this.span.innerHTML=this.input.value,this.input.style.width=this.span.offsetWidth+"px"}),this.input.addEventListener("compositionupdate",i=>{this.span.innerHTML=i.data,this.input.style.width=this.span.offsetWidth+"px"}),this.input.addEventListener("compositionend",i=>{this.composition=!1,this.editor.emitInputString(this.input.value),this.input.value="",this.span.innerHTML=this.input.value,this.input.style.width="0",this.ignoreKeydownAfterCompositionend=!0}),document.body.appendChild(this.input),document.body.appendChild(this.span),this.input.focus()}finalize(){document.body.removeChild(this.input),document.body.removeChild(this.span)}move(e,t){const[i,n]=this.editor.getDisplayRectangle();this.span.style.top=n+t+"px",this.span.style.left=i+e+"px",this.input.style.top=this.span.offsetTop+"px",this.input.style.left=this.span.offsetLeft+"px"}updateForeground(e){this.span.style.color=e}updateBackground(e){this.span.style.backgroundColor=e}}class MessageTable{constructor(){this.map=new Map}register(e,t){for(const i in t){const n=t[i];this.map.set(i,n),e.on(i,n)}}get(e){return this.map.get(e)}}function getDisplayRectangleDefault(){return[0,0,window.innerWidth,window.innerHeight]}class Editor{constructor({getDisplayRectangle:e=getDisplayRectangleDefault,fontName:t,fontSize:i,url:n,onExit:s,onClosed:r}){this.getDisplayRectangle=e,this.option=new Option({fontName:t,fontSize:i}),this.onExit=s,this.input=new Input(this),this.cursors=new Map,this.cursorOverlay=document.createElement("div"),this.cursorOverlay.className="lem-cursor",this.cursorOverlay.style.width=this.option.fontWidth+"px",this.cursorOverlay.style.height=this.option.fontHeight+"px",this.cursorOverlay.style.backgroundColor="#ffffff",this.cursorType="box",this.viewMap=new Map,this.jsonrpc=new JSONRPC(n,{onClosed:()=>{r()}}),this.messageTable=new MessageTable,this.messageTable.register(this.jsonrpc,{"update-foreground":this.updateForeground.bind(this),"update-background":this.updateBackground.bind(this),"make-view":this.makeView.bind(this),"delete-view":this.deleteView.bind(this),"resize-view":this.resize.bind(this),"move-view":this.move.bind(this),"redraw-view-after":this.redrawViewAfter.bind(this),clear:this.clear.bind(this),"clear-eol":this.clearEol.bind(this),"clear-eob":this.clearEob.bind(this),put:this.put.bind(this),"modeline-put":this.modelinePut.bind(this),"update-display":this.updateDisplay.bind(this),"move-cursor":this.moveCursor.bind(this),"change-view":this.changeView.bind(this),"resize-display":this.resizeDisplay.bind(this),bulk:this.bulk.bind(this),exit:this.exitEditor.bind(this),"get-clipboard-text":this.getClipboardText.bind(this),"set-clipboard-text":this.setClipboardText.bind(this),"js-eval":this.jsEval.bind(this),"set-font":this.setFont.bind(this),"get-font":this.getFont.bind(this),"get-display-size":this.getDisplaySize.bind(this),"load-css":this.loadCSS.bind(this),"update-cursor-shape":this.updateCursorShape.bind(this)}),this.login(),this.boundedHandleResize=this.handleResize.bind(this),this.focusHiddenInput=this.focusHiddenInput.bind(this)}init(){window.addEventListener("resize",this.boundedHandleResize),document.getElementsByTagName("html")[0].style["background-color"]="#333",getLemEditorElement().appendChild(this.cursorOverlay)}finalize(){window.removeEventListener("resize",this.boundedHandleResize),this.input.finalize(),this.cursorOverlay.parentNode&&this.cursorOverlay.parentNode.removeChild(this.cursorOverlay)}closeConnection(){this.jsonrpc.close()}emitInput(e){const t=convertKeyEvent(e);if(t){if(t.key==="]"&&t.ctrl&&!t.meta&&!t.super&&!t.shift){this.jsonrpc.notify("input",{kind:"abort"});return}t.key!=="Unidentified"&&this.jsonrpc.notify("input",{kind:"key",value:t})}}emitInputString(e){e?this.jsonrpc.notify("input",{kind:"input-string",value:e}):console.error("unexpected argument",e)}handleResize(e){this.jsonrpc.notify("redraw",{size:this.getDisplaySize()})}focusHiddenInput(){const e=this.input?.input;if(e){try{window.focus()}catch{}requestAnimationFrame(()=>{setTimeout(()=>{e.focus({preventScroll:!0})},0)})}}sendNotification(e,t){this.jsonrpc.notify(e,t)}request(e,t,i){this.jsonrpc.request(e,t,i)}getDisplaySize(){const[e,t,i,n]=this.getDisplayRectangle(),s=Math.floor(i/this.option.fontWidth),r=Math.floor(n/this.option.fontHeight);return{width:s,height:r}}callMessage(e,t){this.messageTable.get(e)(t)}findViewById(e){return this.viewMap.get(e)}login(){this.jsonrpc.request("login",{size:this.getDisplaySize(),foreground:this.option.foreground,background:this.option.background},e=>{if(this.updateForeground(e.foreground),this.updateBackground(e.background),e.views)for(const t of e.views)this.makeView(t);this.jsonrpc.notify("redraw",{size:this.getDisplaySize()})})}updateForeground(e){e!=null&&(this.option.foreground=e,this.input.updateForeground(e))}updateBackground(e){if(e==null)return;this.option.background=e,this.input.updateBackground(e);const t=getLemEditorElement();t.style.backgroundColor=e}makeView({id:e,x:t,y:i,width:n,height:s,pixelX:r,pixelY:l,pixelWidth:f,pixelHeight:d,use_modeline:y,kind:v,type:N,content:u,border:h,border_shape:a}){const c=new View({option:this.option,id:e,x:t,y:i,width:n,height:s,pixelX:r,pixelY:l,pixelWidth:f,pixelHeight:d,useModeline:y,kind:v,type:N,content:u,border:h,borderShape:a,editor:this});this.viewMap.set(e,c)}deleteView({viewInfo:{id:e}}){this.findViewById(e).delete(),this.viewMap.delete(e)}resize({viewInfo:{id:e},width:t,height:i,pixelWidth:n,pixelHeight:s}){const r=this.findViewById(e);r?r.resize(t,i,n,s):console.warn(`resize: view not found for id ${e}`)}move({viewInfo:{id:e},x:t,y:i,pixelX:n,pixelY:s}){const r=this.findViewById(e);r?r.move(t,i,n,s):console.warn(`move: view not found for id ${e}`)}redrawViewAfter({viewInfo:{id:e},isActive:t}){this.findViewById(e).touch(t)}clear({viewInfo:{id:e}}){this.findViewById(e).clear()}clearEol({viewInfo:{id:e},x:t,y:i}){this.findViewById(e).clearEol(t,i)}clearEob({viewInfo:{id:e},x:t,y:i}){this.findViewById(e).clearEob(t,i)}put({viewInfo:{id:e},x:t,y:i,text:n,textWidth:s,attribute:r,font:l}){this.findViewById(e).print(t,i,n,s,r,l)}modelinePut({viewInfo:{id:e},x:t,y:i,text:n,textWidth:s,attribute:r}){this.findViewById(e).printToModeline(t,i,n,s,r)}updateDisplay(){}moveCursor({viewInfo:{id:e},x:t,y:i,color:n,cursorText:s,cursorForeground:r}){const l=this.findViewById(e),[f,d]=this.getDisplayRectangle(),y=l.x*this.option.fontWidth+t*this.option.fontWidth,v=l.y*this.option.fontHeight+i*this.option.fontHeight;this.input.move(y,v);const N=n||this.option.foreground,u=r||this.option.background,h=this.cursorOverlay;switch(this.cursorType){case"bar":h.style.left=f+y+"px",h.style.top=d+v+"px",h.style.width="2px",h.style.height=this.option.fontHeight+"px",h.style.backgroundColor=N,h.textContent="",h.style.color="",h.style.font="",h.style.paddingTop="";break;case"underline":h.style.left=f+y+"px",h.style.top=d+v+this.option.fontHeight-2+"px",h.style.width=this.option.fontWidth+"px",h.style.height="2px",h.style.backgroundColor=N,h.textContent="",h.style.color="",h.style.font="",h.style.paddingTop="";break;case"box":default:h.style.left=f+y+"px",h.style.top=d+v+"px",h.style.width=this.option.fontWidth+"px",h.style.height=this.option.fontHeight+"px",h.style.backgroundColor=N,h.style.font=this.option.font,h.style.paddingTop=textOffsetY+"px",h.textContent=s||"",h.style.color=u;break}h.style.animation="none",h.offsetHeight,h.style.animation=""}updateCursorShape({cursorType:e}){this.cursorType=e||"box"}changeView({viewInfo:{id:e},type:t,content:i}){const n=this.findViewById(e);switch(t){case"html":n.changeToHTMLContent(i);break;case"editor":n.changeToEditorContent();break}}resizeDisplay({width:e,height:t}){const i=getLemEditorElement();i.style.width=Math.floor(e*this.option.fontWidth)+"px",i.style.height=Math.floor(t*this.option.fontHeight)+"px"}bulk(e){for(const{method:t,argument:i}of e)this.callMessage(t,i)}exitEditor(){this.onExit&&this.onExit()}getClipboardText(){navigator.clipboard?.readText().then(e=>{this.jsonrpc.notify("got-clipboard-text",{text:e})})}setClipboardText({text:e}){navigator.clipboard&&navigator.clipboard.writeText(e)}jsEval({viewInfo:{id:e},code:t}){const n=this.findViewById(e).evalIn(t);return n&&n.toString()}setFont({fontName:e,fontSize:t}){this.option.setFont(e||this.option.fontName,t||this.option.fontSize)}getFont(){return{name:this.option.fontName,size:this.option.fontSize}}loadCSS({content:e}){const t=document.createElement("style");t.textContent=e,document.head.appendChild(t)}notifyToServer(e,t){this.jsonrpc.notify("invoke",{method:e,args:t})}}const canvas=document.querySelector("#editor");async function main(){await Promise.all([document.fonts.load("19px file-icons"),document.fonts.load("19px AllTheIcons"),document.fonts.load("19px fontawesome"),document.fonts.load("19px material-design-icons"),document.fonts.load("19px octicons")]),await document.fonts.ready;const o=window.location.protocol==="https:"?"wss":"ws",e=new Editor({canvas,fontName:"Monospace",fontSize:18,url:`${o}://${window.location.hostname}:${window.location.port}`,onExit:null,onClosed:null});window.addEventListener("message",t=>{t.data.type==="invoke-lem"&&e.notifyToServer(t.data.method,t.data.args)}),e.init()}main(); +var __defProp=Object.defineProperty,__commonJSMin=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),__exportAll=(e,t)=>{let n={};for(var r in e)__defProp(n,r,{get:e[r],enumerable:!0});return t||__defProp(n,Symbol.toStringTag,{value:`Module`}),n};(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var require_models=__commonJSMin((e=>{var t=e&&e.__extends||(function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};return function(t,n){if(typeof n!=`function`&&n!==null)throw TypeError(`Class extends value `+String(n)+` is not a constructor or null`);e(t,n);function r(){this.constructor=t}t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}})();Object.defineProperty(e,"__esModule",{value:!0}),e.createJSONRPCNotification=e.createJSONRPCRequest=e.createJSONRPCSuccessResponse=e.createJSONRPCErrorResponse=e.JSONRPCErrorCode=e.JSONRPCErrorException=e.isJSONRPCResponses=e.isJSONRPCResponse=e.isJSONRPCRequests=e.isJSONRPCRequest=e.isJSONRPCID=e.JSONRPC=void 0,e.JSONRPC=`2.0`,e.isJSONRPCID=function(e){return typeof e==`string`||typeof e==`number`||e===null},e.isJSONRPCRequest=function(t){return t.jsonrpc===e.JSONRPC&&t.method!==void 0&&t.result===void 0&&t.error===void 0},e.isJSONRPCRequests=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCRequest)},e.isJSONRPCResponse=function(t){return t.jsonrpc===e.JSONRPC&&t.id!==void 0&&(t.result!==void 0||t.error!==void 0)},e.isJSONRPCResponses=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCResponse)};var n=function(e,t,n){var r={code:e,message:t};return n!=null&&(r.data=n),r};e.JSONRPCErrorException=function(e){t(r,e);function r(t,n,i){var a=e.call(this,t)||this;return Object.setPrototypeOf(a,r.prototype),a.code=n,a.data=i,a}return r.prototype.toObject=function(){return n(this.code,this.message,this.data)},r}(Error),(function(e){e[e.ParseError=-32700]=`ParseError`,e[e.InvalidRequest=-32600]=`InvalidRequest`,e[e.MethodNotFound=-32601]=`MethodNotFound`,e[e.InvalidParams=-32602]=`InvalidParams`,e[e.InternalError=-32603]=`InternalError`})(e.JSONRPCErrorCode||={}),e.createJSONRPCErrorResponse=function(t,r,i,a){return{jsonrpc:e.JSONRPC,id:t,error:n(r,i,a)}},e.createJSONRPCSuccessResponse=function(t,n){return{jsonrpc:e.JSONRPC,id:t,result:n??null}},e.createJSONRPCRequest=function(t,n,r){return{jsonrpc:e.JSONRPC,id:t,method:n,params:r}},e.createJSONRPCNotification=function(t,n){return{jsonrpc:e.JSONRPC,method:t,params:n}}})),require_internal=__commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.DefaultErrorCode=void 0,e.DefaultErrorCode=0})),require_client=__commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{Object.defineProperty(e,"__esModule",{value:!0})})),require_server=__commonJSMin((e=>{var t=e&&e.__assign||function(){return t=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__createBinding||(Object.create?(function(e,t,n,r){r===void 0&&(r=n);var i=Object.getOwnPropertyDescriptor(t,n);(!i||(`get`in i?!t.__esModule:i.writable||i.configurable))&&(i={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,i)}):(function(e,t,n,r){r===void 0&&(r=n),e[r]=t[n]})),n=e&&e.__exportStar||function(e,n){for(var r in e)r!=="default"&&!Object.prototype.hasOwnProperty.call(n,r)&&t(n,e,r)};Object.defineProperty(e,"__esModule",{value:!0}),n(require_client(),e),n(require_interfaces(),e),n(require_models(),e),n(require_server(),e),n(require_server_and_client(),e)})),import_dist=require_dist(),JSONRPC=class{constructor(e,{onConnected:t,onClosed:n}){this.url=e,this.onConnected=t,this.onClosed=n,this.messageQueue=[],this.serverAndClient=null,this.connect(),this.connectionEstablished=!1,this.timerId=null,this.closed=!1}close(){this.timerId&&clearTimeout(this.timerId),this.webSocket.close(),this.closed=!0}on(e,t){this.serverAndClient.addMethod(e,t)}async requestInternal(e,t,n){let r=await this.serverAndClient.request(e,t);n&&n(r)}requestMessageQueue(){this.messageQueue.forEach(e=>{let[t,n,r]=e;this.requestInternal(t,n,r)}),this.messageQueue=[]}request(e,t,n){this.webSocket.readyState===WebSocket.OPEN?this.requestInternal(e,t,n):this.messageQueue.push([e,t,n])}notify(e,t){switch(this.webSocket.readyState){case WebSocket.OPEN:this.serverAndClient.notify(e,t);break;case WebSocket.CLOSED:break}}connect(e){this.closed||(console.log(`connect`,this.url),this.webSocket=new WebSocket(this.url),this.serverAndClient||=new import_dist.JSONRPCServerAndClient(new import_dist.JSONRPCServer,new import_dist.JSONRPCClient(e=>{try{return this.webSocket.send(JSON.stringify(e)),Promise.resolve()}catch(e){return Promise.reject(e)}})),this.webSocket.onmessage=e=>{this.serverAndClient.receiveAndSend(JSON.parse(e.data.toString()))},this.webSocket.onopen=()=>{console.log(`WebSocket connection established`),this.connectionEstablished=!0,this.onConnected&&this.onConnected(),this.requestMessageQueue()},this.webSocket.onclose=e=>{console.error(`WebScoket closed`,e),this.serverAndClient.rejectAllPendingRequests(`Connection is closed (${e.reason}).`),this.connectionEstablished&&this.onClosed(),this.timerId=setTimeout(()=>{this.connect()},3e3)},this.webSocket.onerror=e=>{console.error(`WebSocket error:`,e),this.webSocket.close()})}},keyevent_exports=__exportAll({convertKeyEvent:()=>convertKeyEvent}),modifierKeys=[`Shift`,`Control`,`Alt`,`Meta`,`CapsLock`],convertKeyTable={Enter:`Return`,ArrowRight:`Right`,ArrowLeft:`Left`,ArrowUp:`Up`,ArrowDown:`Down`,"¡":`1`,"™":`2`,"£":`3`,"¢":`4`,"∞":`5`,"§":`6`,"¶":`7`,"•":`8`,ª:`9`,º:`0`,"–":`-`,"≠":`=`,"“":`[`,"‘":`]`,"«":`\\`,"…":`;`,æ:`'`,"≤":`,`,"≥":`.`,"÷":`/`,"⁄":`!`,"€":`@`,"‹":`#`,"›":`$`,fi:`%`,fl:`^`,"‡":`&`,"°":`*`,"·":`(`,"‚":`)`,"—":`_`,"±":`+`,"”":`{`,"’":`}`,"»":`|`,Ú:`:`,Æ:`"`,"¯":`<`,"˘":`>`,"¿":`?`,œ:`q`,"∑":`w`,"´":`e`,"®":`r`,"†":`t`,"¥":`y`,"¨":`u`,ˆ:`i`,ø:`o`,π:`p`,å:`a`,ß:`s`,"∂":`d`,ƒ:`f`,"©":`g`,"˙":`h`,"∆":`j`,"˚":`k`,"¬":`l`,Ω:`z`,"≈":`x`,ç:`c`,"√":`v`,"∫":`b`,"˜":`n`,µ:`m`,Œ:`Q`,"„":`W`,"´":`E`,"‰":`R`,ˇ:`T`,Á:`Y`,"¨":`U`,ˆ:`I`,Ø:`O`,"∏":`P`,Å:`A`,Í:`S`,Î:`D`,Ï:`F`,"˝":`G`,Ó:`H`,Ô:`J`,"":`K`,Ò:`L`,"¸":`Z`,"˛":`X`,Ç:`C`,"◊":`V`,ı:`B`,"˜":`N`,Â:`M`};function getKey(e){return e.altKey?convertKeyTable[e.key]||(e.code.startsWith(`Key`)?e.code[3].toLowerCase():null)||e.key:convertKeyTable[e.key]||e.key}function convertKeyEvent(e){return modifierKeys.indexOf(e.key)===-1?{key:getKey(e),ctrl:e.ctrlKey,meta:e.altKey,super:e.metaKey,shift:e.shiftKey}:null}var lib_exports=__exportAll({computeWidth:()=>computeWidth,eawVersion:()=>version,getEAW:()=>getEAW}),defs=[[0,31,`N`],[32,126,`Na`],[127,160,`N`],[161,161,`A`],[162,163,`Na`],[164,164,`A`],[165,166,`Na`],[167,168,`A`],[169,169,`N`],[170,170,`A`],[171,171,`N`],[172,172,`Na`],[173,174,`A`],[175,175,`Na`],[176,180,`A`],[181,181,`N`],[182,186,`A`],[187,187,`N`],[188,191,`A`],[192,197,`N`],[198,198,`A`],[199,207,`N`],[208,208,`A`],[209,214,`N`],[215,216,`A`],[217,221,`N`],[222,225,`A`],[226,229,`N`],[230,230,`A`],[231,231,`N`],[232,234,`A`],[235,235,`N`],[236,237,`A`],[238,239,`N`],[240,240,`A`],[241,241,`N`],[242,243,`A`],[244,246,`N`],[247,250,`A`],[251,251,`N`],[252,252,`A`],[253,253,`N`],[254,254,`A`],[255,256,`N`],[257,257,`A`],[258,272,`N`],[273,273,`A`],[274,274,`N`],[275,275,`A`],[276,282,`N`],[283,283,`A`],[284,293,`N`],[294,295,`A`],[296,298,`N`],[299,299,`A`],[300,304,`N`],[305,307,`A`],[308,311,`N`],[312,312,`A`],[313,318,`N`],[319,322,`A`],[323,323,`N`],[324,324,`A`],[325,327,`N`],[328,331,`A`],[332,332,`N`],[333,333,`A`],[334,337,`N`],[338,339,`A`],[340,357,`N`],[358,359,`A`],[360,362,`N`],[363,363,`A`],[364,461,`N`],[462,462,`A`],[463,463,`N`],[464,464,`A`],[465,465,`N`],[466,466,`A`],[467,467,`N`],[468,468,`A`],[469,469,`N`],[470,470,`A`],[471,471,`N`],[472,472,`A`],[473,473,`N`],[474,474,`A`],[475,475,`N`],[476,476,`A`],[477,592,`N`],[593,593,`A`],[594,608,`N`],[609,609,`A`],[610,707,`N`],[708,708,`A`],[709,710,`N`],[711,711,`A`],[712,712,`N`],[713,715,`A`],[716,716,`N`],[717,717,`A`],[718,719,`N`],[720,720,`A`],[721,727,`N`],[728,731,`A`],[732,732,`N`],[733,733,`A`],[734,734,`N`],[735,735,`A`],[736,767,`N`],[768,879,`A`],[880,912,`N`],[913,929,`A`],[930,930,`N`],[931,937,`A`],[938,944,`N`],[945,961,`A`],[962,962,`N`],[963,969,`A`],[970,1024,`N`],[1025,1025,`A`],[1026,1039,`N`],[1040,1103,`A`],[1104,1104,`N`],[1105,1105,`A`],[1106,4351,`N`],[4352,4447,`W`],[4448,8207,`N`],[8208,8208,`A`],[8209,8210,`N`],[8211,8214,`A`],[8215,8215,`N`],[8216,8217,`A`],[8218,8219,`N`],[8220,8221,`A`],[8222,8223,`N`],[8224,8226,`A`],[8227,8227,`N`],[8228,8231,`A`],[8232,8239,`N`],[8240,8240,`A`],[8241,8241,`N`],[8242,8243,`A`],[8244,8244,`N`],[8245,8245,`A`],[8246,8250,`N`],[8251,8251,`A`],[8252,8253,`N`],[8254,8254,`A`],[8255,8307,`N`],[8308,8308,`A`],[8309,8318,`N`],[8319,8319,`A`],[8320,8320,`N`],[8321,8324,`A`],[8325,8360,`N`],[8361,8361,`H`],[8362,8363,`N`],[8364,8364,`A`],[8365,8450,`N`],[8451,8451,`A`],[8452,8452,`N`],[8453,8453,`A`],[8454,8456,`N`],[8457,8457,`A`],[8458,8466,`N`],[8467,8467,`A`],[8468,8469,`N`],[8470,8470,`A`],[8471,8480,`N`],[8481,8482,`A`],[8483,8485,`N`],[8486,8486,`A`],[8487,8490,`N`],[8491,8491,`A`],[8492,8530,`N`],[8531,8532,`A`],[8533,8538,`N`],[8539,8542,`A`],[8543,8543,`N`],[8544,8555,`A`],[8556,8559,`N`],[8560,8569,`A`],[8570,8584,`N`],[8585,8585,`A`],[8586,8591,`N`],[8592,8601,`A`],[8602,8631,`N`],[8632,8633,`A`],[8634,8657,`N`],[8658,8658,`A`],[8659,8659,`N`],[8660,8660,`A`],[8661,8678,`N`],[8679,8679,`A`],[8680,8703,`N`],[8704,8704,`A`],[8705,8705,`N`],[8706,8707,`A`],[8708,8710,`N`],[8711,8712,`A`],[8713,8714,`N`],[8715,8715,`A`],[8716,8718,`N`],[8719,8719,`A`],[8720,8720,`N`],[8721,8721,`A`],[8722,8724,`N`],[8725,8725,`A`],[8726,8729,`N`],[8730,8730,`A`],[8731,8732,`N`],[8733,8736,`A`],[8737,8738,`N`],[8739,8739,`A`],[8740,8740,`N`],[8741,8741,`A`],[8742,8742,`N`],[8743,8748,`A`],[8749,8749,`N`],[8750,8750,`A`],[8751,8755,`N`],[8756,8759,`A`],[8760,8763,`N`],[8764,8765,`A`],[8766,8775,`N`],[8776,8776,`A`],[8777,8779,`N`],[8780,8780,`A`],[8781,8785,`N`],[8786,8786,`A`],[8787,8799,`N`],[8800,8801,`A`],[8802,8803,`N`],[8804,8807,`A`],[8808,8809,`N`],[8810,8811,`A`],[8812,8813,`N`],[8814,8815,`A`],[8816,8833,`N`],[8834,8835,`A`],[8836,8837,`N`],[8838,8839,`A`],[8840,8852,`N`],[8853,8853,`A`],[8854,8856,`N`],[8857,8857,`A`],[8858,8868,`N`],[8869,8869,`A`],[8870,8894,`N`],[8895,8895,`A`],[8896,8977,`N`],[8978,8978,`A`],[8979,8985,`N`],[8986,8987,`W`],[8988,9e3,`N`],[9001,9002,`W`],[9003,9192,`N`],[9193,9196,`W`],[9197,9199,`N`],[9200,9200,`W`],[9201,9202,`N`],[9203,9203,`W`],[9204,9311,`N`],[9312,9449,`A`],[9450,9450,`N`],[9451,9547,`A`],[9548,9551,`N`],[9552,9587,`A`],[9588,9599,`N`],[9600,9615,`A`],[9616,9617,`N`],[9618,9621,`A`],[9622,9631,`N`],[9632,9633,`A`],[9634,9634,`N`],[9635,9641,`A`],[9642,9649,`N`],[9650,9651,`A`],[9652,9653,`N`],[9654,9655,`A`],[9656,9659,`N`],[9660,9661,`A`],[9662,9663,`N`],[9664,9665,`A`],[9666,9669,`N`],[9670,9672,`A`],[9673,9674,`N`],[9675,9675,`A`],[9676,9677,`N`],[9678,9681,`A`],[9682,9697,`N`],[9698,9701,`A`],[9702,9710,`N`],[9711,9711,`A`],[9712,9724,`N`],[9725,9726,`W`],[9727,9732,`N`],[9733,9734,`A`],[9735,9736,`N`],[9737,9737,`A`],[9738,9741,`N`],[9742,9743,`A`],[9744,9747,`N`],[9748,9749,`W`],[9750,9755,`N`],[9756,9756,`A`],[9757,9757,`N`],[9758,9758,`A`],[9759,9791,`N`],[9792,9792,`A`],[9793,9793,`N`],[9794,9794,`A`],[9795,9799,`N`],[9800,9811,`W`],[9812,9823,`N`],[9824,9825,`A`],[9826,9826,`N`],[9827,9829,`A`],[9830,9830,`N`],[9831,9834,`A`],[9835,9835,`N`],[9836,9837,`A`],[9838,9838,`N`],[9839,9839,`A`],[9840,9854,`N`],[9855,9855,`W`],[9856,9874,`N`],[9875,9875,`W`],[9876,9885,`N`],[9886,9887,`A`],[9888,9888,`N`],[9889,9889,`W`],[9890,9897,`N`],[9898,9899,`W`],[9900,9916,`N`],[9917,9918,`W`],[9919,9919,`A`],[9920,9923,`N`],[9924,9925,`W`],[9926,9933,`A`],[9934,9934,`W`],[9935,9939,`A`],[9940,9940,`W`],[9941,9953,`A`],[9954,9954,`N`],[9955,9955,`A`],[9956,9959,`N`],[9960,9961,`A`],[9962,9962,`W`],[9963,9969,`A`],[9970,9971,`W`],[9972,9972,`A`],[9973,9973,`W`],[9974,9977,`A`],[9978,9978,`W`],[9979,9980,`A`],[9981,9981,`W`],[9982,9983,`A`],[9984,9988,`N`],[9989,9989,`W`],[9990,9993,`N`],[9994,9995,`W`],[9996,10023,`N`],[10024,10024,`W`],[10025,10044,`N`],[10045,10045,`A`],[10046,10059,`N`],[10060,10060,`W`],[10061,10061,`N`],[10062,10062,`W`],[10063,10066,`N`],[10067,10069,`W`],[10070,10070,`N`],[10071,10071,`W`],[10072,10101,`N`],[10102,10111,`A`],[10112,10132,`N`],[10133,10135,`W`],[10136,10159,`N`],[10160,10160,`W`],[10161,10174,`N`],[10175,10175,`W`],[10176,10213,`N`],[10214,10221,`Na`],[10222,10628,`N`],[10629,10630,`Na`],[10631,11034,`N`],[11035,11036,`W`],[11037,11087,`N`],[11088,11088,`W`],[11089,11092,`N`],[11093,11093,`W`],[11094,11097,`A`],[11098,11903,`N`],[11904,11929,`W`],[11930,11930,`N`],[11931,12019,`W`],[12020,12031,`N`],[12032,12245,`W`],[12246,12271,`N`],[12272,12287,`W`],[12288,12288,`F`],[12289,12350,`W`],[12351,12352,`N`],[12353,12438,`W`],[12439,12440,`N`],[12441,12543,`W`],[12544,12548,`N`],[12549,12591,`W`],[12592,12592,`N`],[12593,12686,`W`],[12687,12687,`N`],[12688,12771,`W`],[12772,12782,`N`],[12783,12830,`W`],[12831,12831,`N`],[12832,12871,`W`],[12872,12879,`A`],[12880,19903,`W`],[19904,19967,`N`],[19968,42124,`W`],[42125,42127,`N`],[42128,42182,`W`],[42183,43359,`N`],[43360,43388,`W`],[43389,44031,`N`],[44032,55203,`W`],[55204,57343,`N`],[57344,63743,`A`],[63744,64255,`W`],[64256,65023,`N`],[65024,65039,`A`],[65040,65049,`W`],[65050,65071,`N`],[65072,65106,`W`],[65107,65107,`N`],[65108,65126,`W`],[65127,65127,`N`],[65128,65131,`W`],[65132,65280,`N`],[65281,65376,`F`],[65377,65470,`H`],[65471,65473,`N`],[65474,65479,`H`],[65480,65481,`N`],[65482,65487,`H`],[65488,65489,`N`],[65490,65495,`H`],[65496,65497,`N`],[65498,65500,`H`],[65501,65503,`N`],[65504,65510,`F`],[65511,65511,`N`],[65512,65518,`H`],[65519,65532,`N`],[65533,65533,`A`],[65534,94175,`N`],[94176,94180,`W`],[94181,94191,`N`],[94192,94193,`W`],[94194,94207,`N`],[94208,100343,`W`],[100344,100351,`N`],[100352,101589,`W`],[101590,101631,`N`],[101632,101640,`W`],[101641,110575,`N`],[110576,110579,`W`],[110580,110580,`N`],[110581,110587,`W`],[110588,110588,`N`],[110589,110590,`W`],[110591,110591,`N`],[110592,110882,`W`],[110883,110897,`N`],[110898,110898,`W`],[110899,110927,`N`],[110928,110930,`W`],[110931,110932,`N`],[110933,110933,`W`],[110934,110947,`N`],[110948,110951,`W`],[110952,110959,`N`],[110960,111355,`W`],[111356,126979,`N`],[126980,126980,`W`],[126981,127182,`N`],[127183,127183,`W`],[127184,127231,`N`],[127232,127242,`A`],[127243,127247,`N`],[127248,127277,`A`],[127278,127279,`N`],[127280,127337,`A`],[127338,127343,`N`],[127344,127373,`A`],[127374,127374,`W`],[127375,127376,`A`],[127377,127386,`W`],[127387,127404,`A`],[127405,127487,`N`],[127488,127490,`W`],[127491,127503,`N`],[127504,127547,`W`],[127548,127551,`N`],[127552,127560,`W`],[127561,127567,`N`],[127568,127569,`W`],[127570,127583,`N`],[127584,127589,`W`],[127590,127743,`N`],[127744,127776,`W`],[127777,127788,`N`],[127789,127797,`W`],[127798,127798,`N`],[127799,127868,`W`],[127869,127869,`N`],[127870,127891,`W`],[127892,127903,`N`],[127904,127946,`W`],[127947,127950,`N`],[127951,127955,`W`],[127956,127967,`N`],[127968,127984,`W`],[127985,127987,`N`],[127988,127988,`W`],[127989,127991,`N`],[127992,128062,`W`],[128063,128063,`N`],[128064,128064,`W`],[128065,128065,`N`],[128066,128252,`W`],[128253,128254,`N`],[128255,128317,`W`],[128318,128330,`N`],[128331,128334,`W`],[128335,128335,`N`],[128336,128359,`W`],[128360,128377,`N`],[128378,128378,`W`],[128379,128404,`N`],[128405,128406,`W`],[128407,128419,`N`],[128420,128420,`W`],[128421,128506,`N`],[128507,128591,`W`],[128592,128639,`N`],[128640,128709,`W`],[128710,128715,`N`],[128716,128716,`W`],[128717,128719,`N`],[128720,128722,`W`],[128723,128724,`N`],[128725,128727,`W`],[128728,128731,`N`],[128732,128735,`W`],[128736,128746,`N`],[128747,128748,`W`],[128749,128755,`N`],[128756,128764,`W`],[128765,128991,`N`],[128992,129003,`W`],[129004,129007,`N`],[129008,129008,`W`],[129009,129291,`N`],[129292,129338,`W`],[129339,129339,`N`],[129340,129349,`W`],[129350,129350,`N`],[129351,129535,`W`],[129536,129647,`N`],[129648,129660,`W`],[129661,129663,`N`],[129664,129672,`W`],[129673,129679,`N`],[129680,129725,`W`],[129726,129726,`N`],[129727,129733,`W`],[129734,129741,`N`],[129742,129755,`W`],[129756,129759,`N`],[129760,129768,`W`],[129769,129775,`N`],[129776,129784,`W`],[129785,131071,`N`],[131072,196605,`W`],[196606,196607,`N`],[196608,262141,`W`],[262142,917759,`N`],[917760,917999,`A`],[918e3,983039,`N`],[983040,1048573,`A`],[1048574,1048575,`N`],[1048576,1114109,`A`],[1114110,1114111,`N`]],version=`15.1.0`;function getEAWOfCodePoint(e){let t=0,n=defs.length-1;for(;t!==n;){let r=t+(n-t>>1),[i,a,o]=defs[r];if(ea)t=r+1;else return o}return defs[t][2]}function getEAW(e,t=0){let n=e.codePointAt(t);if(n!==void 0)return getEAWOfCodePoint(n)}var defaultWidths={N:1,Na:1,W:2,F:2,H:1,A:1};function computeWidth(e,t){let n=0;for(let r of e){let e=getEAW(r);n+=t&&t[e]||defaultWidths[e]}return n}var textOffsetY=5,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function isWideChar(e){switch(getEAW(e)){case`F`:case`W`:return!0;default:return!1}}function isMacOS(){return window.navigator.userAgent.indexOf(`Mac OS X`)!==-1}function computeFontSize(e){let t=document.createElement(`canvas`).getContext(`2d`);t.font=e;let n=t.measureText(`W`);return[Math.floor(n.width),Math.round(n.fontBoundingBoxAscent+textOffsetY+(n.emHeightDescent||0))]}function drawBlock({ctx:e,x:t,y:n,width:r,height:i,style:a}){e.fillStyle=a,e.fillRect(t,n,r,i)}function drawText({ctx:e,x:t,y:n,text:r,font:i,style:a,option:o}){n+=Math.round(textOffsetY),e.fillStyle=a,e.font=i,e.textBaseline=`top`;for(let i of r)isWideChar(i)?(e.fillText(i,t,n,o.fontWidth*2),t+=o.fontWidth*2):(e.fillText(i,t,n,o.fontWidth),t+=o.fontWidth)}function drawHorizontalLine({ctx:e,x:t,y:n,width:r,style:i,lineWidth:a=1}){e.strokeStyle=i,e.lineWidth=a,e.setLineDash=[],e.beginPath(),e.moveTo(t,n),e.lineTo(t+r,n),e.stroke()}var Option=class{constructor({fontName:e,fontSize:t}){this.setFont(e,t),this.foreground=`#cccccc`,this.background=`#2d2d2d`}setFont(e,t){let n=t+`px `+e,[r,i]=computeFontSize(n);this.fontName=e,this.fontSize=t,this.fontWidth=r,this.fontHeight=i,this.font=n}};function getLemEditorElement(){return document.getElementById(`lem-editor`)}function normalizeWheelDelta(e,t,n,r){switch(n){case 0:return{dx:e/r,dy:t/r};case 2:return{dx:e*20,dy:t*20};default:return{dx:e,dy:t}}}function extractWholeLines(e,t){let n=Math.trunc(e),r=Math.trunc(t);return{scrollX:n,scrollY:r,remainderX:e-n,remainderY:t-r}}function cursorPosition(e,t){let[n,r]=t.getDisplayRectangle(),i=e.clientX-n,a=e.clientY-r;return{pixelX:i,pixelY:a,x:Math.floor(i/t.option.fontWidth),y:Math.floor(a/t.option.fontHeight)}}function makeWheelHandler(e){let t={x:0,y:0},n=!1,r={pixelX:0,pixelY:0,x:0,y:0};return i=>{i.preventDefault(),r=cursorPosition(i,e);let{dx:a,dy:o}=normalizeWheelDelta(i.deltaX,i.deltaY,i.deltaMode,e.option.fontHeight);t={x:t.x+a,y:t.y+o},n||(n=!0,requestAnimationFrame(()=>{n=!1;let{scrollX:i,scrollY:a,remainderX:o,remainderY:s}=extractWholeLines(t.x,t.y);t={x:o,y:s},(i!==0||a!==0)&&e.jsonrpc.notify(`input`,{kind:`wheel`,value:{...r,wheelX:-i,wheelY:-a}})}))}}function addMouseEventListeners({dom:e,editor:t,isDraggable:n,draggableStyle:r}){e.addEventListener(`contextmenu`,e=>{e.preventDefault()});let i=(e,n)=>{e.preventDefault();let[r,i]=t.getDisplayRectangle(),a=e.clientX-r,o=e.clientY-i,s=Math.floor(a/t.option.fontWidth),c=Math.floor(o/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:n,value:{x:s,y:c,pixelX:a,pixelY:o,button:e.button,clicks:e.detail}})};e.addEventListener(`mousedown`,e=>{n&&(document.body.style.cursor=r),t.focusHiddenInput(),i(e,`mousedown`)}),e.addEventListener(`mouseup`,e=>{n&&(document.body.style.cursor=`default`),i(e,`mouseup`)});let a=0;e.addEventListener(`mousemove`,e=>{e.preventDefault();let n=Date.now();if(n-a>50){a=n;let[r,i]=t.getDisplayRectangle(),o=e.clientX-r,s=e.clientY-i,c=Math.floor(o/t.option.fontWidth),l=Math.floor(s/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:`mousemove`,value:{x:c,y:l,pixelX:o,pixelY:s,button:e.buttons===0?null:e.buttons-1}})}}),n&&(e.addEventListener(`mouseover`,()=>{document.body.style.cursor=r}),e.addEventListener(`mouseout`,e=>{e.buttons!==1&&(document.body.style.cursor=`default`)})),e.addEventListener(`wheel`,makeWheelHandler(t))}var zIndexTable={"floating-window":200,modeline:100,"vertical-border":100,"horizontal-border":101};function zindex(e){return zIndexTable[e]||0}var borderOffsetX=5,borderOffsetY=10,BaseSurface=class{constructor({editor:e}){this.editor=e,this.mainDOM=null,this.wrapper=null}delete(){this.wrapper?getLemEditorElement().removeChild(this.wrapper):getLemEditorElement().removeChild(this.mainDOM)}setupDOM({dom:e,isFloating:t,border:n,cssClassName:r}){this.mainDOM=e,t&&n?(this.wrapper=document.createElement(`div`),r&&(this.wrapper.className=r),this.wrapper.style.position=`absolute`,this.wrapper.style.backgroundColor=this.editor.option.background,this.wrapper.style.zIndex=zindex(`floating-window`),this.wrapper.appendChild(e),getLemEditorElement().appendChild(this.wrapper)):(r&&(e.className=r),getLemEditorElement().appendChild(e))}move(e,t,n,r){let[i,a]=this.editor.getDisplayRectangle(),o=Math.floor(n==null?i+e*this.editor.option.fontWidth:i+n),s=Math.floor(r==null?a+t*this.editor.option.fontHeight:a+r);this.wrapper?(this.wrapper.style.left=o-borderOffsetX+`px`,this.wrapper.style.top=s-borderOffsetY+`px`,this.mainDOM.style.left=borderOffsetX+`px`,this.mainDOM.style.top=borderOffsetY+`px`):(this.mainDOM.style.left=o+`px`,this.mainDOM.style.top=s+`px`)}_resize(e,t,n,r){let i=window.devicePixelRatio||1,a=n??e*this.editor.option.fontWidth,o=r??t*this.editor.option.fontHeight;this.mainDOM.width=a*i,this.mainDOM.height=o*i,this.mainDOM.style.width=a+`px`,this.mainDOM.style.height=o+`px`,this.wrapper&&(this.wrapper.style.width=a+borderOffsetX*2+`px`,this.wrapper.style.height=o+borderOffsetY*2+`px`)}drawBlock(e,t,n,r,i){}drawText(e,t,n,r,i){}drawImage(e,t,n,r,i,a,o){}clearImages(e,t){}clearAllImages(){}touch(){}evalIn(code){return eval(code)}},CanvasSurface=class extends BaseSurface{constructor({editor:e,view:t,x:n,y:r,width:i,height:a,styles:o,isFloating:s,border:c,cssClassName:l}){super({editor:e});let u=this.setupCanvas(o);this.setupDOM({dom:u,isFloating:s,border:c,cssClassName:l}),this.move(n,r),this.resize(i,a),this.drawingQueue=[],addMouseEventListeners({dom:u,editor:e})}setupCanvas(e){let t=document.createElement(`canvas`);if(t.style.position=`absolute`,e)for(let n in e)t.style[n]=e[n];return t}resize(e,t,n,r){this._resize(e,t,n,r);let i=window.devicePixelRatio||1;this.mainDOM.getContext(`2d`).scale(i,i)}move(e,t,n,r){if(super.move(e,t,n,r),this.imageEls)for(let[,e]of this.imageEls)this.positionImage(e)}delete(){this.clearAllImages(),super.delete()}drawBlock(e,t,n,r,i){let a=this.editor.option;this.drawingQueue.push(function(o){drawBlock({ctx:o,x:e*a.fontWidth,y:t*a.fontHeight,width:n*a.fontWidth,height:r*a.fontHeight,style:i})})}drawText(e,t,n,r,i,a){let o=this.editor.option;this.drawingQueue.push(function(s){if(a=a?`${o.fontSize}px ${a}`:o.font,!i)drawBlock({ctx:s,x:e*o.fontWidth,y:t*o.fontHeight,width:r*o.fontWidth,height:o.fontHeight,style:o.background}),drawText({ctx:s,x:e*o.fontWidth,y:t*o.fontHeight,text:n,style:o.foreground,font:a,option:o});else{let{foreground:c,background:l,bold:u,reverse:d,underline:f,cursor:p}=i;if(c||=o.foreground,l||=o.background,d){let e=l;l=c,c=e}p&&(l=o.background);let m=e*o.fontWidth,h=t*o.fontHeight;drawBlock({ctx:s,x:m,y:h,width:r*o.fontWidth,height:o.fontHeight,style:l}),drawText({ctx:s,x:m,y:h,text:n,style:c,font:u?`bold `+a:a,option:o}),f&&drawHorizontalLine({ctx:s,x:m,y:h+o.fontHeight-2,width:r*o.fontWidth,style:typeof f==`string`?f:c,lineWidth:2})}})}imageBaseLeft(){return parseFloat(this.mainDOM.style.left)||0}imageBaseTop(){return parseFloat(this.mainDOM.style.top)||0}drawImage(e,t,n,r,i,a,o){this.imageEls||=new Map;let s=e+`,`+t,c=this.imageEls.get(s);if(c&&c.url!==o&&(c.el.remove(),this.imageEls.delete(s),c=null),!c){let e=document.createElement(`img`);e.style.position=`absolute`,e.style.pointerEvents=`none`,e.style.zIndex=`1`,e.src=o,this.mainDOM.parentNode.appendChild(e),c={el:e,url:o},this.imageEls.set(s,c)}c.x=e,c.y=t,c.widthCells=n,c.heightCells=r,c.pixelWidth=i,c.pixelHeight=a,this.positionImage(c)}positionImage(e){let t=this.editor.option,n=e.widthCells*t.fontWidth,r=e.heightCells*t.fontHeight;e.el.style.left=this.imageBaseLeft()+e.x*t.fontWidth+`px`,e.el.style.top=this.imageBaseTop()+e.y*t.fontHeight+`px`,e.el.style.width=(e.pixelWidth==null?n:Math.min(e.pixelWidth,n))+`px`,e.el.style.height=(e.pixelHeight==null?r:Math.min(e.pixelHeight,r))+`px`}clearImages(e,t){if(this.imageEls)for(let[n,r]of this.imageEls)r.ye&&(r.el.remove(),this.imageEls.delete(n))}clearAllImages(){if(this.imageEls){for(let[,e]of this.imageEls)e.el.remove();this.imageEls.clear()}}touch(){let e=this.mainDOM.getContext(`2d`);for(let t of this.drawingQueue)t(e);this.drawingQueue=[]}activate(){this.mainDOM.dataset.store=`active`}deactivate(){this.mainDOM.dataset.store=`inactive`}},HTMLSurface=class extends BaseSurface{constructor({editor:e,x:t,y:n,width:r,height:i,styles:a,option:o,isFloating:s,border:c,html:l}){super({editor:e});let u=document.createElement(`iframe`);this.setupDOM({dom:u,isFloating:s,border:c}),u.style.position=`absolute`,u.style.backgroundColor=o.background,u.setAttribute(`sandbox`,`allow-scripts allow-same-origin`),u.srcdoc=l,u.addEventListener(`load`,()=>{let e=u.contentWindow;e.invokeLem=(e,t)=>parent.postMessage({type:`invoke-lem`,method:e,args:t})}),this.iframe=u,this.move(t,n),this.resize(r,i)}resize(e,t,n,r){this._resize(e,t,n,r)}update(e){let t=this.iframe.contentWindow.scrollY;this.iframe.srcdoc=e,this.iframe.onload=()=>{this.iframe.onload=null,this.iframe.contentWindow.scrollTo(0,t)}}evalIn(e){return this.iframe.contentWindow.eval(e)}},VerticalBorder=class{constructor({x:e,y:t,height:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__vertical-border`,this.line.style.height=n*r.fontHeight+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`vertical-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`col-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=Math.floor(n+e*this.option.fontWidth-this.option.fontWidth/2)+`px`,this.line.style.top=r+t*this.option.fontHeight+`px`}resize(e){this.line.style.height=e*this.option.fontHeight+`px`}},HorizontalBorder=class{constructor({x:e,y:t,width:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__horizontal-border`,this.line.style.width=n*r.fontWidth+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`horizontal-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`row-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=n+e*this.option.fontWidth+`px`,this.line.style.top=Math.floor(r+t*this.option.fontHeight-4)+`px`}resize(e){this.line.style.width=e*this.option.fontWidth+`px`}},viewStyles={header:()=>{},tile:()=>{},floating:e=>({boxSizing:`border-box`,borderColor:e.foreground,backgroundColor:e.background})};function getViewStyle(e,t){return viewStyles[e](t)||{}}var View=class{constructor({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,option:h,editor:g}){switch(this.option=h,this.id=e,this.x=t,this.y=n,this.width=r,this.height=i,this.pixelX=a,this.pixelY=o,this.pixelWidth=s,this.pixelHeight=c,this.useModeline=l,this.kind=u,this.type=d,this.border=p,this.borderShape=m,this.editor=g,this.bottomBar=null,this.leftsideBar=null,u){case`tile`:this.mainSurface=this.makeSurface(d,f),this.leftSideBar=new VerticalBorder({x:t,y:n,height:i+ +!!l,option:h,editor:g}),l||(this.bottomBar=new HorizontalBorder({x:t,y:n+i-1,width:r,option:h,editor:g}));break;case`header`:this.mainSurface=this.makeSurface(d,f);break;case`floating`:this.mainSurface=this.makeSurface(d,f),m===`left-border`&&(this.leftSideBar=new VerticalBorder({x:t,y:n,height:i,option:h,editor:g}));break}this.modelineSurface=l?this.makeModelineSurface():null,u===`floating`&&(a!=null||o!=null)&&this.move(t,n,a,o)}delete(){this.mainSurface.delete(),this.modelineSurface&&this.modelineSurface.delete(),this.leftSideBar&&this.leftSideBar.delete(),this.bottomBar&&this.bottomBar.delete()}move(e,t,n,r){if(this.x=e,this.y=t,this.pixelX=n,this.pixelY=r,this.mainSurface.move(e,t,n,r),this.modelineSurface){let i=r!=null&&this.pixelHeight!=null?r+this.pixelHeight:null;this.modelineSurface.move(e,t+this.height,n,i)}this.leftSideBar&&this.leftSideBar.move(e,t),this.bottomBar&&this.bottomBar.move(e,t+this.height)}resize(e,t,n,r){if(this.width=e,this.height=t,this.pixelWidth=n,this.pixelHeight=r,this.mainSurface.resize(e,t,n,r),this.modelineSurface){let t=this.pixelY!=null&&r!=null?this.pixelY+r:null;this.modelineSurface.move(this.x,this.y+this.height,this.pixelX,t),this.modelineSurface.resize(e,1)}this.leftSideBar&&this.leftSideBar.resize(t+ +!!this.modelineSurface),this.bottomBar&&this.bottomBar.resize(e)}clear(){this.mainSurface.drawBlock(0,0,this.width,this.height,this.option.background)}clearEol(e,t,n=1){this.mainSurface.drawBlock(e,t,this.width-e,n,this.option.background),this.mainSurface.clearImages(t,t+n)}clearEob(e,t){this.mainSurface.drawBlock(e,t,this.width,this.height-t,this.option.background),this.mainSurface.clearImages(t,this.height)}print(e,t,n,r,i,a){this.mainSurface.drawText(e,t,n,r,i,a)}printImage(e,t,n,r,i,a,o){this.mainSurface.drawImage(e,t,n,r,i,a,o)}printToModeline(e,t,n,r,i){this.modelineSurface&&this.modelineSurface.drawText(e,t,n,r,i)}touch(e){this.mainSurface.touch(),this.modelineSurface&&(this.modelineSurface.touch(),e?this.modelineSurface.activate():this.modelineSurface.deactivate())}makeSurface(e,t){switch(e){case`html`:return this.makeHTMLSurface(t);case`editor`:return this.makeEditorSurface();default:console.error(`unknown type: ${e}`)}}makeHTMLSurface(e){return new HTMLSurface({editor:this.editor,x:this.x,y:this.y,width:this.width,height:this.height,styles:getViewStyle(this.kind,this.option),option:this.option,isFloating:this.kind===`floating`,border:this.border,html:e})}makeEditorSurface(){let e=this.borderShape===`left-border`?0:this.border,t=this.kind===`floating`;return new CanvasSurface({option:this.editor.option,x:this.x,y:this.y,width:this.width,height:this.height,styles:getViewStyle(this.kind,this.option),editor:this.editor,border:e,isFloating:t,view:this,cssClassName:t&&e?`lem-editor__floating-window--bordered`:null})}makeModelineSurface(){let e=new CanvasSurface({option:this.editor.option,x:this.x,y:this.y+this.height,width:this.width,height:1,editor:this.editor,view:this,styles:{zIndex:zindex(`modeline`)},cssClassName:`lem-editor__mode-line`});return addMouseEventListeners({dom:e.mainDOM,editor:this.editor,isDraggable:!0,draggableStyle:`row-resize`}),e}changeToHTMLContent(e){this.mainSurface.constructor.name===`HTMLSurface`?this.mainSurface.update(e):(this.mainSurface.delete(),this.mainSurface=this.makeHTMLSurface(e))}changeToEditorContent(){this.mainSurface.delete(),this.mainSurface=this.makeEditorSurface()}evalIn(e){return this.mainSurface.evalIn(e)}};function isPasteKeyEvent(e){return isMacOS()?e.metaKey&&e.key===`v`:e.ctrlKey&&e.shiftKey&&e.key===`V`}var Input=class{constructor(e){let t=e.option;this.editor=e,this.composition=!1,this.ignoreKeydownAfterCompositionend=!1,this.span=document.createElement(`span`),this.span.style.color=t.foreground,this.span.style.backgroundColor=t.background,this.span.style.position=`absolute`,this.span.style.zIndex=1e6,this.span.style.top=`0`,this.span.style.left=`0`,this.span.style.font=t.font,this.input=document.createElement(`input`),this.input.style.backgroundColor=`transparent`,this.input.style.color=`transparent`,this.input.style.width=`0`,this.input.style.padding=`0`,this.input.style.margin=`0`,this.input.style.border=`none`,this.input.style.position=`absolute`,this.input.style.zIndex=`-10`,this.input.style.top=`0`,this.input.style.left=`0`,this.input.style.font=t.font,this.input.addEventListener(`blur`,e=>{this.input.focus()}),this.input.addEventListener(`input`,e=>{this.composition===!1&&(this.input.value=``,this.span.innerHTML=``,this.input.style.width=`0`,isMacOS()||this.editor.emitInputString(e.data))}),this.input.addEventListener(`paste`,async e=>{e.preventDefault();let t=e.clipboardData||window.Clipboard.data,n=t?.getData(`text`)??t?.getData(`text/plain`);if(n&&n.length>0){this.editor.emitInputString(n);return}try{if(navigator.clipboard?.readText){let e=await navigator.clipboard.readText();if(e&&e.length>0){this.editor.emitInputString(e);return}}}catch(e){console.warn(`clipboard.readText() failed:`,e)}alert(`Paste failed (permission/environment restriction`)}),this.input.addEventListener(`keydown`,e=>{if(!isPasteKeyEvent(e)&&!(e.isComposing||this.composition)&&e.key!==`Process`){if(this.ignoreKeydownAfterCompositionend&&(isSafari||isMacOS())){e.preventDefault(),this.ignoreKeydownAfterCompositionend=!1;return}if(!(!isMacOS()&&!e.ctrlKey&&!e.altKey&&e.key.length===1)&&(e.preventDefault(),e.isComposing!==!0&&e.code!==``))return setTimeout(()=>{this.composition||(this.editor.emitInput(e),this.input.value=``)},0),!1}}),this.input.addEventListener(`compositionstart`,e=>{this.composition=!0,this.span.innerHTML=this.input.value,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionupdate`,e=>{this.span.innerHTML=e.data,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionend`,e=>{this.composition=!1,this.editor.emitInputString(this.input.value),this.input.value=``,this.span.innerHTML=this.input.value,this.input.style.width=`0`,this.ignoreKeydownAfterCompositionend=!0}),document.body.appendChild(this.input),document.body.appendChild(this.span),this.input.focus()}finalize(){document.body.removeChild(this.input),document.body.removeChild(this.span)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.span.style.top=r+t+`px`,this.span.style.left=n+e+`px`,this.input.style.top=this.span.offsetTop+`px`,this.input.style.left=this.span.offsetLeft+`px`}updateForeground(e){this.span.style.color=e}updateBackground(e){this.span.style.backgroundColor=e}},MessageTable=class{constructor(){this.map=new Map}register(e,t){for(let n in t){let r=t[n];this.map.set(n,r),e.on(n,r)}}get(e){return this.map.get(e)}};function getDisplayRectangleDefault(){return[0,0,window.innerWidth,window.innerHeight]}var Editor=class{constructor({getDisplayRectangle:e=getDisplayRectangleDefault,fontName:t,fontSize:n,url:r,onExit:i,onClosed:a}){this.getDisplayRectangle=e,this.option=new Option({fontName:t,fontSize:n}),this.onExit=i,this.input=new Input(this),this.cursors=new Map,this.cursorOverlay=document.createElement(`div`),this.cursorOverlay.className=`lem-cursor`,this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.cursorOverlay.style.backgroundColor=`#ffffff`,this.cursorType=`box`,this.viewMap=new Map,this.jsonrpc=new JSONRPC(r,{onClosed:()=>{a()}}),this.messageTable=new MessageTable,this.messageTable.register(this.jsonrpc,{"update-foreground":this.updateForeground.bind(this),"update-background":this.updateBackground.bind(this),"make-view":this.makeView.bind(this),"delete-view":this.deleteView.bind(this),"resize-view":this.resize.bind(this),"move-view":this.move.bind(this),"redraw-view-after":this.redrawViewAfter.bind(this),clear:this.clear.bind(this),"clear-eol":this.clearEol.bind(this),"clear-eob":this.clearEob.bind(this),put:this.put.bind(this),"put-image":this.putImage.bind(this),"modeline-put":this.modelinePut.bind(this),"update-display":this.updateDisplay.bind(this),"move-cursor":this.moveCursor.bind(this),"change-view":this.changeView.bind(this),"resize-display":this.resizeDisplay.bind(this),bulk:this.bulk.bind(this),exit:this.exitEditor.bind(this),"get-clipboard-text":this.getClipboardText.bind(this),"set-clipboard-text":this.setClipboardText.bind(this),"js-eval":this.jsEval.bind(this),"set-font":this.setFont.bind(this),"get-font":this.getFont.bind(this),"get-display-size":this.getDisplaySize.bind(this),"load-css":this.loadCSS.bind(this),"update-cursor-shape":this.updateCursorShape.bind(this)}),this.login(),this.boundedHandleResize=this.handleResize.bind(this),this.focusHiddenInput=this.focusHiddenInput.bind(this)}init(){window.addEventListener(`resize`,this.boundedHandleResize),document.getElementsByTagName(`html`)[0].style[`background-color`]=`#333`,getLemEditorElement().appendChild(this.cursorOverlay)}finalize(){window.removeEventListener(`resize`,this.boundedHandleResize),this.input.finalize(),this.cursorOverlay.parentNode&&this.cursorOverlay.parentNode.removeChild(this.cursorOverlay)}closeConnection(){this.jsonrpc.close()}emitInput(e){let t=convertKeyEvent(e);if(t){if(t.key===`]`&&t.ctrl&&!t.meta&&!t.super&&!t.shift){this.jsonrpc.notify(`input`,{kind:`abort`});return}t.key!==`Unidentified`&&this.jsonrpc.notify(`input`,{kind:`key`,value:t})}}emitInputString(e){e?this.jsonrpc.notify(`input`,{kind:`input-string`,value:e}):console.error(`unexpected argument`,e)}handleResize(e){let t=!0;this.jsonrpc.notify(`redraw`,{size:this.getDisplaySize()})}focusHiddenInput(){let e=this.input?.input;if(e){try{window.focus()}catch{}requestAnimationFrame(()=>{setTimeout(()=>{e.focus({preventScroll:!0})},0)})}}sendNotification(e,t){this.jsonrpc.notify(e,t)}request(e,t,n){this.jsonrpc.request(e,t,n)}getDisplaySize(){let[e,t,n,r]=this.getDisplayRectangle();return{width:Math.floor(n/this.option.fontWidth),height:Math.floor(r/this.option.fontHeight)}}callMessage(e,t){this.messageTable.get(e)(t)}findViewById(e){return this.viewMap.get(e)}login(){this.jsonrpc.request(`login`,{size:this.getDisplaySize(),foreground:this.option.foreground,background:this.option.background,fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight},e=>{if(this.updateForeground(e.foreground),this.updateBackground(e.background),e.views)for(let t of e.views)this.makeView(t);this.jsonrpc.notify(`redraw`,{size:this.getDisplaySize()})})}updateForeground(e){e!=null&&(this.option.foreground=e,this.input.updateForeground(e))}updateBackground(e){if(e==null)return;this.option.background=e,this.input.updateBackground(e);let t=getLemEditorElement();t.style.backgroundColor=e}makeView({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,use_modeline:l,kind:u,type:d,content:f,border:p,border_shape:m}){let h=new View({option:this.option,id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,editor:this});this.viewMap.set(e,h)}deleteView({viewInfo:{id:e}}){this.findViewById(e).delete(),this.viewMap.delete(e)}resize({viewInfo:{id:e},width:t,height:n,pixelWidth:r,pixelHeight:i}){let a=this.findViewById(e);a?a.resize(t,n,r,i):console.warn(`resize: view not found for id ${e}`)}move({viewInfo:{id:e},x:t,y:n,pixelX:r,pixelY:i}){let a=this.findViewById(e);a?a.move(t,n,r,i):console.warn(`move: view not found for id ${e}`)}redrawViewAfter({viewInfo:{id:e},isActive:t}){this.findViewById(e).touch(t)}clear({viewInfo:{id:e}}){this.findViewById(e).clear()}clearEol({viewInfo:{id:e},x:t,y:n,height:r}){this.findViewById(e).clearEol(t,n,r)}clearEob({viewInfo:{id:e},x:t,y:n}){this.findViewById(e).clearEob(t,n)}put({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,font:o}){this.findViewById(e).print(t,n,r,i,a,o)}putImage({viewInfo:{id:e},x:t,y:n,width:r,height:i,pixelWidth:a,pixelHeight:o,url:s}){this.findViewById(e).printImage(t,n,r,i,a,o,s)}modelinePut({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a}){this.findViewById(e).printToModeline(t,n,r,i,a)}updateDisplay(){}moveCursor({viewInfo:{id:e},x:t,y:n,color:r,cursorText:i,cursorForeground:a}){let o=this.findViewById(e),[s,c]=this.getDisplayRectangle(),l=o.x*this.option.fontWidth+t*this.option.fontWidth,u=o.y*this.option.fontHeight+n*this.option.fontHeight;this.input.move(l,u);let d=r||this.option.foreground,f=a||this.option.background,p=this.cursorOverlay;switch(this.cursorType){case`bar`:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=`2px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;case`underline`:p.style.left=s+l+`px`,p.style.top=c+u+this.option.fontHeight-2+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=`2px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;default:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.style.font=this.option.font,p.style.paddingTop=textOffsetY+`px`,p.textContent=i||``,p.style.color=f;break}p.style.animation=`none`,p.offsetHeight,p.style.animation=``}updateCursorShape({cursorType:e}){this.cursorType=e||`box`}changeView({viewInfo:{id:e},type:t,content:n}){let r=this.findViewById(e);switch(t){case`html`:r.changeToHTMLContent(n);break;case`editor`:r.changeToEditorContent();break}}resizeDisplay({width:e,height:t}){let n=getLemEditorElement();n.style.width=Math.floor(e*this.option.fontWidth)+`px`,n.style.height=Math.floor(t*this.option.fontHeight)+`px`}bulk(e){for(let{method:t,argument:n}of e)this.callMessage(t,n)}exitEditor(){this.onExit&&this.onExit()}getClipboardText(){navigator.clipboard?.readText().then(e=>{this.jsonrpc.notify(`got-clipboard-text`,{text:e})})}setClipboardText({text:e}){navigator.clipboard&&navigator.clipboard.writeText(e)}jsEval({viewInfo:{id:e},code:t}){let n=this.findViewById(e).evalIn(t);return n&&n.toString()}setFont({fontName:e,fontSize:t}){this.option.setFont(e||this.option.fontName,t||this.option.fontSize)}getFont(){return{name:this.option.fontName,size:this.option.fontSize}}loadCSS({content:e}){let t=document.createElement(`style`);t.textContent=e,document.head.appendChild(t)}notifyToServer(e,t){this.jsonrpc.notify(`invoke`,{method:e,args:t})}},canvas=document.querySelector(`#editor`);async function main(){await Promise.all([document.fonts.load(`19px file-icons`),document.fonts.load(`19px AllTheIcons`),document.fonts.load(`19px fontawesome`),document.fonts.load(`19px material-design-icons`),document.fonts.load(`19px octicons`)]),await document.fonts.ready;let e=new Editor({canvas,fontName:`Monospace`,fontSize:18,url:`${window.location.protocol===`https:`?`wss`:`ws`}://${window.location.hostname}:${window.location.port}`,onExit:null,onClosed:null});window.addEventListener(`message`,t=>{t.data.type===`invoke-lem`&&e.notifyToServer(t.data.method,t.data.args)}),e.init()}main(); \ No newline at end of file diff --git a/frontends/server/frontend/editor.js b/frontends/server/frontend/editor.js index 55027113a..c52afb54b 100644 --- a/frontends/server/frontend/editor.js +++ b/frontends/server/frontend/editor.js @@ -346,6 +346,10 @@ class BaseSurface { drawBlock(x, y, width, height, color) { } drawText(x, y, text, textWidth, attribute) { } + drawImage(x, y, widthCells, heightCells, pixelWidth, pixelHeight, url) { } + + clearImages(yStart, yEnd) { } + clearAllImages() { } touch() { return; @@ -388,6 +392,18 @@ class CanvasSurface extends BaseSurface { ctx.scale(ratio, ratio); } + move(x, y, pixelX, pixelY) { + super.move(x, y, pixelX, pixelY); + if (this.imageEls) { + for (const [, entry] of this.imageEls) this.positionImage(entry); + } + } + + delete() { + this.clearAllImages(); + super.delete(); + } + drawBlock(x, y, width, height, color) { const option = this.editor.option; this.drawingQueue.push(function(ctx) { @@ -475,6 +491,69 @@ class CanvasSurface extends BaseSurface { }); } + // images are rendered as DOM elements on a layer above the canvas rather than into it. + imageBaseLeft() { return parseFloat(this.mainDOM.style.left) || 0; } + imageBaseTop() { return parseFloat(this.mainDOM.style.top) || 0; } + + drawImage(x, y, widthCells, heightCells, pixelWidth, pixelHeight, url) { + if (!this.imageEls) + // mapping "x,y" to { el, url, x, y, widthCells, heightCells, pixelWidth, pixelHeight } + this.imageEls = new Map(); + const key = x + ',' + y; + let entry = this.imageEls.get(key); + if (entry && entry.url !== url) { + entry.el.remove(); + this.imageEls.delete(key); + entry = null; + } + if (!entry) { + const el = document.createElement('img'); + el.style.position = 'absolute'; + el.style.pointerEvents = 'none'; + // above the surface's own canvas but below the modeline/floating windows. + el.style.zIndex = '1'; + el.src = url; + this.mainDOM.parentNode.appendChild(el); + entry = { el, url }; + this.imageEls.set(key, entry); + } + entry.x = x; + entry.y = y; + entry.widthCells = widthCells; + entry.heightCells = heightCells; + entry.pixelWidth = pixelWidth; + entry.pixelHeight = pixelHeight; + this.positionImage(entry); + } + + positionImage(entry) { + const option = this.editor.option; + // we reserved widthCells x heightCells cells for this image. + const boxWidth = entry.widthCells * option.fontWidth; + const boxHeight = entry.heightCells * option.fontHeight; + entry.el.style.left = (this.imageBaseLeft() + entry.x * option.fontWidth) + 'px'; + entry.el.style.top = (this.imageBaseTop() + entry.y * option.fontHeight) + 'px'; + entry.el.style.width = (entry.pixelWidth != null ? Math.min(entry.pixelWidth, boxWidth) : boxWidth) + 'px'; + entry.el.style.height = (entry.pixelHeight != null ? Math.min(entry.pixelHeight, boxHeight) : boxHeight) + 'px'; + } + + // remove image elements whose row span intersects [yStart, yEnd). + clearImages(yStart, yEnd) { + if (!this.imageEls) return; + for (const [key, entry] of this.imageEls) { + if (entry.y < yEnd && (entry.y + entry.heightCells) > yStart) { + entry.el.remove(); + this.imageEls.delete(key); + } + } + } + + clearAllImages() { + if (!this.imageEls) return; + for (const [, entry] of this.imageEls) entry.el.remove(); + this.imageEls.clear(); + } + touch() { const ctx = this.mainDOM.getContext('2d'); for (let fn of this.drawingQueue) { @@ -778,14 +857,15 @@ class View { ); } - clearEol(x, y) { + clearEol(x, y, height=1) { this.mainSurface.drawBlock( x, y, this.width - x, - 1, + height, this.option.background, ); + this.mainSurface.clearImages(y, y + height); } clearEob(x, y) { @@ -796,6 +876,7 @@ class View { this.height - y, this.option.background, ); + this.mainSurface.clearImages(y, this.height); } print(x, y, text, textWidth, attribute, font) { @@ -809,6 +890,10 @@ class View { ); } + printImage(x, y, width, height, pixelWidth, pixelHeight, url) { + this.mainSurface.drawImage(x, y, width, height, pixelWidth, pixelHeight, url); + } + printToModeline(x, y, text, textWidth, attribute) { if (this.modelineSurface) { this.modelineSurface.drawText( @@ -1166,6 +1251,7 @@ export class Editor { 'clear-eol': this.clearEol.bind(this), 'clear-eob': this.clearEob.bind(this), 'put': this.put.bind(this), + 'put-image': this.putImage.bind(this), 'modeline-put': this.modelinePut.bind(this), 'update-display': this.updateDisplay.bind(this), 'move-cursor': this.moveCursor.bind(this), @@ -1280,6 +1366,8 @@ export class Editor { size: this.getDisplaySize(), foreground: this.option.foreground, background: this.option.background, + fontWidth: this.option.fontWidth, + fontHeight: this.option.fontHeight, }, (response) => { this.updateForeground(response.foreground); this.updateBackground(response.background); @@ -1364,9 +1452,9 @@ export class Editor { view.clear(); } - clearEol({ viewInfo: { id }, x, y }) { + clearEol({ viewInfo: { id }, x, y, height }) { const view = this.findViewById(id); - view.clearEol(x, y); + view.clearEol(x, y, height); } clearEob({ viewInfo: { id }, x, y }) { @@ -1379,6 +1467,11 @@ export class Editor { view.print(x, y, text, textWidth, attribute, font); } + putImage({ viewInfo: { id }, x, y, width, height, pixelWidth, pixelHeight, url }) { + const view = this.findViewById(id); + view.printImage(x, y, width, height, pixelWidth, pixelHeight, url); + } + modelinePut({ viewInfo: { id }, x, y, text, textWidth, attribute }) { const view = this.findViewById(id); view.printToModeline(x, y, text, textWidth, attribute); diff --git a/frontends/server/main.lisp b/frontends/server/main.lisp index 22545579e..f8a28164a 100644 --- a/frontends/server/main.lisp +++ b/frontends/server/main.lisp @@ -109,7 +109,12 @@ quits by itself afterwards.") (message-queue :initform (queue:make-queue) :reader jsonrpc-message-queue) (editor-thread :initform nil - :accessor jsonrpc-editor-thread)) + :accessor jsonrpc-editor-thread) + ;; pixel size of one character cell, reported by the client. + (cell-width :initform nil + :accessor jsonrpc-cell-width) + (cell-height :initform nil + :accessor jsonrpc-cell-height)) (:default-initargs :name :jsonrpc :redraw-after-modifying-floating-window t @@ -170,6 +175,10 @@ the same immutable instance for every subsequent message." (let ((width (gethash "width" size)) (height (gethash "height" size))) (resize-display jsonrpc width height))) + (alexandria:when-let ((fw (gethash "fontWidth" params))) + (when (plusp fw) (setf (jsonrpc-cell-width jsonrpc) fw))) + (alexandria:when-let ((fh (gethash "fontHeight" params))) + (when (plusp fh) (setf (jsonrpc-cell-height jsonrpc) fh))) (when background (alexandria:when-let (color (lem:parse-color background)) (setf (jsonrpc-background-color jsonrpc) color))) @@ -592,7 +601,34 @@ the same immutable instance for every subsequent message." (lem-core:string-width (lem-core/display:text-object-string drawing-object))) (defmethod object-width ((drawing-object display:image-object)) - 0) + ;; width in character cells. when :pixel-width is given (and the client's cell size is known), + ;; round it up to whole cells so the column reserves enough grid space. otherwise use :width + ;; (a cell count) from the attribute. + (let ((pw (image-pixel-dimension drawing-object :pixel-width)) + (cw (jsonrpc-cell-width (lem-core:implementation)))) + (if (and pw cw) + (ceiling pw cw) + (or (display:image-object-width drawing-object) 1)))) + +(defgeneric object-height (drawing-object) + (:documentation "height of DRAWING-OBJECT in character cells. +we advance the vertical position of the next line by the tallest object's height (see +`max-height-of-objects'), so returning more than 1 for an image makes its line grow to fit.")) + +(defmethod object-height (drawing-object) + 1) + +(defmethod object-height ((drawing-object display:image-object)) + (let ((ph (image-pixel-dimension drawing-object :pixel-height)) + (ch (jsonrpc-cell-height (lem-core:implementation)))) + (if (and ph ch) + (ceiling ph ch) + (or (display:image-object-height drawing-object) 1)))) + +(defun image-pixel-dimension (object key) + "pixel value of KEY (:pixel-width / :pixel-height) on OBJECT's attribute, or NIL." + (let ((attribute (display:image-object-attribute object))) + (and attribute (lem:attribute-value attribute key)))) (defgeneric draw-object (jsonrpc object x y view)) @@ -711,8 +747,42 @@ same hash." attribute :text-width width))) +(defun image-object-url (object) + "return a URL the JS client can load for OBJECT's image, or NIL. +a pathname or plain-string path is served through the existing /local static route. +a string already carrying a data:/https: URL is passed through unchanged." + (let ((image (display:image-object-image object))) + (typecase image + (pathname (format nil "/local~A" (namestring image))) + (string (if (or (alexandria:starts-with-subseq "data:" image) + (alexandria:starts-with-subseq "http:" image) + (alexandria:starts-with-subseq "https:" image)) + image + (format nil "/local~A" image))) + (t nil)))) + (defmethod draw-object (jsonrpc (object display:image-object) x y view) - (values)) + (let ((url (image-object-url object))) + (when url + (with-error-handler () + ;; use the attribute's :pixel-width/:pixel-height if given, else the reserved cell box + ;; (cells * cell pixel size) when the cell size is known. + (let ((pw (or (image-pixel-dimension object :pixel-width) + (alexandria:when-let ((cw (jsonrpc-cell-width jsonrpc))) + (* (object-width object) cw)))) + (ph (or (image-pixel-dimension object :pixel-height) + (alexandria:when-let ((ch (jsonrpc-cell-height jsonrpc))) + (* (object-height object) ch))))) + (notify* jsonrpc + "put-image" + (hash "viewInfo" (view-id-hash view) + "x" x + "y" y + "width" (object-width object) + "height" (object-height object) + "pixelWidth" pw + "pixelHeight" ph + "url" url))))))) (defun render-line (jsonrpc view x y objects) (loop :for object :in objects @@ -727,11 +797,14 @@ same hash." (defmethod lem-if:render-line ((jsonrpc jsonrpc) view x y objects height) (with-error-handler () + ;; clear the line's full height (not just one row) since a tall object such as an image may + ;; occupy several rows. (notify* jsonrpc "clear-eol" (hash "viewInfo" (view-id-hash view) "x" x - "y" y)) + "y" y + "height" height)) (render-line jsonrpc view x y objects))) (defmethod lem-if:render-line-on-modeline ((jsonrpc jsonrpc) view left-objects right-objects @@ -753,7 +826,7 @@ same hash." (object-width drawing-object)) (defmethod lem-if:object-height ((jsonrpc jsonrpc) drawing-object) - 1) + (object-height drawing-object)) (defmethod lem-if:clear-to-end-of-window ((jsonrpc jsonrpc) view y) (notify* jsonrpc diff --git a/src/display/physical-line.lisp b/src/display/physical-line.lisp index 9fb31f600..fa905ea48 100644 --- a/src/display/physical-line.lisp +++ b/src/display/physical-line.lisp @@ -103,9 +103,9 @@ (line-end-object-offset drawing-object-2)))) (defmethod drawing-object-equal ((drawing-object-1 image-object) (drawing-object-2 image-object)) - (and (eq (image-object-image drawing-object-1) (image-object-image drawing-object-1)) - (equal (image-object-width drawing-object-1) (image-object-width drawing-object-1)) - (equal (image-object-height drawing-object-1) (image-object-height drawing-object-1)))) + (and (eq (image-object-image drawing-object-1) (image-object-image drawing-object-2)) + (equal (image-object-width drawing-object-1) (image-object-width drawing-object-2)) + (equal (image-object-height drawing-object-1) (image-object-height drawing-object-2)))) (defgeneric drawing-object-mergable-p (drawing-object-1 drawing-object-2)) @@ -137,12 +137,6 @@ (equal (line-end-object-offset drawing-object-1) (line-end-object-offset drawing-object-2)))) -(defmethod drawing-object-mergable-p ((drawing-object-1 image-object) (drawing-object-2 image-object)) - (and (eq (image-object-image drawing-object-1) (image-object-image drawing-object-1)) - (equal (image-object-width drawing-object-1) (image-object-width drawing-object-1)) - (equal (image-object-height drawing-object-1) (image-object-height drawing-object-1)))) - - (defgeneric drawing-object-merge (drawing-object-1 drawing-object-2)) (defmethod drawing-object-merge ((drawing-object-1 void-object) (drawing-object-2 void-object)) diff --git a/src/internal-packages.lisp b/src/internal-packages.lisp index 4a98e4298..f3fe501d9 100644 --- a/src/internal-packages.lisp +++ b/src/internal-packages.lisp @@ -14,6 +14,7 @@ :folder-object :icon-object :image-object + :image-object-attribute :image-object-height :image-object-image :image-object-width From 373249053a006a6db018894033699fc2ec6a8b8a Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Tue, 28 Jul 2026 21:58:10 +0300 Subject: [PATCH 02/18] evict drawing-cache entries a tall line overlaps --- src/display/physical-line.lisp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/display/physical-line.lisp b/src/display/physical-line.lisp index fa905ea48..36b174cfb 100644 --- a/src/display/physical-line.lisp +++ b/src/display/physical-line.lisp @@ -371,14 +371,18 @@ Assumes inputs are already reduced (no adjacent mergeable objects)." (drawing-objects-equal objects cache-objects)) :return t)) +(defun remove-drawing-cache-entries-overlapping (entries y height) + "Return ENTRIES with every entry whose rows overlap [Y, Y+HEIGHT) removed." + (remove-if (lambda (elt) + (destructuring-bind (cache-y cache-height drawing-objects) elt + (declare (ignore drawing-objects)) + (and (< cache-y (+ y height)) + (< y (+ cache-y cache-height))))) + entries)) + (defun invalidate-cache (window y height) (setf (drawing-cache window) - (remove-if (lambda (elt) - (destructuring-bind (cache-y cache-height drawing-objects) elt - (declare (ignore drawing-objects)) - (and (<= cache-y y) - (<= (+ y height) (+ cache-y cache-height))))) - (drawing-cache window)))) + (remove-drawing-cache-entries-overlapping (drawing-cache window) y height))) (defun remove-drawing-cache-entries-from (entries y) "Return ENTRIES with drawing-cache rows at or below Y removed. From 7d3fd509b11db2d9be4b4c4e5675c514f64215ec Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Tue, 28 Jul 2026 21:58:32 +0300 Subject: [PATCH 03/18] drop the fingerprint entries of the rows a tall line covers --- src/display/physical-line.lisp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/display/physical-line.lisp b/src/display/physical-line.lisp index 36b174cfb..296dfd52a 100644 --- a/src/display/physical-line.lisp +++ b/src/display/physical-line.lisp @@ -545,10 +545,16 @@ over the top-level spine and tolerant of improper (dotted) lists." (when (and found (eql (car entry) fingerprint)) (cdr entry))))) +(defun evict-line-fingerprint-shadow (cache y height) + "Remove entries in CACHE for the rows a HEIGHT-tall line at Y covers." + (loop :for row :from (1+ y) :below (+ y height) + :do (remhash row cache))) + (defun update-line-fingerprint (window y fingerprint height) - "Store the fingerprint and height for line at Y." - (setf (gethash y (line-fingerprint-cache window)) - (cons fingerprint height))) + "Store the fingerprint and height for line at Y, and drop the rows it covers." + (let ((cache (line-fingerprint-cache window))) + (setf (gethash y cache) (cons fingerprint height)) + (evict-line-fingerprint-shadow cache y height))) (defun redraw-logical-line-when-line-wrapping (window y From 3ce43a46e5013b2315bc8a4abb7f422e1a0adf18 Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Fri, 31 Jul 2026 19:30:41 +0300 Subject: [PATCH 04/18] rename lem-if:get-char-width/height to cell-width/cell-height they now report the size of one character cell in the frontend's layout units (1 on terminal and webview, pixels on sdl2) --- extensions/pixel-demo/pixel-demo.lisp | 12 ++++++------ frontends/fake-interface/fake-interface.lisp | 4 ++-- frontends/ncurses/ncurses.lisp | 5 ++++- frontends/sdl2/main.lisp | 4 ++-- frontends/sdl2/tree.lisp | 2 +- frontends/server/main.lisp | 4 ++-- src/display/physical-line.lisp | 2 +- src/interface.lisp | 10 ++++++++-- src/internal-packages.lisp | 4 ++-- src/mouse.lisp | 4 ++-- src/window/floating-window.lisp | 4 ++-- 11 files changed, 32 insertions(+), 23 deletions(-) diff --git a/extensions/pixel-demo/pixel-demo.lisp b/extensions/pixel-demo/pixel-demo.lisp index 9013df18b..9bbb53dac 100644 --- a/extensions/pixel-demo/pixel-demo.lisp +++ b/extensions/pixel-demo/pixel-demo.lisp @@ -64,8 +64,8 @@ (defun animation-step () "Perform one animation step." (when (and *demo-window* (eq *demo-mode* :animate)) - (let* ((char-width (lem-if:get-char-width (implementation))) - (char-height (lem-if:get-char-height (implementation))) + (let* ((char-width (lem-if:cell-width (implementation))) + (char-height (lem-if:cell-height (implementation))) (display-width (* (display-width) char-width)) (display-height (* (display-height) char-height)) (win-width (or (floating-window-pixel-width *demo-window*) @@ -177,8 +177,8 @@ A floating window follows your mouse cursor at pixel precision." "Update coordinate debug display." (when (and *demo-window* (eq *demo-mode* :debug)) (let* ((mouse-event (lem-core::last-mouse-event)) - (char-width (lem-if:get-char-width (implementation))) - (char-height (lem-if:get-char-height (implementation)))) + (char-width (lem-if:cell-width (implementation))) + (char-height (lem-if:cell-height (implementation)))) (multiple-value-bind (win-px win-py win-pw win-ph) (floating-window-pixel-bounds *demo-window*) (let ((content @@ -230,8 +230,8 @@ Shows real-time pixel and character coordinate information." (defun compare-animation-step () "Animate both windows for comparison." (when (eq *demo-mode* :compare) - (let* ((char-width (lem-if:get-char-width (implementation))) - (char-height (lem-if:get-char-height (implementation))) + (let* ((char-width (lem-if:cell-width (implementation))) + (char-height (lem-if:cell-height (implementation))) (display-width (* (display-width) char-width)) (display-height (* (display-height) char-height)) (win-width (* 20 char-width))) diff --git a/frontends/fake-interface/fake-interface.lisp b/frontends/fake-interface/fake-interface.lisp index 1f9aa94d0..1e676e9fe 100644 --- a/frontends/fake-interface/fake-interface.lisp +++ b/frontends/fake-interface/fake-interface.lisp @@ -103,10 +103,10 @@ (defmethod lem-if:clear-to-end-of-window ((implementation fake-interface) view y) nil) -(defmethod lem-if:get-char-width ((implementation fake-interface)) +(defmethod lem-if:cell-width ((implementation fake-interface)) 1) -(defmethod lem-if:get-char-height ((implementation fake-interface)) +(defmethod lem-if:cell-height ((implementation fake-interface)) 1) (defmethod lem-if:render-line-on-modeline ((implementation fake-interface) diff --git a/frontends/ncurses/ncurses.lisp b/frontends/ncurses/ncurses.lisp index 5f1c60bd3..61b168604 100644 --- a/frontends/ncurses/ncurses.lisp +++ b/frontends/ncurses/ncurses.lisp @@ -106,7 +106,10 @@ (defmethod lem-if:clear-to-end-of-window ((implementation ncurses) view y) (lem-ncurses/render:clear-to-end-of-window view y)) -(defmethod lem-if:get-char-width ((implementation ncurses)) +(defmethod lem-if:cell-width ((implementation ncurses)) + 1) + +(defmethod lem-if:cell-height ((implementation ncurses)) 1) ;; for mouse control diff --git a/frontends/sdl2/main.lisp b/frontends/sdl2/main.lisp index 3940e6ef3..278c0a60b 100644 --- a/frontends/sdl2/main.lisp +++ b/frontends/sdl2/main.lisp @@ -470,11 +470,11 @@ (values (display:scaled-char-width display x) (display:scaled-char-height display y)))))) -(defmethod lem-if:get-char-width ((implementation sdl2)) +(defmethod lem-if:cell-width ((implementation sdl2)) (display:with-display (display) (display:display-char-width display))) -(defmethod lem-if:get-char-height ((implementation sdl2)) +(defmethod lem-if:cell-height ((implementation sdl2)) (display:with-display (display) (display:display-char-height display))) diff --git a/frontends/sdl2/tree.lisp b/frontends/sdl2/tree.lisp index 998635296..036e17d22 100644 --- a/frontends/sdl2/tree.lisp +++ b/frontends/sdl2/tree.lisp @@ -29,7 +29,7 @@ (defmethod tree-view-scroll-vertically ((buffer tree-view-buffer) window n) (incf (tree-view-buffer-scroll-y buffer) n) (let* ((height (* (1- (window-height window)) - (lem-if:get-char-height (implementation)))) + (lem-if:cell-height (implementation)))) (last-y (max 0 (- (tree-view-buffer-height buffer) height)))) (cond ((< last-y (tree-view-buffer-scroll-y buffer)) diff --git a/frontends/server/main.lisp b/frontends/server/main.lisp index f8a28164a..280041817 100644 --- a/frontends/server/main.lisp +++ b/frontends/server/main.lisp @@ -478,10 +478,10 @@ the same immutable instance for every subsequent message." (defmethod lem-if:get-mouse-position ((jsonrpc jsonrpc)) (mouse:get-position)) -(defmethod lem-if:get-char-width ((jsonrpc jsonrpc)) +(defmethod lem-if:cell-width ((jsonrpc jsonrpc)) ;; TODO 1) -(defmethod lem-if:get-char-height ((jsonrpc jsonrpc)) +(defmethod lem-if:cell-height ((jsonrpc jsonrpc)) ;; TODO 1) diff --git a/src/display/physical-line.lisp b/src/display/physical-line.lisp index 296dfd52a..4c130aebb 100644 --- a/src/display/physical-line.lisp +++ b/src/display/physical-line.lisp @@ -736,7 +736,7 @@ creating zero temporary letter-objects." (invalidate-drawing-cache-from window y) (lem-if:clear-to-end-of-window (implementation) (window-view window) y)) (setf (window-left-width window) - (floor left-side-width (lem-if:get-char-width (implementation))))))) + (floor left-side-width (lem-if:cell-width (implementation))))))) (defun call-with-display-error (function) (handler-bind ((error (lambda (e) diff --git a/src/interface.lisp b/src/interface.lisp index ef762a86a..a4f33a9b6 100644 --- a/src/interface.lisp +++ b/src/interface.lisp @@ -175,8 +175,14 @@ PIXEL-X, PIXEL-Y, PIXEL-WIDTH, PIXEL-HEIGHT are in pixels (may be nil for auto-c (:method (implementation) (values -1 -1))) -(defgeneric lem-if:get-char-width (implementation)) -(defgeneric lem-if:get-char-height (implementation)) +(defgeneric lem-if:cell-width (implementation) + (:documentation "Width of one character cell in the frontend's native layout units. +1 on a cell-based frontend (a terminal counts in cells), pixels on a pixel-based one. These are +the units `object-width' / `object-height' are counted in.")) + +(defgeneric lem-if:cell-height (implementation) + (:documentation "Height of one character cell in the frontend's native layout units. +Unit-relative like `cell-width'.")) (defgeneric lem-if:render-line (implementation view x y objects height)) (defgeneric lem-if:render-line-on-modeline (implementation view left-objects right-objects diff --git a/src/internal-packages.lisp b/src/internal-packages.lisp index f3fe501d9..42cd3acc0 100644 --- a/src/internal-packages.lisp +++ b/src/internal-packages.lisp @@ -820,8 +820,8 @@ :get-font-by-name-and-style :get-font :get-mouse-position - :get-char-width - :get-char-height + :cell-width + :cell-height :clear-to-end-of-window :js-eval :render-line diff --git a/src/mouse.lisp b/src/mouse.lisp index c08f9e105..7faa8548d 100644 --- a/src/mouse.lisp +++ b/src/mouse.lisp @@ -64,10 +64,10 @@ (y (mouse-event-pixel-y mouse-event))) (values (- x (* (window-x window) - (lem-if:get-char-width (implementation)))) + (lem-if:cell-width (implementation)))) (- y (* (window-y window) - (lem-if:get-char-height (implementation))))))) + (lem-if:cell-height (implementation))))))) (defun get-point-from-window-with-coordinates (window x y &optional (allow-overflow-column t)) (with-point ((point (buffer-point (window-buffer window)))) diff --git a/src/window/floating-window.lisp b/src/window/floating-window.lisp index d37516a1d..ca93109d5 100644 --- a/src/window/floating-window.lisp +++ b/src/window/floating-window.lisp @@ -142,8 +142,8 @@ This updates the window's pixel dimensions and notifies the frontend." Returns (values pixel-x pixel-y pixel-width pixel-height). If pixel coordinates are not set, calculates from character coordinates." (check-type window floating-window) - (let ((char-width (lem-if:get-char-width (implementation))) - (char-height (lem-if:get-char-height (implementation)))) + (let ((char-width (lem-if:cell-width (implementation))) + (char-height (lem-if:cell-height (implementation)))) (values (or (floating-window-pixel-x window) (* (window-x window) char-width)) (or (floating-window-pixel-y window) From 655c2034760de450a7a612d33c039b1d5b6c5ded Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Fri, 31 Jul 2026 19:47:25 +0300 Subject: [PATCH 05/18] move default object-width/object-height into the core every frontend measured the same way, so the arithmetic now lives once in physical-line.lisp. frontends keep a method only for what they draw at another size. an image with no size of its own asks for one through the new lem-if:image-natural-size. --- frontends/ncurses/drawing-object.lisp | 29 ------ frontends/ncurses/lem-ncurses.asd | 1 - frontends/ncurses/ncurses.lisp | 10 +- frontends/ncurses/render.lisp | 4 +- frontends/sdl2/drawing.lisp | 136 +++++--------------------- src/display/physical-line.lisp | 36 +++++++ src/interface.lisp | 24 ++++- src/internal-packages.lisp | 5 + 8 files changed, 98 insertions(+), 147 deletions(-) delete mode 100644 frontends/ncurses/drawing-object.lisp diff --git a/frontends/ncurses/drawing-object.lisp b/frontends/ncurses/drawing-object.lisp deleted file mode 100644 index b0e92122d..000000000 --- a/frontends/ncurses/drawing-object.lisp +++ /dev/null @@ -1,29 +0,0 @@ -(defpackage :lem-ncurses/drawing-object - (:use :cl - :lem-core/display) - (:export :object-width - :object-height)) -(in-package :lem-ncurses/drawing-object) - -(defgeneric object-width (drawing-object)) - -(defmethod object-width ((drawing-object void-object)) - 0) - -(defmethod object-width ((drawing-object text-object)) - (lem-core:string-width (text-object-string drawing-object))) - -(defmethod object-width ((drawing-object eol-cursor-object)) - 0) - -(defmethod object-width ((drawing-object extend-to-eol-object)) - 0) - -(defmethod object-width ((drawing-object line-end-object)) - (lem-core:string-width (text-object-string drawing-object))) - -(defmethod object-width ((drawing-object image-object)) - 0) - -(defmethod object-height (drawing-object) - 1) diff --git a/frontends/ncurses/lem-ncurses.asd b/frontends/ncurses/lem-ncurses.asd index 1c33af19f..2036ca22f 100644 --- a/frontends/ncurses/lem-ncurses.asd +++ b/frontends/ncurses/lem-ncurses.asd @@ -12,7 +12,6 @@ (:file "style") (:file "key") (:file "attribute") - (:file "drawing-object") (:file "view") (:file "render") (:file "input") diff --git a/frontends/ncurses/ncurses.lisp b/frontends/ncurses/ncurses.lisp index 61b168604..e1df0eaf4 100644 --- a/frontends/ncurses/ncurses.lisp +++ b/frontends/ncurses/ncurses.lisp @@ -97,11 +97,13 @@ height) (lem-ncurses/render:render-line-on-modeline view left-objects right-objects default-attribute)) -(defmethod lem-if:object-width ((implementation ncurses) drawing-object) - (lem-ncurses/drawing-object:object-width drawing-object)) +(defmethod lem-if:object-width ((implementation ncurses) + (drawing-object lem-core/display:image-object)) + 0) -(defmethod lem-if:object-height ((implementation ncurses) drawing-object) - (lem-ncurses/drawing-object:object-height drawing-object)) +(defmethod lem-if:object-height ((implementation ncurses) + (drawing-object lem-core/display:image-object)) + 1) (defmethod lem-if:clear-to-end-of-window ((implementation ncurses) view y) (lem-ncurses/render:clear-to-end-of-window view y)) diff --git a/frontends/ncurses/render.lisp b/frontends/ncurses/render.lisp index e67f4387b..3065c74a6 100644 --- a/frontends/ncurses/render.lisp +++ b/frontends/ncurses/render.lisp @@ -64,7 +64,7 @@ (defun render-line-from-behind (view y objects scrwin) (loop :with current-x := (lem-if:view-width (lem:implementation) view) :for object :in objects - :do (decf current-x (lem-ncurses/drawing-object:object-width object)) + :do (decf current-x (lem-if:object-width (lem:implementation) object)) (draw-object object current-x y view scrwin))) (defun clear-line (view x y) @@ -74,7 +74,7 @@ (defun %render-line (view x y objects scrwin) (loop :for object :in objects :do (draw-object object x y view scrwin) - (incf x (lem-ncurses/drawing-object:object-width object)))) + (incf x (lem-if:object-width (lem:implementation) object)))) (defun render-line (view x y objects) (clear-line view x y) diff --git a/frontends/sdl2/drawing.lisp b/frontends/sdl2/drawing.lisp index e941f850f..2ea30b7c8 100644 --- a/frontends/sdl2/drawing.lisp +++ b/frontends/sdl2/drawing.lisp @@ -65,100 +65,18 @@ Uses a sentinel key so it participates in the normal cache lifecycle "__folder_icon__" nil :folder surface) surface))) -(defgeneric object-width (drawing-object display)) +(defmethod lem-if:image-natural-size ((implementation lem-sdl2/sdl2:sdl2) image) + (values (sdl2:surface-width image) (sdl2:surface-height image))) -(defmethod object-width ((drawing-object void-object) display) - 0) - -(defun text-cell-width (drawing-object display) - "Cell-aligned pixel width of a text-object: string-width × char-width. -Mirrors lem-ncurses/drawing-object:object-width semantics (logical -column width) so SDL2 text aligns on the character grid regardless of -per-string SDL_ttf surface-width drift." - (* (lem-core:string-width (text-object-string drawing-object)) - (display:display-char-width display))) - -(defmethod object-width ((drawing-object text-object) display) - (text-cell-width drawing-object display)) - -(defmethod object-width ((drawing-object control-character-object) display) - (* 2 (display:display-char-width display))) - -(defmethod object-width ((drawing-object icon-object) display) - ;; Cell-aligned advance (typically 2 * char-width). The icon font's natural - ;; glyph surface is usually wider than this; draw-object scales it to fit. - (text-cell-width drawing-object display)) - -(defmethod object-width ((drawing-object folder-object) display) - (* 2 (display:display-char-width display))) - -(defmethod object-width ((drawing-object emoji-object) display) - (* (display:display-char-width display) 2 (length (text-object-string drawing-object)))) - -(defmethod object-width ((drawing-object eol-cursor-object) display) - 0) - -(defmethod object-width ((drawing-object extend-to-eol-object) display) - 0) - -(defmethod object-width ((drawing-object line-end-object) display) - (text-cell-width drawing-object display)) - -(defmethod object-width ((drawing-object image-object) display) - (or (image-object-width drawing-object) - (sdl2:surface-width (image-object-image drawing-object)))) - - -(defgeneric object-height (drawing-object display)) - -(defmethod object-height ((drawing-object void-object) display) - (display:display-char-height display)) - -(defmethod object-height ((drawing-object text-object) display) - ;; Use the stable row cell-height (derived from font metrics at the - ;; display level) rather than the per-string SDL_ttf surface height. - ;; SDL_ttf can return slightly different surface heights for different - ;; strings (e.g. ones containing descenders like `p'/`g'/`y' versus - ;; ones without), which would otherwise leak into the background - ;; rectangle drawn by `draw-text-glyph-surface', producing the - ;; uneven-extent "padding around the problem letters" artefact at - ;; attribute boundaries on a highlighted row. The natural surface - ;; height is still read inside `draw-text-glyph-surface' directly - ;; from the surface for baseline-anchored glyph blitting. - (display:display-char-height display)) - -(defmethod object-height ((drawing-object icon-object) display) - (display:display-char-height display)) - -(defmethod object-height ((drawing-object control-character-object) display) - (display:display-char-height display)) - -(defmethod object-height ((drawing-object folder-object) display) - (display:display-char-height display)) - -(defmethod object-height ((drawing-object emoji-object) display) - (display:display-char-height display)) - -(defmethod object-height ((drawing-object eol-cursor-object) display) - (display:display-char-height display)) - -(defmethod object-height ((drawing-object extend-to-eol-object) display) - (display:display-char-height display)) - -(defmethod object-height ((drawing-object line-end-object) display) - (display:display-char-height display)) - -(defmethod object-height ((drawing-object image-object) display) - (or (image-object-height drawing-object) - (sdl2:surface-height (image-object-image drawing-object)))) - -(defmethod lem-if:object-width ((implementation lem-sdl2/sdl2:sdl2) drawing-object) +(defmethod lem-if:object-width ((implementation lem-sdl2/sdl2:sdl2) + (drawing-object folder-object)) (display:with-display (display) - (object-width drawing-object display))) + (* 2 (display:display-char-width display)))) -(defmethod lem-if:object-height ((implementation lem-sdl2/sdl2:sdl2) drawing-object) +(defmethod lem-if:object-width ((implementation lem-sdl2/sdl2:sdl2) + (drawing-object emoji-object)) (display:with-display (display) - (object-height drawing-object display))) + (* (display:display-char-width display) 2 (length (text-object-string drawing-object))))) (defmethod draw-object ((drawing-object void-object) x bottom-y display view) 0) @@ -208,7 +126,7 @@ is not erased by the next glyph's background fill." (let* ((surface (get-surface drawing-object display)) (surface-width (sdl2:surface-width surface)) (surface-height (sdl2:surface-height surface)) - (cell-height (object-height drawing-object display)) + (cell-height (object-height drawing-object)) (attribute (text-object-attribute drawing-object)) (background (lem-core:attribute-background-with-reverse attribute)) (y (- bottom-y cell-height)) @@ -275,14 +193,14 @@ is not erased by the next glyph's background fill." (or (lem:parse-color underline) (lem-core:attribute-foreground-color attribute)))))))) -(defun text-object-letter-objects-and-widths (drawing-object display) +(defun text-object-letter-objects-and-widths (drawing-object) "Return two parallel lists: per-character letter-objects and their cell widths, for the multi-character text run DRAWING-OBJECT." (let ((attribute (text-object-attribute drawing-object))) (loop :for c :across (text-object-string drawing-object) :for letter := (make-letter-object c attribute) :collect letter :into letters - :collect (object-width letter display) :into widths + :collect (object-width letter) :into widths :finally (return (values letters widths))))) (defun draw-text-object-phase (drawing-object x bottom-y display view phase) @@ -293,11 +211,11 @@ width so the rasterizer's right-edge anti-aliasing tail is preserved." (let ((string (text-object-string drawing-object))) (cond ((<= (length string) 1) (draw-text-glyph-surface drawing-object x bottom-y display view - (object-width drawing-object display) + (object-width drawing-object) :clip t :phase phase)) (t (multiple-value-bind (letter-objects letter-widths) - (text-object-letter-objects-and-widths drawing-object display) + (text-object-letter-objects-and-widths drawing-object) (loop :with current-x := x :for letter-object :in letter-objects :for letter-width :in letter-widths @@ -319,7 +237,7 @@ width so the rasterizer's right-edge anti-aliasing tail is preserved." ;; The cross-text-object equivalent (an adjacent text-object's :bg erasing ;; the previous text-object's AA tail) is handled by `redraw-physical-line', ;; which lifts the two-pass to span the entire physical line. - (let ((total-width (object-width drawing-object display))) + (let ((total-width (object-width drawing-object))) (draw-text-object-phase drawing-object x bottom-y display view :bg) (draw-text-object-phase drawing-object x bottom-y display view :glyph) total-width)) @@ -327,14 +245,14 @@ width so the rasterizer's right-edge anti-aliasing tail is preserved." (defmethod draw-object ((drawing-object icon-object) x bottom-y display view) ;; Icon font glyphs typically render much wider than the 2-cell column the ;; layout reserves for them; draw-text-glyph-surface scales them down to fit. - (let ((cell-width (object-width drawing-object display))) + (let ((cell-width (object-width drawing-object))) (draw-text-glyph-surface drawing-object x bottom-y display view cell-width) cell-width)) (defmethod draw-object ((drawing-object folder-object) x bottom-y display view) ;; Folder PNG surface is much wider than 2 cells; render once and scale to fit. ;; Overrides the text-object per-character loop so the icon stays atomic. - (let ((cell-width (object-width drawing-object display))) + (let ((cell-width (object-width drawing-object))) (draw-text-glyph-surface drawing-object x bottom-y display view cell-width) cell-width)) @@ -343,21 +261,21 @@ width so the rasterizer's right-edge anti-aliasing tail is preserved." ;; ZWJ sequences, ...) that must be rendered as one composed glyph. Use the ;; single-surface path with cell-aligned scaling so we neither split the ;; sequence per-codepoint nor let an oversized emoji surface spill over. - (let ((cell-width (object-width drawing-object display))) + (let ((cell-width (object-width drawing-object))) (draw-text-glyph-surface drawing-object x bottom-y display view cell-width) cell-width)) (defmethod draw-object ((drawing-object eol-cursor-object) x bottom-y display view) (display:set-render-color display (eol-cursor-object-color drawing-object)) - (let ((y (- bottom-y (object-height drawing-object display)))) + (let ((y (- bottom-y (object-height drawing-object)))) (lem-sdl2/view:set-cursor-position view x y) (draw-cursor display x y (display:display-char-width display) - (object-height drawing-object display) + (object-height drawing-object) (eol-cursor-object-color drawing-object))) - (object-width drawing-object display)) + (object-width drawing-object)) (defmethod draw-object ((drawing-object extend-to-eol-object) x bottom-y display view) (display:set-render-color display (extend-to-eol-object-color drawing-object)) @@ -367,7 +285,7 @@ width so the rasterizer's right-edge anti-aliasing tail is preserved." (- (lem-if:view-width (lem-core:implementation) view) x) (display:display-char-height display)) (sdl2:render-fill-rect (display:display-renderer display) rect)) - (object-width drawing-object display)) + (object-width drawing-object)) (defmethod draw-object ((drawing-object line-end-object) x bottom-y display view) (call-next-method drawing-object @@ -379,8 +297,8 @@ width so the rasterizer's right-edge anti-aliasing tail is preserved." view)) (defmethod draw-object ((drawing-object image-object) x bottom-y display view) - (let* ((surface-width (object-width drawing-object display)) - (surface-height (object-height drawing-object display)) + (let* ((surface-width (object-width drawing-object)) + (surface-height (object-height drawing-object)) (texture (sdl2:create-texture-from-surface (display:display-renderer display) (image-object-image drawing-object))) (y (- bottom-y surface-height))) @@ -418,18 +336,18 @@ rather than the row-wide two-pass)." :for object :in objects :while (< current-x display-width) :collect (cons object current-x) - :do (incf current-x (object-width object display))))) + :do (incf current-x (object-width object))))) (flet ((draw-text-pass (object obj-x phase) ;; Honour the wrap-to-letters branch the old code used when a ;; text-object would extend past the display width. (cond ((< display-width - (+ obj-x (object-width object display))) + (+ obj-x (object-width object))) (loop :with current-x := obj-x :for c :across (text-object-string object) :while (< current-x display-width) :for letter := (make-letter-object c (text-object-attribute object)) - :for letter-width := (object-width letter display) + :for letter-width := (object-width letter) :do (draw-text-glyph-surface letter current-x bottom-y display view letter-width :clip t :phase phase) @@ -452,7 +370,7 @@ rather than the row-wide two-pass)." (loop :with current-x := (lem-if:view-width (lem-core:implementation) view) :and y := (lem-if:view-height (lem-core:implementation) view) :for object :in objects - :do (decf current-x (object-width object display)) + :do (decf current-x (object-width object)) (draw-object object current-x y display view))) (defun fill-to-end-of-line (display view x y height &optional default-attribute) diff --git a/src/display/physical-line.lisp b/src/display/physical-line.lisp index 4c130aebb..75de4b114 100644 --- a/src/display/physical-line.lisp +++ b/src/display/physical-line.lisp @@ -62,6 +62,42 @@ (height :initarg :height :reader image-object-height) (attribute :initarg :attribute :reader image-object-attribute))) +(defun image-draw-width (implementation object) + "Pixel width OBJECT's image is drawn at. +:width on the object is a pixel count. An image carrying none is drawn at its natural size if the +frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." + (or (image-object-width object) + (nth-value 0 (lem-if:image-natural-size implementation (image-object-image object))) + (lem-if:cell-width implementation))) + +(defun image-draw-height (implementation object) + "Pixel height OBJECT's image is drawn at, as `image-draw-width' on the other axis." + (or (image-object-height object) + (nth-value 1 (lem-if:image-natural-size implementation (image-object-image object))) + (lem-if:cell-height implementation))) + +(defmethod lem-if:object-width (implementation (drawing-object void-object)) + 0) + +(defmethod lem-if:object-width (implementation (drawing-object text-object)) + (* (string-width (text-object-string drawing-object)) + (lem-if:cell-width implementation))) + +(defmethod lem-if:object-width (implementation (drawing-object eol-cursor-object)) + 0) + +(defmethod lem-if:object-width (implementation (drawing-object extend-to-eol-object)) + 0) + +(defmethod lem-if:object-width (implementation (drawing-object image-object)) + (image-draw-width implementation drawing-object)) + +(defmethod lem-if:object-height (implementation (drawing-object drawing-object)) + (lem-if:cell-height implementation)) + +(defmethod lem-if:object-height (implementation (drawing-object image-object)) + (image-draw-height implementation drawing-object)) + (defmethod cursor-object-p (drawing-object) nil) diff --git a/src/interface.lisp b/src/interface.lisp index a4f33a9b6..64b25d868 100644 --- a/src/interface.lisp +++ b/src/interface.lisp @@ -187,8 +187,28 @@ Unit-relative like `cell-width'.")) (defgeneric lem-if:render-line (implementation view x y objects height)) (defgeneric lem-if:render-line-on-modeline (implementation view left-objects right-objects default-attribute height)) -(defgeneric lem-if:object-width (implementation drawing-object)) -(defgeneric lem-if:object-height (implementation drawing-object)) +(defgeneric lem-if:object-width (implementation drawing-object) + (:documentation "Width DRAWING-OBJECT occupies, in the same units as `cell-width'. +The default methods in src/display/physical-line.lisp derive this from `cell-width'. A +`lem-core/display:text-object' (one run of characters sharing an attribute) is as wide as its +string: `string-width' cells, counting a wide glyph as two. An image takes the pixel width it is +drawn at (`lem-core/display:image-draw-width'). +Specialize this only for an object the frontend draws at some other size, as sdl2 does for its +folder and emoji glyphs.")) + +(defgeneric lem-if:object-height (implementation drawing-object) + (:documentation "Height DRAWING-OBJECT occupies, in the same units as `cell-height'. +Defaults to one cell for every object but an image, which takes the pixel height it is drawn at +(`lem-core/display:image-draw-height'). Specialize it as in `object-width'.")) + +(defgeneric lem-if:image-natural-size (implementation image) + (:documentation "Fallback size for an image whose object requests no particular size. +Returns (values WIDTH HEIGHT) in pixels, or NIL NIL if the frontend can't tell. IMAGE is the +frontend's own loaded-image handle (an SDL surface, a path handed to a browser, ...), the value +stored in an `lem-core/display:image-object' and obtained via `image-object-image'. See +`lem-core/display:image-draw-width'.") + (:method (implementation image) + (values nil nil))) (defgeneric lem-if:clear-to-end-of-window (implementation view y)) (defgeneric lem-if:js-eval (implementation view code &key wait) diff --git a/src/internal-packages.lisp b/src/internal-packages.lisp index 42cd3acc0..a87300bef 100644 --- a/src/internal-packages.lisp +++ b/src/internal-packages.lisp @@ -18,6 +18,10 @@ :image-object-height :image-object-image :image-object-width + :image-draw-width + :image-draw-height + :object-height + :object-width :line-end-object :line-end-object-offset :text-object @@ -828,4 +832,5 @@ :render-line-on-modeline :object-width :object-height + :image-natural-size :set-frame-color)) From 881f49c24f19a883492cb06d39808e3acde67152 Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Fri, 31 Jul 2026 21:06:01 +0300 Subject: [PATCH 06/18] lay rows out in the core, hand frontends a laid-out row lem-if:render-line handed frontends loose objects and left placement to each one. it is replaced by lem-if:render-row, taking a lem-core/display:row with height, fill and per-object placement from layout-row. objects hang from a shared baseline, reported via lem-if:cell-pixel-size and lem-if:object-ascent. extend-to-eol becomes row-fill-x/row-fill-color rather than an object. --- .claude/rules/frontend.md | 2 +- frontends/fake-interface/fake-interface.lisp | 12 +- frontends/ncurses/ncurses.lisp | 20 +- frontends/ncurses/render.lisp | 64 +++-- frontends/ncurses/view.lisp | 4 +- frontends/sdl2/display.lisp | 2 +- frontends/sdl2/drawing.lisp | 239 +++++++++---------- frontends/sdl2/main.lisp | 6 + frontends/server/main.lisp | 73 +++--- src/color-theme.lisp | 2 +- src/display/physical-line.lisp | 192 ++++++++++++--- src/interface.lisp | 42 +++- src/internal-packages.lisp | 21 +- 13 files changed, 407 insertions(+), 272 deletions(-) diff --git a/.claude/rules/frontend.md b/.claude/rules/frontend.md index 3cae97a9e..cec33ccb9 100644 --- a/.claude/rules/frontend.md +++ b/.claude/rules/frontend.md @@ -20,7 +20,7 @@ Frontends subclass `implementation` and implement `lem-if:*` generics. (lem-if:set-view-pos impl view x y) ;; Rendering -(lem-if:render-line impl view x y objects height) +(lem-if:render-row impl view row) ; ROW is a laid-out lem-core/display:row (lem-if:clear-to-end-of-window impl view y) ``` diff --git a/frontends/fake-interface/fake-interface.lisp b/frontends/fake-interface/fake-interface.lisp index 1e676e9fe..241004004 100644 --- a/frontends/fake-interface/fake-interface.lisp +++ b/frontends/fake-interface/fake-interface.lisp @@ -97,7 +97,7 @@ (defmethod lem-if:object-height ((implementation fake-interface) object) 1) -(defmethod lem-if:render-line ((implementation fake-interface) view x y objects height) +(defmethod lem-if:render-row ((implementation fake-interface) view row) nil) (defmethod lem-if:clear-to-end-of-window ((implementation fake-interface) view y) @@ -109,12 +109,10 @@ (defmethod lem-if:cell-height ((implementation fake-interface)) 1) -(defmethod lem-if:render-line-on-modeline ((implementation fake-interface) - view - left-objects - right-objects - default-attribute - height) +(defmethod lem-if:render-modeline-row ((implementation fake-interface) + view + row + default-attribute) nil) (defmacro with-fake-interface (() &body body) diff --git a/frontends/ncurses/ncurses.lisp b/frontends/ncurses/ncurses.lisp index e1df0eaf4..3c1060820 100644 --- a/frontends/ncurses/ncurses.lisp +++ b/frontends/ncurses/ncurses.lisp @@ -85,17 +85,11 @@ (defmethod lem-if:view-height ((implementation ncurses) view) (lem-ncurses/view:view-height view)) -(defmethod lem-if:render-line ((implementation ncurses) - view x y objects height) - (lem-ncurses/render:render-line view x y objects)) - -(defmethod lem-if:render-line-on-modeline ((implementation ncurses) - view - left-objects - right-objects - default-attribute - height) - (lem-ncurses/render:render-line-on-modeline view left-objects right-objects default-attribute)) +(defmethod lem-if:render-row ((implementation ncurses) view row) + (lem-ncurses/render:render-row view row)) + +(defmethod lem-if:render-modeline-row ((implementation ncurses) view row default-attribute) + (lem-ncurses/render:render-modeline-row view row default-attribute)) (defmethod lem-if:object-width ((implementation ncurses) (drawing-object lem-core/display:image-object)) @@ -105,6 +99,10 @@ (drawing-object lem-core/display:image-object)) 1) +(defmethod lem-if:object-ascent ((implementation ncurses) + (drawing-object lem-core/display:image-object)) + 1) + (defmethod lem-if:clear-to-end-of-window ((implementation ncurses) view y) (lem-ncurses/render:clear-to-end-of-window view y)) diff --git a/frontends/ncurses/render.lisp b/frontends/ncurses/render.lisp index 3065c74a6..cd96fef35 100644 --- a/frontends/ncurses/render.lisp +++ b/frontends/ncurses/render.lisp @@ -1,8 +1,8 @@ (defpackage :lem-ncurses/render (:use :cl :lem-core/display) - (:export :render-line - :render-line-on-modeline + (:export :render-row + :render-modeline-row :clear-to-end-of-window)) (in-package :lem-ncurses/render) @@ -37,17 +37,6 @@ " " (lem:make-attribute :foreground (lem:color-to-hex-string (eol-cursor-object-color object))))) -(defmethod draw-object ((object extend-to-eol-object) x y view scrwin) - (let ((width (lem-if:view-width (lem:implementation) view))) - (when (< x width) - (print-string - scrwin - x - y - (make-string (- width x) :initial-element #\space) - (lem:make-attribute :background - (lem:color-to-hex-string (extend-to-eol-object-color object))))))) - (defmethod draw-object ((object line-end-object) x y view scrwin) (let ((string (text-object-string object)) (attribute (text-object-attribute object))) @@ -61,40 +50,43 @@ (defmethod draw-object ((object image-object) x y view scrwin) (values)) -(defun render-line-from-behind (view y objects scrwin) - (loop :with current-x := (lem-if:view-width (lem:implementation) view) - :for object :in objects - :do (decf current-x (lem-if:object-width (lem:implementation) object)) - (draw-object object current-x y view scrwin))) - (defun clear-line (view x y) (charms/ll:wmove (lem-ncurses/view:view-scrwin view) y x) (charms/ll:wclrtoeol (lem-ncurses/view:view-scrwin view))) -(defun %render-line (view x y objects scrwin) - (loop :for object :in objects - :do (draw-object object x y view scrwin) - (incf x (lem-if:object-width (lem:implementation) object)))) +(defun draw-row (view row scrwin) + "Draw ROW's background fill, then everything placed on it. +The fill is spaces carrying the background color, since a terminal cell only takes a color by +having a character written into it." + (let ((width (lem-if:view-width (lem:implementation) view))) + (when (and (row-fill-color row) + (< (row-fill-x row) width)) + (print-string scrwin + (row-fill-x row) + (row-top row) + (make-string (- width (row-fill-x row)) :initial-element #\space) + (lem:make-attribute :background + (lem:color-to-hex-string (row-fill-color row)))))) + (loop :for placement :in (row-placements row) + :do (draw-object (placement-object placement) + (placement-x placement) + (placement-top placement) + view + scrwin))) -(defun render-line (view x y objects) - (clear-line view x y) - (%render-line view x y objects (lem-ncurses/view:view-scrwin view))) +(defun render-row (view row) + (clear-line view 0 (row-top row)) + (draw-row view row (lem-ncurses/view:view-scrwin view))) -(defun render-line-on-modeline (view - left-objects - right-objects - default-attribute) +(defun render-modeline-row (view row default-attribute) + ;; the modeline gets its own curses window, so its row (laid out at top 0) needs no translation. (print-string (lem-ncurses/view:view-modeline-scrwin view) 0 - 0 + (row-top row) (make-string (lem-ncurses/view:view-width view) :initial-element #\space) default-attribute) - (%render-line view 0 0 left-objects (lem-ncurses/view:view-modeline-scrwin view)) - (render-line-from-behind view - 0 - right-objects - (lem-ncurses/view:view-modeline-scrwin view))) + (draw-row view row (lem-ncurses/view:view-modeline-scrwin view))) (defun clear-to-end-of-window (view y) (let ((win (lem-ncurses/view:view-scrwin view))) diff --git a/frontends/ncurses/view.lisp b/frontends/ncurses/view.lisp index b5d31c674..25225f85c 100644 --- a/frontends/ncurses/view.lisp +++ b/frontends/ncurses/view.lisp @@ -16,8 +16,8 @@ :set-view-pos :redraw-view-after :redraw-display-after - :render-line - :render-line-on-modeline + :render-row + :render-modeline-row :clear-to-end-of-window :update-display :set-last-print-cursor)) diff --git a/frontends/sdl2/display.lisp b/frontends/sdl2/display.lisp index ff3255866..b48955dbf 100644 --- a/frontends/sdl2/display.lisp +++ b/frontends/sdl2/display.lisp @@ -112,7 +112,7 @@ Retina to a 1x display).") :documentation "Pre-allocated SDL_Rect reused across all render calls to avoid heap-allocating a new rect + Lisp wrapper on every draw-rect, -fill-to-end-of-line, render-texture, etc. Mutated in-place by +fill-row, render-texture, etc. Mutated in-place by `call-with-scratch-rect' / `with-scratch-rect'; do not rely on its contents outside the dynamic extent of that call."))) diff --git a/frontends/sdl2/drawing.lisp b/frontends/sdl2/drawing.lisp index 2ea30b7c8..ec949b938 100644 --- a/frontends/sdl2/drawing.lisp +++ b/frontends/sdl2/drawing.lisp @@ -78,7 +78,12 @@ Uses a sentinel key so it participates in the normal cache lifecycle (display:with-display (display) (* (display:display-char-width display) 2 (length (text-object-string drawing-object))))) -(defmethod draw-object ((drawing-object void-object) x bottom-y display view) +(defgeneric draw-object (drawing-object x top display view) + (:documentation "Draw DRAWING-OBJECT into VIEW with its top-left corner at (X, TOP). +Returns the pixel width it occupied. +`lem-core/display:layout-row' already chose TOP as the row's baseline minus this object's ascent.")) + +(defmethod draw-object ((drawing-object void-object) x top display view) 0) (defun draw-rect (display x y width height color) @@ -95,10 +100,10 @@ Uses a sentinel key so it participates in the normal cache lifecycle (:underline (draw-rect display x (+ y surface-height -1) surface-width 1 background)))) -(defun draw-text-glyph-surface (drawing-object x bottom-y display view cell-width +(defun draw-text-glyph-surface (drawing-object x top display view cell-width &key clip (phase :both)) "Draws DRAWING-OBJECT's cached SDL surface in a (CELL-WIDTH × cell-height) slot -at (X, BOTTOM-Y). Cell-height is taken from the drawing-object's OBJECT-HEIGHT so +at (X, TOP). Cell-height is taken from the drawing-object's OBJECT-HEIGHT so non-text surfaces (folder PNG, icon font, emoji font) get scaled to the editor's character row height instead of being placed at their natural pixel height. @@ -129,15 +134,15 @@ is not erased by the next glyph's background fill." (cell-height (object-height drawing-object)) (attribute (text-object-attribute drawing-object)) (background (lem-core:attribute-background-with-reverse attribute)) - (y (- bottom-y cell-height)) + (bottom-y (+ top cell-height)) (draw-width (if clip surface-width (min surface-width cell-width))) (draw-height (min surface-height cell-height))) (when (member phase '(:bg :both)) (cond ((and attribute (lem-core:cursor-attribute-p attribute)) - (lem-sdl2/view:set-cursor-position view x y) - (draw-cursor display x y cell-width cell-height background)) + (lem-sdl2/view:set-cursor-position view x top) + (draw-cursor display x top cell-width cell-height background)) (t - (draw-rect display x y cell-width cell-height background)))) + (draw-rect display x top cell-width cell-height background)))) (when (member phase '(:glyph :both)) (let ((texture (lem-sdl2/text-surface-cache:get-or-create-texture (display:display-renderer display) @@ -173,7 +178,7 @@ is not erased by the next glyph's background fill." :dest-rect dst-rect :flip (list :none))))) (t - (display:with-scratch-rect (dst-rect display x y draw-width draw-height) + (display:with-scratch-rect (dst-rect display x top draw-width draw-height) (sdl2:render-copy-ex (display:display-renderer display) texture :source-rect nil @@ -184,9 +189,9 @@ is not erased by the next glyph's background fill." (lem:attribute-underline attribute)) (display:render-line display x - (1- (+ y cell-height)) + (1- bottom-y) (+ x cell-width) - (1- (+ y cell-height)) + (1- bottom-y) :color (let ((underline (lem:attribute-underline attribute))) (if (eq underline t) (lem-core:attribute-foreground-color attribute) @@ -203,14 +208,14 @@ widths, for the multi-character text run DRAWING-OBJECT." :collect (object-width letter) :into widths :finally (return (values letters widths))))) -(defun draw-text-object-phase (drawing-object x bottom-y display view phase) +(defun draw-text-object-phase (drawing-object x top display view phase) "Render the text-object DRAWING-OBJECT for one of the two-pass phases (:BG or :GLYPH). PHASE :BG paints backgrounds, cursors and underlines for every cell of the run; PHASE :GLYPH blits each glyph at its natural surface width so the rasterizer's right-edge anti-aliasing tail is preserved." (let ((string (text-object-string drawing-object))) (cond ((<= (length string) 1) - (draw-text-glyph-surface drawing-object x bottom-y display view + (draw-text-glyph-surface drawing-object x top display view (object-width drawing-object) :clip t :phase phase)) (t @@ -219,12 +224,12 @@ width so the rasterizer's right-edge anti-aliasing tail is preserved." (loop :with current-x := x :for letter-object :in letter-objects :for letter-width :in letter-widths - :do (draw-text-glyph-surface letter-object current-x bottom-y + :do (draw-text-glyph-surface letter-object current-x top display view letter-width :clip t :phase phase) (incf current-x letter-width))))))) -(defmethod draw-object ((drawing-object text-object) x bottom-y display view) +(defmethod draw-object ((drawing-object text-object) x top display view) ;; Render each character individually on the cell grid. SDL_ttf's blended ;; surface for a multi-character string has metrics that do not equal the ;; sum of its per-character metrics, so a glyph would otherwise land on a @@ -235,74 +240,62 @@ width so the rasterizer's right-edge anti-aliasing tail is preserved." ;; ;; This per-text-object two-pass preserves the AA overhang within the run. ;; The cross-text-object equivalent (an adjacent text-object's :bg erasing - ;; the previous text-object's AA tail) is handled by `redraw-physical-line', - ;; which lifts the two-pass to span the entire physical line. + ;; the previous text-object's AA tail) is handled by `draw-row-objects', + ;; which lifts the two-pass to span the entire row. (let ((total-width (object-width drawing-object))) - (draw-text-object-phase drawing-object x bottom-y display view :bg) - (draw-text-object-phase drawing-object x bottom-y display view :glyph) + (draw-text-object-phase drawing-object x top display view :bg) + (draw-text-object-phase drawing-object x top display view :glyph) total-width)) -(defmethod draw-object ((drawing-object icon-object) x bottom-y display view) +(defmethod draw-object ((drawing-object icon-object) x top display view) ;; Icon font glyphs typically render much wider than the 2-cell column the ;; layout reserves for them; draw-text-glyph-surface scales them down to fit. (let ((cell-width (object-width drawing-object))) - (draw-text-glyph-surface drawing-object x bottom-y display view cell-width) + (draw-text-glyph-surface drawing-object x top display view cell-width) cell-width)) -(defmethod draw-object ((drawing-object folder-object) x bottom-y display view) +(defmethod draw-object ((drawing-object folder-object) x top display view) ;; Folder PNG surface is much wider than 2 cells; render once and scale to fit. ;; Overrides the text-object per-character loop so the icon stays atomic. (let ((cell-width (object-width drawing-object))) - (draw-text-glyph-surface drawing-object x bottom-y display view cell-width) + (draw-text-glyph-surface drawing-object x top display view cell-width) cell-width)) -(defmethod draw-object ((drawing-object emoji-object) x bottom-y display view) +(defmethod draw-object ((drawing-object emoji-object) x top display view) ;; Emoji strings may span multiple codepoints (base + variation selector, ;; ZWJ sequences, ...) that must be rendered as one composed glyph. Use the ;; single-surface path with cell-aligned scaling so we neither split the ;; sequence per-codepoint nor let an oversized emoji surface spill over. (let ((cell-width (object-width drawing-object))) - (draw-text-glyph-surface drawing-object x bottom-y display view cell-width) + (draw-text-glyph-surface drawing-object x top display view cell-width) cell-width)) -(defmethod draw-object ((drawing-object eol-cursor-object) x bottom-y display view) +(defmethod draw-object ((drawing-object eol-cursor-object) x top display view) (display:set-render-color display (eol-cursor-object-color drawing-object)) - (let ((y (- bottom-y (object-height drawing-object)))) - (lem-sdl2/view:set-cursor-position view x y) - (draw-cursor display - x - y - (display:display-char-width display) - (object-height drawing-object) - (eol-cursor-object-color drawing-object))) + (lem-sdl2/view:set-cursor-position view x top) + (draw-cursor display + x + top + (display:display-char-width display) + (object-height drawing-object) + (eol-cursor-object-color drawing-object)) (object-width drawing-object)) -(defmethod draw-object ((drawing-object extend-to-eol-object) x bottom-y display view) - (display:set-render-color display (extend-to-eol-object-color drawing-object)) - (display:with-scratch-rect (rect display - x - (- bottom-y (display:display-char-height display)) - (- (lem-if:view-width (lem-core:implementation) view) x) - (display:display-char-height display)) - (sdl2:render-fill-rect (display:display-renderer display) rect)) - (object-width drawing-object)) - -(defmethod draw-object ((drawing-object line-end-object) x bottom-y display view) +(defmethod draw-object ((drawing-object line-end-object) x top display view) (call-next-method drawing-object (+ x (* (line-end-object-offset drawing-object) (display:display-char-width display))) - bottom-y + top display view)) -(defmethod draw-object ((drawing-object image-object) x bottom-y display view) +(defmethod draw-object ((drawing-object image-object) x top display view) (let* ((surface-width (object-width drawing-object)) (surface-height (object-height drawing-object)) (texture (sdl2:create-texture-from-surface (display:display-renderer display) - (image-object-image drawing-object))) - (y (- bottom-y surface-height))) - (display:with-scratch-rect (dest-rect display x y surface-width surface-height) + (image-object-image drawing-object)))) + (display:with-scratch-rect (dest-rect display x top surface-width surface-height) (sdl2:render-copy-ex (display:display-renderer display) texture :source-rect nil @@ -318,93 +311,85 @@ one of its specialised subclasses `icon-object', `folder-object', or rather than the row-wide two-pass)." (eq (class-of object) (find-class 'text-object))) -(defun redraw-physical-line (display view x y objects height) - ;; Two-pass over the whole physical line: paint every plain text-object's - ;; backgrounds first, then blit every plain text-object's glyphs. This - ;; preserves the 1-pixel right-edge AA tail at attribute boundaries (e.g. - ;; on the dashboard's highlighted row, where a `p' or `g' at the end of - ;; one attribute run would otherwise be eroded by the next text-object's +(defun draw-row-objects (display view row) + ;; Two-pass over the whole row: paint every plain text-object's backgrounds + ;; first, then blit every plain text-object's glyphs. This preserves the + ;; 1-pixel right-edge AA tail at attribute boundaries (e.g. on the + ;; dashboard's highlighted row, where a `p' or `g' at the end of one + ;; attribute run would otherwise be eroded by the next text-object's ;; full-width background fill). Everything else (icon / folder / emoji - ;; text-object subclasses, images, eol-cursor, extend-to-eol) draws fully - ;; in the first pass via its own `draw-object' method — those don't have - ;; AA overhang to preserve and need their bespoke rendering (scale-to-fit - ;; for icon/folder/emoji surfaces, fill for extend-to-eol, etc.). - (let* ((bottom-y (+ y height)) - (display-width (round (* (display:display-window-width display) + ;; text-object subclasses, images, eol-cursor) draws fully in the first pass + ;; via its own `draw-object' method — those don't have AA overhang to + ;; preserve and need their bespoke rendering (scale-to-fit for + ;; icon/folder/emoji surfaces, etc.). + (let* ((display-width (round (* (display:display-window-width display) (first (display:display-scale display))))) - (placed (loop :with current-x := x - :for object :in objects - :while (< current-x display-width) - :collect (cons object current-x) - :do (incf current-x (object-width object))))) - (flet ((draw-text-pass (object obj-x phase) - ;; Honour the wrap-to-letters branch the old code used when a - ;; text-object would extend past the display width. - (cond ((< display-width - (+ obj-x (object-width object))) - (loop :with current-x := obj-x - :for c :across (text-object-string object) - :while (< current-x display-width) - :for letter := (make-letter-object - c (text-object-attribute object)) - :for letter-width := (object-width letter) - :do (draw-text-glyph-surface letter current-x bottom-y - display view letter-width - :clip t :phase phase) - (incf current-x letter-width))) - (t - (draw-text-object-phase object obj-x bottom-y - display view phase))))) + (placements (remove-if (lambda (placement) + (<= display-width (placement-x placement))) + (row-placements row)))) + (flet ((draw-text-pass (placement phase) + (let* ((object (placement-object placement)) + (x (placement-x placement)) + (top (placement-top placement))) + (cond ((< display-width (+ x (object-width object))) + ;; a run reaching past the edge is drawn letter by letter, as far as it fits. + (loop :with current-x := x + :for c :across (text-object-string object) + :while (< current-x display-width) + :for letter := (make-letter-object + c (text-object-attribute object)) + :for letter-width := (object-width letter) + :do (draw-text-glyph-surface letter current-x top + display view letter-width + :clip t :phase phase) + (incf current-x letter-width))) + (t + (draw-text-object-phase object x top display view phase)))))) ;; Pass 1: plain-text backgrounds + everything else (subclassed text- ;; objects and non-text objects) in normal order. - (loop :for (object . obj-x) :in placed - :do (if (plain-text-object-p object) - (draw-text-pass object obj-x :bg) - (draw-object object obj-x bottom-y display view))) + (loop :for placement :in placements + :do (if (plain-text-object-p (placement-object placement)) + (draw-text-pass placement :bg) + (draw-object (placement-object placement) + (placement-x placement) + (placement-top placement) + display + view))) ;; Pass 2: plain-text glyphs. - (loop :for (object . obj-x) :in placed - :when (plain-text-object-p object) - :do (draw-text-pass object obj-x :glyph))))) - -(defun redraw-physical-line-from-behind (display view objects) - (loop :with current-x := (lem-if:view-width (lem-core:implementation) view) - :and y := (lem-if:view-height (lem-core:implementation) view) - :for object :in objects - :do (decf current-x (object-width object)) - (draw-object object current-x y display view))) - -(defun fill-to-end-of-line (display view x y height &optional default-attribute) - (display:with-scratch-rect (rect display x y (- (lem-if:view-width (lem-core:implementation) view) x) height) - (display:set-render-color display - (lem-core:attribute-background-color default-attribute)) + (loop :for placement :in placements + :when (plain-text-object-p (placement-object placement)) + :do (draw-text-pass placement :glyph))))) + +(defun fill-row (display view row x color) + "Paint COLOR from X to the right edge of VIEW, over ROW's full height." + (display:with-scratch-rect (rect display + x + (row-top row) + (- (lem-if:view-width (lem-core:implementation) view) x) + (row-height row)) + (display:set-render-color display color) (sdl2:render-fill-rect (display:display-renderer display) rect))) -(defmethod lem-if:render-line ((implementation lem-sdl2/sdl2:sdl2) view x y objects height) +(defun draw-row (display view row background) + "Blank ROW to BACKGROUND, paint whatever fill it carries, then draw everything placed on it. +Both fills cover the row's full height, which may exceed a single text line's height when a +tall object (e.g. an image) sits on the row." + (fill-row display view row 0 background) + (when (row-fill-color row) + (fill-row display view row (row-fill-x row) (row-fill-color row))) + (draw-row-objects display view row)) + +(defmethod lem-if:render-row ((implementation lem-sdl2/sdl2:sdl2) view row) (display:with-display (display) - (fill-to-end-of-line display view x y height) - (redraw-physical-line display view x y objects height))) - -(defmethod lem-if:render-line-on-modeline ((implementation lem-sdl2/sdl2:sdl2) - view - left-objects - right-objects - default-attribute - height) + (draw-row display view row (lem-core:attribute-background-color nil)))) + +(defmethod lem-if:render-modeline-row ((implementation lem-sdl2/sdl2:sdl2) view row + default-attribute) (display:with-display (display) - (fill-to-end-of-line display - view - 0 - (- (lem-if:view-height (lem-core:implementation) view) height) - height - default-attribute) - (redraw-physical-line display - view - 0 - (- (lem-if:view-height (lem-core:implementation) view) - (display:display-char-height display)) - left-objects - height) - (redraw-physical-line-from-behind display view right-objects))) + (draw-row display + view + (translate-row row (- (lem-if:view-height implementation view) (row-height row))) + (lem-core:attribute-background-color default-attribute)))) (defmethod lem-if:clear-to-end-of-window ((implementation lem-sdl2/sdl2:sdl2) view y) (display:with-display (display) diff --git a/frontends/sdl2/main.lisp b/frontends/sdl2/main.lisp index 278c0a60b..d218d664c 100644 --- a/frontends/sdl2/main.lisp +++ b/frontends/sdl2/main.lisp @@ -478,6 +478,12 @@ (display:with-display (display) (display:display-char-height display))) +(defmethod lem-if:cell-pixel-size ((implementation sdl2)) + (display:with-display (display) + (values (display:display-char-width display) + (display:display-char-height display) + (display:display-font-ascent display)))) + (defmethod lem-if:view-width ((implementation sdl2) view) (display:with-display (display) (* (display:display-char-width display) diff --git a/frontends/server/main.lisp b/frontends/server/main.lisp index 280041817..0165dad06 100644 --- a/frontends/server/main.lisp +++ b/frontends/server/main.lisp @@ -612,8 +612,8 @@ the same immutable instance for every subsequent message." (defgeneric object-height (drawing-object) (:documentation "height of DRAWING-OBJECT in character cells. -we advance the vertical position of the next line by the tallest object's height (see -`max-height-of-objects'), so returning more than 1 for an image makes its line grow to fit.")) +`lem-core/display:layout-row' grows the row to fit everything on it, so returning more than 1 for +an image gives it the cells it needs.")) (defmethod object-height (drawing-object) 1) @@ -724,17 +724,6 @@ same hash." (lem-core:set-cursor-attribute attr) (put jsonrpc view x y " " attr :text-width 1))) -(defmethod draw-object (jsonrpc (object display:extend-to-eol-object) x y view) - (let ((width (lem-if:view-width (lem-core:implementation) view))) - (when (< x width) - (let ((fill-width (- width x))) - (put jsonrpc view x y - (make-string fill-width :initial-element #\space) - (lem:make-attribute - :background - (lem:color-to-hex-string (display:extend-to-eol-object-color object))) - :text-width fill-width))))) - (defmethod draw-object (jsonrpc (object display:line-end-object) x y view) (let ((string (display:text-object-string object)) (attribute (display:text-object-attribute object)) @@ -784,43 +773,55 @@ a string already carrying a data:/https: URL is passed through unchanged." "pixelHeight" ph "url" url))))))) -(defun render-line (jsonrpc view x y objects) - (loop :for object :in objects - :do (draw-object jsonrpc object x y view) - (incf x (object-width object)))) - -(defun render-line-from-behind (jsonrpc view y objects) - (loop :with current-x := (view-width view) - :for object :in objects - :do (decf current-x (object-width object)) - (draw-object jsonrpc object current-x y view))) - -(defmethod lem-if:render-line ((jsonrpc jsonrpc) view x y objects height) +(defun draw-row (jsonrpc view row) + "draw ROW's background fill, then everything placed on it. +`clear-eol'/`clear-eob' only ever paint the editor's plain background, so a fill in an arbitrary +color (e.g. a highlighted row) goes out as spaces carrying that color via `put'." + (let ((width (view-width view))) + (when (and (display:row-fill-color row) + (< (display:row-fill-x row) width)) + (let ((fill-width (- width (display:row-fill-x row)))) + (put jsonrpc + view + (display:row-fill-x row) + (display:row-top row) + (make-string fill-width :initial-element #\space) + (lem:make-attribute + :background + (lem:color-to-hex-string (display:row-fill-color row))) + :text-width fill-width)))) + (loop :for placement :in (display:row-placements row) + :do (draw-object jsonrpc + (display:placement-object placement) + (display:placement-x placement) + (display:placement-top placement) + view))) + +(defmethod lem-if:render-row ((jsonrpc jsonrpc) view row) (with-error-handler () - ;; clear the line's full height (not just one row) since a tall object such as an image may - ;; occupy several rows. + ;; clear the row's full height (not just one line of text) since a tall object such as an image + ;; may occupy several. (notify* jsonrpc "clear-eol" (hash "viewInfo" (view-id-hash view) - "x" x - "y" y - "height" height)) - (render-line jsonrpc view x y objects))) + "x" 0 + "y" (display:row-top row) + "height" (display:row-height row))) + (draw-row jsonrpc view row))) -(defmethod lem-if:render-line-on-modeline ((jsonrpc jsonrpc) view left-objects right-objects - default-attribute height) +(defmethod lem-if:render-modeline-row ((jsonrpc jsonrpc) view row default-attribute) + ;; the modeline has a surface of its own here, so the row is drawn where it was laid out. (let ((*put-target* :modeline)) (with-error-handler () (notify* jsonrpc "modeline-put" (hash "viewInfo" (view-id-hash view) "x" 0 - "y" 0 + "y" (display:row-top row) "text" (make-string (view-width view) :initial-element #\space) "textWidth" (view-width view) "attribute" (attribute-to-hash default-attribute))) - (render-line jsonrpc view 0 0 left-objects) - (render-line-from-behind jsonrpc view 0 right-objects)))) + (draw-row jsonrpc view row)))) (defmethod lem-if:object-width ((jsonrpc jsonrpc) drawing-object) (object-width drawing-object)) diff --git a/src/color-theme.lisp b/src/color-theme.lisp index 760301ecc..b97c69fd4 100644 --- a/src/color-theme.lisp +++ b/src/color-theme.lisp @@ -101,7 +101,7 @@ for example, to maintain an attribute like CURSOR.") ;; The per-window drawing-cache compares attributes via ensure-attribute, ;; which resolves to the *current* theme on both sides — so after a color ;; change the cache silently treats every line as unchanged and skips - ;; render-line. With :no-force-needed implementations (e.g. webview), + ;; render-row. With :no-force-needed implementations (e.g. webview), ;; (redraw-display :force t) above also strips force, so non-current ;; windows never invalidate their cache. Mark every window dirty so ;; clear-cache-if-screen-modified drops the stale cache. diff --git a/src/display/physical-line.lisp b/src/display/physical-line.lisp index 75de4b114..252d0bd9d 100644 --- a/src/display/physical-line.lisp +++ b/src/display/physical-line.lisp @@ -98,6 +98,14 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." (defmethod lem-if:object-height (implementation (drawing-object image-object)) (image-draw-height implementation drawing-object)) +(defmethod lem-if:object-ascent (implementation (drawing-object drawing-object)) + ;; anything drawn in the editor's font shares that font's baseline, the cell ascent, when the + ;; frontend reports one. + (multiple-value-bind (cell-width cell-height cell-ascent) + (lem-if:cell-pixel-size implementation) + (declare (ignore cell-width cell-height)) + (or cell-ascent (lem-if:object-height implementation drawing-object)))) + (defmethod cursor-object-p (drawing-object) nil) @@ -220,6 +228,9 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." (defun object-height (drawing-object) (lem-if:object-height (implementation) drawing-object)) +(defun object-ascent (drawing-object) + (lem-if:object-ascent (implementation) drawing-object)) + (defun split-string-by-character-type (string) (loop :with pos := 0 :and items := '() :while (< pos (length string)) @@ -361,8 +372,8 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." (push object physical-line-objects))) :finally (return (nreverse physical-line-objects)))))) -(defun render-line (view x y objects height) - (lem-if:render-line (implementation) view x y objects height)) +(defun render-row (view row) + (lem-if:render-row (implementation) view row)) (defun reduce-list (list &key (test (alexandria:required-argument :test)) @@ -440,23 +451,128 @@ leaving the row blank on persistent-texture frontends such as SDL2." (remove-drawing-cache-entries-from (drawing-cache window) y))) (defun update-and-validate-cache-p (window y height objects) - "Check cache validity, reducing objects once before storing. + "Check cache validity for the already-reduced OBJECTS, storing them when they differ. Returns T if the cached entry matches (render can be skipped)." - (let ((reduced (reduce-objects objects))) - (cond ((validate-cache-p window y height reduced) t) - (t - (invalidate-cache window y height) - (push (list y height reduced) - (drawing-cache window)) - nil)))) - -(defun render-line-with-caching (window x y objects height) - (unless (update-and-validate-cache-p window y height objects) - (render-line (window-view window) x y objects height))) - -(defun max-height-of-objects (objects) - (loop :for object :in objects - :maximize (object-height object))) + (cond ((validate-cache-p window y height objects) t) + (t + (invalidate-cache window y height) + (push (list y height objects) + (drawing-cache window)) + nil))) + +(defun render-row-with-caching (window y objects) + "Lay OBJECTS out as one screen row of WINDOW at Y and draw it, unless it is already on screen." + (let* ((reduced (reduce-objects objects)) + (row (layout-row y reduced))) + (unless (update-and-validate-cache-p window y (row-height row) reduced) + (render-row (window-view window) row)) + (row-height row))) + +(defun text-row-metrics () + "The ascent and height of a row holding nothing but text, as (values ASCENT HEIGHT). +A frontend that does not report a baseline is taken to put it at the bottom of the row." + (multiple-value-bind (cell-width cell-height cell-ascent) + (lem-if:cell-pixel-size (implementation)) + (declare (ignore cell-width)) + (let ((height (or cell-height (lem-if:cell-height (implementation))))) + (values (or cell-ascent height) height)))) + +(defun row-metrics-of-objects (&rest object-lists) + "The ascent and height a row of all the objects in OBJECT-LISTS needs, as (values ASCENT HEIGHT). +Everything shares one baseline, so the height is max ascent plus max descent, which can exceed any +single object's own height: an object with a tall ascent and short descent and one with a short +ascent and tall descent can each set one half of the row independently, so the row ends up taller +than either. An empty row is still one row of text tall. +The returned ASCENT is also the baseline's offset from the row's top, since the baseline sits +exactly ASCENT below it. `layout-row' uses it that way to hang everything on the row from it." + (multiple-value-bind (ascent height) (text-row-metrics) + (let ((descent (- height ascent))) + (dolist (objects object-lists) + (dolist (object objects) + (let ((object-ascent (object-ascent object))) + (setf ascent (max ascent object-ascent)) + (setf descent (max descent (- (object-height object) object-ascent)))))) + (values ascent (+ ascent descent))))) + +(defstruct (placement (:constructor make-placement (object x top))) + "Where one drawing object goes, top-left corner at (X, TOP), in the frontend's units. +TOP is the row's baseline minus this object's ascent, so objects of different heights hang from one +baseline instead of sharing a top edge." + object + x + top) + +(defstruct row + "One screen row, laid out by `layout-row' and ready for a frontend to draw. +TOP/HEIGHT already account for every object on the row, including one taller than a line of text. +A frontend should size the row from these fields rather than re-deriving its extent from any +single object's own height." + top + height + ;; needed by a frontend that draws a text-object letter by letter, to put each letter on it. + baseline + ;; where each object goes, its own x and top. + placements + ;; from an `extend-to-eol-object', if the row holds one. A frontend paints FILL-COLOR first, + ;; before any of the row's objects, over the rectangle from FILL-X to the right edge and down + ;; the row's full height. NIL FILL-COLOR means nothing to paint. + fill-x + fill-color) + +(defun layout-row (top objects + &key + right-objects + (right-edge (and right-objects + (alexandria:required-argument :right-edge)))) + "Lay OBJECTS out as one screen row with its top edge at TOP, as a `row'. +RIGHT-OBJECTS are laid out leftwards from RIGHT-EDGE instead, for a row drawn from both ends (the +modeline), so the left- and right-aligned objects share one baseline. Everything, including an +image, is positioned by its own ascent measured from that one shared baseline (see +`image-object-ascent'), so it stays correctly placed relative to the text beside it however tall +the row is. +An `extend-to-eol-object' is not placed. It draws nothing of its own and colors the row's full +height, so it becomes ROW-FILL-X and ROW-FILL-COLOR." + (multiple-value-bind (ascent height) (row-metrics-of-objects objects right-objects) + (let ((baseline (+ top ascent)) + (placements) + (fill-x) + (fill-color)) + (flet ((place (object x) + (if (typep object 'extend-to-eol-object) + ;; only the first can show, it colors everything from its x rightwards. + (unless fill-color + (setf fill-x x + fill-color (extend-to-eol-object-color object))) + (push (make-placement object x (- baseline (object-ascent object))) + placements)))) + (loop :with x := 0 + :for object :in objects + :do (place object x) + (incf x (object-width object))) + (loop :with x := right-edge + :for object :in right-objects + :do (decf x (object-width object)) + (place object x))) + (make-row :top top + :height height + :baseline baseline + :placements (nreverse placements) + :fill-x fill-x + :fill-color fill-color)))) + +(defun translate-row (row dy) + "A copy of ROW moved DY down the view. +For a frontend that draws a row elsewhere than where it was laid out, a modeline drawn into the +bottom of the window's view rather than onto a surface of its own." + (let ((moved (copy-row row))) + (setf (row-top moved) (+ (row-top row) dy) + (row-baseline moved) (+ (row-baseline row) dy) + (row-placements moved) + (loop :for placement :in (row-placements row) + :collect (make-placement (placement-object placement) + (placement-x placement) + (+ (placement-top placement) dy)))) + moved)) ;;; Line fingerprint cache — avoids creating drawing objects for unchanged lines @@ -615,8 +731,7 @@ over the top-level spine and tolerant of improper (dotted) lists." (loop (unless objects (return)) (let* ((all-objects (append left-side-objects objects)) - (height (max-height-of-objects all-objects))) - (render-line-with-caching window 0 y all-objects height) + (height (render-row-with-caching window y all-objects))) (incf y height) (setq left-side-objects wrapped-left-side-objects) (incf total-height height) @@ -709,10 +824,8 @@ creating zero temporary letter-objects." ;; Early exit if line content unchanged (alexandria:when-let ((cached-height (check-line-fingerprint window y fingerprint))) (return-from redraw-logical-line-when-horizontal-scroll cached-height)) - (let* ((objects (create-drawing-objects logical-line)) - (height - (max (max-height-of-objects left-side-objects) - (max-height-of-objects objects)))) + (let ((objects (create-drawing-objects logical-line)) + (height 0)) (multiple-value-bind (cursor-object cursor-x) (find-cursor-object objects) (when cursor-object @@ -726,13 +839,13 @@ creating zero temporary letter-objects." (+ (- cursor-x width) (object-width cursor-object))))))) (setf objects - (reduce-objects - (clip-objects-to-display-range - objects - (horizontal-scroll-start window) - (+ (horizontal-scroll-start window) - (window-view-width window))))) - (render-line-with-caching window 0 y (append left-side-objects objects) height)) + (clip-objects-to-display-range + objects + (horizontal-scroll-start window) + (+ (horizontal-scroll-start window) + (window-view-width window)))) + (setf height + (render-row-with-caching window y (append left-side-objects objects)))) ;; Reuse fingerprint if scroll position didn't change; avoids redundant sxhash (update-line-fingerprint window y @@ -819,13 +932,16 @@ creating zero temporary letter-objects." 'modeline-inactive)))) (multiple-value-bind (left-objects right-objects) (make-modeline-objects window default-attribute) - (lem-if:render-line-on-modeline (implementation) - view - left-objects - right-objects - default-attribute - (max (max-height-of-objects left-objects) - (max-height-of-objects right-objects))))))) + ;; top 0: only the frontend knows where the modeline actually goes on screen. see + ;; `lem-if:render-modeline-row'. + (lem-if:render-modeline-row (implementation) + view + (layout-row 0 + left-objects + :right-objects right-objects + :right-edge (lem-if:view-width (implementation) + view)) + default-attribute))))) (defun get-background-color-of-window (window) (cond ((typep window 'floating-window) diff --git a/src/interface.lisp b/src/interface.lisp index 64b25d868..9be5c1305 100644 --- a/src/interface.lisp +++ b/src/interface.lisp @@ -184,15 +184,30 @@ the units `object-width' / `object-height' are counted in.")) (:documentation "Height of one character cell in the frontend's native layout units. Unit-relative like `cell-width'.")) -(defgeneric lem-if:render-line (implementation view x y objects height)) -(defgeneric lem-if:render-line-on-modeline (implementation view left-objects right-objects - default-attribute height)) +(defgeneric lem-if:cell-pixel-size (implementation) + (:documentation "One character cell in real pixels, as (values WIDTH HEIGHT ASCENT). +ASCENT is how far below the cell's top the text baseline sits, and may be NIL on its own. +All three are NIL on a frontend that does not draw in pixels. +Always pixels, unlike `cell-width' / `cell-height', which are 1 on a cell-based frontend.") + (:method (implementation) + (values nil nil nil))) + +(defgeneric lem-if:render-row (implementation view row) + (:documentation "Draw ROW, one screen row of VIEW, replacing whatever it held before. +ROW is a `lem-core/display:row'. Its height, background and the position of every object on it were +decided by `lem-core/display:layout-row', so a frontend only paints. +Blank the row's full width, `row-top' down by ROW-HEIGHT, first.")) + +(defgeneric lem-if:render-modeline-row (implementation view row default-attribute) + (:documentation "Draw ROW as VIEW's modeline, filled with DEFAULT-ATTRIBUTE's background. +Like `render-row', except ROW was laid out with its top at Y 0, since only the frontend knows +where on screen its modeline goes. One that draws it into the view moves it with +`lem-core/display:translate-row'.")) + (defgeneric lem-if:object-width (implementation drawing-object) (:documentation "Width DRAWING-OBJECT occupies, in the same units as `cell-width'. -The default methods in src/display/physical-line.lisp derive this from `cell-width'. A -`lem-core/display:text-object' (one run of characters sharing an attribute) is as wide as its -string: `string-width' cells, counting a wide glyph as two. An image takes the pixel width it is -drawn at (`lem-core/display:image-draw-width'). +Defaults in src/display/physical-line.lisp: a text-object is `string-width' cells, counting a wide +glyph as two, an image its `lem-core/display:image-draw-width'. Specialize this only for an object the frontend draws at some other size, as sdl2 does for its folder and emoji glyphs.")) @@ -201,12 +216,19 @@ folder and emoji glyphs.")) Defaults to one cell for every object but an image, which takes the pixel height it is drawn at (`lem-core/display:image-draw-height'). Specialize it as in `object-width'.")) +(defgeneric lem-if:object-ascent (implementation drawing-object) + (:documentation "How much of DRAWING-OBJECT sits above the text baseline, in the same units as +`cell-height'. +Everything on a row shares one baseline, so a row is as tall as the furthest anything reaches above +it plus the furthest anything reaches below, which can exceed the tallest single object. +Defaults to the cell ascent a frontend reports through `cell-pixel-size', or the object's bottom +when it reports none, so one that does not know its baseline keeps its old layout exactly.")) + (defgeneric lem-if:image-natural-size (implementation image) (:documentation "Fallback size for an image whose object requests no particular size. Returns (values WIDTH HEIGHT) in pixels, or NIL NIL if the frontend can't tell. IMAGE is the -frontend's own loaded-image handle (an SDL surface, a path handed to a browser, ...), the value -stored in an `lem-core/display:image-object' and obtained via `image-object-image'. See -`lem-core/display:image-draw-width'.") +frontend's own loaded-image handle (an SDL surface, a path handed to a browser, ...), not the +`lem-core/display:image-object' holding it.") (:method (implementation image) (values nil nil))) (defgeneric lem-if:clear-to-end-of-window (implementation view y)) diff --git a/src/internal-packages.lisp b/src/internal-packages.lisp index a87300bef..95d4e7960 100644 --- a/src/internal-packages.lisp +++ b/src/internal-packages.lisp @@ -20,8 +20,23 @@ :image-object-width :image-draw-width :image-draw-height + :object-ascent :object-height :object-width + :row-metrics-of-objects + :layout-row + :translate-row + :row + :row-top + :row-height + :row-baseline + :row-placements + :row-fill-x + :row-fill-color + :placement + :placement-object + :placement-x + :placement-top :line-end-object :line-end-object-offset :text-object @@ -828,9 +843,11 @@ :cell-height :clear-to-end-of-window :js-eval - :render-line - :render-line-on-modeline + :cell-pixel-size + :render-row + :render-modeline-row :object-width :object-height + :object-ascent :image-natural-size :set-frame-color)) From fa9d48ebf8e9aab3765038f070dcf291f7f21208 Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Sat, 1 Aug 2026 11:52:37 +0300 Subject: [PATCH 07/18] draw the webview frontend in pixels cell-width/cell-height report the client's real font metrics instead of 1, so every coordinate the server sends is a pixel. the client sends its metrics with every redraw, so a font change re-lays out the display the way a resize does. --- .../server/frontend/dist/assets/index.js | 2 +- frontends/server/frontend/editor.js | 302 +++++++++--------- frontends/server/main.lisp | 196 +++++------- frontends/server/view.lisp | 60 +++- 4 files changed, 283 insertions(+), 277 deletions(-) diff --git a/frontends/server/frontend/dist/assets/index.js b/frontends/server/frontend/dist/assets/index.js index 1cc125100..136c84167 100644 --- a/frontends/server/frontend/dist/assets/index.js +++ b/frontends/server/frontend/dist/assets/index.js @@ -1 +1 @@ -var __defProp=Object.defineProperty,__commonJSMin=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),__exportAll=(e,t)=>{let n={};for(var r in e)__defProp(n,r,{get:e[r],enumerable:!0});return t||__defProp(n,Symbol.toStringTag,{value:`Module`}),n};(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var require_models=__commonJSMin((e=>{var t=e&&e.__extends||(function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};return function(t,n){if(typeof n!=`function`&&n!==null)throw TypeError(`Class extends value `+String(n)+` is not a constructor or null`);e(t,n);function r(){this.constructor=t}t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}})();Object.defineProperty(e,"__esModule",{value:!0}),e.createJSONRPCNotification=e.createJSONRPCRequest=e.createJSONRPCSuccessResponse=e.createJSONRPCErrorResponse=e.JSONRPCErrorCode=e.JSONRPCErrorException=e.isJSONRPCResponses=e.isJSONRPCResponse=e.isJSONRPCRequests=e.isJSONRPCRequest=e.isJSONRPCID=e.JSONRPC=void 0,e.JSONRPC=`2.0`,e.isJSONRPCID=function(e){return typeof e==`string`||typeof e==`number`||e===null},e.isJSONRPCRequest=function(t){return t.jsonrpc===e.JSONRPC&&t.method!==void 0&&t.result===void 0&&t.error===void 0},e.isJSONRPCRequests=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCRequest)},e.isJSONRPCResponse=function(t){return t.jsonrpc===e.JSONRPC&&t.id!==void 0&&(t.result!==void 0||t.error!==void 0)},e.isJSONRPCResponses=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCResponse)};var n=function(e,t,n){var r={code:e,message:t};return n!=null&&(r.data=n),r};e.JSONRPCErrorException=function(e){t(r,e);function r(t,n,i){var a=e.call(this,t)||this;return Object.setPrototypeOf(a,r.prototype),a.code=n,a.data=i,a}return r.prototype.toObject=function(){return n(this.code,this.message,this.data)},r}(Error),(function(e){e[e.ParseError=-32700]=`ParseError`,e[e.InvalidRequest=-32600]=`InvalidRequest`,e[e.MethodNotFound=-32601]=`MethodNotFound`,e[e.InvalidParams=-32602]=`InvalidParams`,e[e.InternalError=-32603]=`InternalError`})(e.JSONRPCErrorCode||={}),e.createJSONRPCErrorResponse=function(t,r,i,a){return{jsonrpc:e.JSONRPC,id:t,error:n(r,i,a)}},e.createJSONRPCSuccessResponse=function(t,n){return{jsonrpc:e.JSONRPC,id:t,result:n??null}},e.createJSONRPCRequest=function(t,n,r){return{jsonrpc:e.JSONRPC,id:t,method:n,params:r}},e.createJSONRPCNotification=function(t,n){return{jsonrpc:e.JSONRPC,method:t,params:n}}})),require_internal=__commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.DefaultErrorCode=void 0,e.DefaultErrorCode=0})),require_client=__commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{Object.defineProperty(e,"__esModule",{value:!0})})),require_server=__commonJSMin((e=>{var t=e&&e.__assign||function(){return t=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__createBinding||(Object.create?(function(e,t,n,r){r===void 0&&(r=n);var i=Object.getOwnPropertyDescriptor(t,n);(!i||(`get`in i?!t.__esModule:i.writable||i.configurable))&&(i={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,i)}):(function(e,t,n,r){r===void 0&&(r=n),e[r]=t[n]})),n=e&&e.__exportStar||function(e,n){for(var r in e)r!=="default"&&!Object.prototype.hasOwnProperty.call(n,r)&&t(n,e,r)};Object.defineProperty(e,"__esModule",{value:!0}),n(require_client(),e),n(require_interfaces(),e),n(require_models(),e),n(require_server(),e),n(require_server_and_client(),e)})),import_dist=require_dist(),JSONRPC=class{constructor(e,{onConnected:t,onClosed:n}){this.url=e,this.onConnected=t,this.onClosed=n,this.messageQueue=[],this.serverAndClient=null,this.connect(),this.connectionEstablished=!1,this.timerId=null,this.closed=!1}close(){this.timerId&&clearTimeout(this.timerId),this.webSocket.close(),this.closed=!0}on(e,t){this.serverAndClient.addMethod(e,t)}async requestInternal(e,t,n){let r=await this.serverAndClient.request(e,t);n&&n(r)}requestMessageQueue(){this.messageQueue.forEach(e=>{let[t,n,r]=e;this.requestInternal(t,n,r)}),this.messageQueue=[]}request(e,t,n){this.webSocket.readyState===WebSocket.OPEN?this.requestInternal(e,t,n):this.messageQueue.push([e,t,n])}notify(e,t){switch(this.webSocket.readyState){case WebSocket.OPEN:this.serverAndClient.notify(e,t);break;case WebSocket.CLOSED:break}}connect(e){this.closed||(console.log(`connect`,this.url),this.webSocket=new WebSocket(this.url),this.serverAndClient||=new import_dist.JSONRPCServerAndClient(new import_dist.JSONRPCServer,new import_dist.JSONRPCClient(e=>{try{return this.webSocket.send(JSON.stringify(e)),Promise.resolve()}catch(e){return Promise.reject(e)}})),this.webSocket.onmessage=e=>{this.serverAndClient.receiveAndSend(JSON.parse(e.data.toString()))},this.webSocket.onopen=()=>{console.log(`WebSocket connection established`),this.connectionEstablished=!0,this.onConnected&&this.onConnected(),this.requestMessageQueue()},this.webSocket.onclose=e=>{console.error(`WebScoket closed`,e),this.serverAndClient.rejectAllPendingRequests(`Connection is closed (${e.reason}).`),this.connectionEstablished&&this.onClosed(),this.timerId=setTimeout(()=>{this.connect()},3e3)},this.webSocket.onerror=e=>{console.error(`WebSocket error:`,e),this.webSocket.close()})}},keyevent_exports=__exportAll({convertKeyEvent:()=>convertKeyEvent}),modifierKeys=[`Shift`,`Control`,`Alt`,`Meta`,`CapsLock`],convertKeyTable={Enter:`Return`,ArrowRight:`Right`,ArrowLeft:`Left`,ArrowUp:`Up`,ArrowDown:`Down`,"¡":`1`,"™":`2`,"£":`3`,"¢":`4`,"∞":`5`,"§":`6`,"¶":`7`,"•":`8`,ª:`9`,º:`0`,"–":`-`,"≠":`=`,"“":`[`,"‘":`]`,"«":`\\`,"…":`;`,æ:`'`,"≤":`,`,"≥":`.`,"÷":`/`,"⁄":`!`,"€":`@`,"‹":`#`,"›":`$`,fi:`%`,fl:`^`,"‡":`&`,"°":`*`,"·":`(`,"‚":`)`,"—":`_`,"±":`+`,"”":`{`,"’":`}`,"»":`|`,Ú:`:`,Æ:`"`,"¯":`<`,"˘":`>`,"¿":`?`,œ:`q`,"∑":`w`,"´":`e`,"®":`r`,"†":`t`,"¥":`y`,"¨":`u`,ˆ:`i`,ø:`o`,π:`p`,å:`a`,ß:`s`,"∂":`d`,ƒ:`f`,"©":`g`,"˙":`h`,"∆":`j`,"˚":`k`,"¬":`l`,Ω:`z`,"≈":`x`,ç:`c`,"√":`v`,"∫":`b`,"˜":`n`,µ:`m`,Œ:`Q`,"„":`W`,"´":`E`,"‰":`R`,ˇ:`T`,Á:`Y`,"¨":`U`,ˆ:`I`,Ø:`O`,"∏":`P`,Å:`A`,Í:`S`,Î:`D`,Ï:`F`,"˝":`G`,Ó:`H`,Ô:`J`,"":`K`,Ò:`L`,"¸":`Z`,"˛":`X`,Ç:`C`,"◊":`V`,ı:`B`,"˜":`N`,Â:`M`};function getKey(e){return e.altKey?convertKeyTable[e.key]||(e.code.startsWith(`Key`)?e.code[3].toLowerCase():null)||e.key:convertKeyTable[e.key]||e.key}function convertKeyEvent(e){return modifierKeys.indexOf(e.key)===-1?{key:getKey(e),ctrl:e.ctrlKey,meta:e.altKey,super:e.metaKey,shift:e.shiftKey}:null}var lib_exports=__exportAll({computeWidth:()=>computeWidth,eawVersion:()=>version,getEAW:()=>getEAW}),defs=[[0,31,`N`],[32,126,`Na`],[127,160,`N`],[161,161,`A`],[162,163,`Na`],[164,164,`A`],[165,166,`Na`],[167,168,`A`],[169,169,`N`],[170,170,`A`],[171,171,`N`],[172,172,`Na`],[173,174,`A`],[175,175,`Na`],[176,180,`A`],[181,181,`N`],[182,186,`A`],[187,187,`N`],[188,191,`A`],[192,197,`N`],[198,198,`A`],[199,207,`N`],[208,208,`A`],[209,214,`N`],[215,216,`A`],[217,221,`N`],[222,225,`A`],[226,229,`N`],[230,230,`A`],[231,231,`N`],[232,234,`A`],[235,235,`N`],[236,237,`A`],[238,239,`N`],[240,240,`A`],[241,241,`N`],[242,243,`A`],[244,246,`N`],[247,250,`A`],[251,251,`N`],[252,252,`A`],[253,253,`N`],[254,254,`A`],[255,256,`N`],[257,257,`A`],[258,272,`N`],[273,273,`A`],[274,274,`N`],[275,275,`A`],[276,282,`N`],[283,283,`A`],[284,293,`N`],[294,295,`A`],[296,298,`N`],[299,299,`A`],[300,304,`N`],[305,307,`A`],[308,311,`N`],[312,312,`A`],[313,318,`N`],[319,322,`A`],[323,323,`N`],[324,324,`A`],[325,327,`N`],[328,331,`A`],[332,332,`N`],[333,333,`A`],[334,337,`N`],[338,339,`A`],[340,357,`N`],[358,359,`A`],[360,362,`N`],[363,363,`A`],[364,461,`N`],[462,462,`A`],[463,463,`N`],[464,464,`A`],[465,465,`N`],[466,466,`A`],[467,467,`N`],[468,468,`A`],[469,469,`N`],[470,470,`A`],[471,471,`N`],[472,472,`A`],[473,473,`N`],[474,474,`A`],[475,475,`N`],[476,476,`A`],[477,592,`N`],[593,593,`A`],[594,608,`N`],[609,609,`A`],[610,707,`N`],[708,708,`A`],[709,710,`N`],[711,711,`A`],[712,712,`N`],[713,715,`A`],[716,716,`N`],[717,717,`A`],[718,719,`N`],[720,720,`A`],[721,727,`N`],[728,731,`A`],[732,732,`N`],[733,733,`A`],[734,734,`N`],[735,735,`A`],[736,767,`N`],[768,879,`A`],[880,912,`N`],[913,929,`A`],[930,930,`N`],[931,937,`A`],[938,944,`N`],[945,961,`A`],[962,962,`N`],[963,969,`A`],[970,1024,`N`],[1025,1025,`A`],[1026,1039,`N`],[1040,1103,`A`],[1104,1104,`N`],[1105,1105,`A`],[1106,4351,`N`],[4352,4447,`W`],[4448,8207,`N`],[8208,8208,`A`],[8209,8210,`N`],[8211,8214,`A`],[8215,8215,`N`],[8216,8217,`A`],[8218,8219,`N`],[8220,8221,`A`],[8222,8223,`N`],[8224,8226,`A`],[8227,8227,`N`],[8228,8231,`A`],[8232,8239,`N`],[8240,8240,`A`],[8241,8241,`N`],[8242,8243,`A`],[8244,8244,`N`],[8245,8245,`A`],[8246,8250,`N`],[8251,8251,`A`],[8252,8253,`N`],[8254,8254,`A`],[8255,8307,`N`],[8308,8308,`A`],[8309,8318,`N`],[8319,8319,`A`],[8320,8320,`N`],[8321,8324,`A`],[8325,8360,`N`],[8361,8361,`H`],[8362,8363,`N`],[8364,8364,`A`],[8365,8450,`N`],[8451,8451,`A`],[8452,8452,`N`],[8453,8453,`A`],[8454,8456,`N`],[8457,8457,`A`],[8458,8466,`N`],[8467,8467,`A`],[8468,8469,`N`],[8470,8470,`A`],[8471,8480,`N`],[8481,8482,`A`],[8483,8485,`N`],[8486,8486,`A`],[8487,8490,`N`],[8491,8491,`A`],[8492,8530,`N`],[8531,8532,`A`],[8533,8538,`N`],[8539,8542,`A`],[8543,8543,`N`],[8544,8555,`A`],[8556,8559,`N`],[8560,8569,`A`],[8570,8584,`N`],[8585,8585,`A`],[8586,8591,`N`],[8592,8601,`A`],[8602,8631,`N`],[8632,8633,`A`],[8634,8657,`N`],[8658,8658,`A`],[8659,8659,`N`],[8660,8660,`A`],[8661,8678,`N`],[8679,8679,`A`],[8680,8703,`N`],[8704,8704,`A`],[8705,8705,`N`],[8706,8707,`A`],[8708,8710,`N`],[8711,8712,`A`],[8713,8714,`N`],[8715,8715,`A`],[8716,8718,`N`],[8719,8719,`A`],[8720,8720,`N`],[8721,8721,`A`],[8722,8724,`N`],[8725,8725,`A`],[8726,8729,`N`],[8730,8730,`A`],[8731,8732,`N`],[8733,8736,`A`],[8737,8738,`N`],[8739,8739,`A`],[8740,8740,`N`],[8741,8741,`A`],[8742,8742,`N`],[8743,8748,`A`],[8749,8749,`N`],[8750,8750,`A`],[8751,8755,`N`],[8756,8759,`A`],[8760,8763,`N`],[8764,8765,`A`],[8766,8775,`N`],[8776,8776,`A`],[8777,8779,`N`],[8780,8780,`A`],[8781,8785,`N`],[8786,8786,`A`],[8787,8799,`N`],[8800,8801,`A`],[8802,8803,`N`],[8804,8807,`A`],[8808,8809,`N`],[8810,8811,`A`],[8812,8813,`N`],[8814,8815,`A`],[8816,8833,`N`],[8834,8835,`A`],[8836,8837,`N`],[8838,8839,`A`],[8840,8852,`N`],[8853,8853,`A`],[8854,8856,`N`],[8857,8857,`A`],[8858,8868,`N`],[8869,8869,`A`],[8870,8894,`N`],[8895,8895,`A`],[8896,8977,`N`],[8978,8978,`A`],[8979,8985,`N`],[8986,8987,`W`],[8988,9e3,`N`],[9001,9002,`W`],[9003,9192,`N`],[9193,9196,`W`],[9197,9199,`N`],[9200,9200,`W`],[9201,9202,`N`],[9203,9203,`W`],[9204,9311,`N`],[9312,9449,`A`],[9450,9450,`N`],[9451,9547,`A`],[9548,9551,`N`],[9552,9587,`A`],[9588,9599,`N`],[9600,9615,`A`],[9616,9617,`N`],[9618,9621,`A`],[9622,9631,`N`],[9632,9633,`A`],[9634,9634,`N`],[9635,9641,`A`],[9642,9649,`N`],[9650,9651,`A`],[9652,9653,`N`],[9654,9655,`A`],[9656,9659,`N`],[9660,9661,`A`],[9662,9663,`N`],[9664,9665,`A`],[9666,9669,`N`],[9670,9672,`A`],[9673,9674,`N`],[9675,9675,`A`],[9676,9677,`N`],[9678,9681,`A`],[9682,9697,`N`],[9698,9701,`A`],[9702,9710,`N`],[9711,9711,`A`],[9712,9724,`N`],[9725,9726,`W`],[9727,9732,`N`],[9733,9734,`A`],[9735,9736,`N`],[9737,9737,`A`],[9738,9741,`N`],[9742,9743,`A`],[9744,9747,`N`],[9748,9749,`W`],[9750,9755,`N`],[9756,9756,`A`],[9757,9757,`N`],[9758,9758,`A`],[9759,9791,`N`],[9792,9792,`A`],[9793,9793,`N`],[9794,9794,`A`],[9795,9799,`N`],[9800,9811,`W`],[9812,9823,`N`],[9824,9825,`A`],[9826,9826,`N`],[9827,9829,`A`],[9830,9830,`N`],[9831,9834,`A`],[9835,9835,`N`],[9836,9837,`A`],[9838,9838,`N`],[9839,9839,`A`],[9840,9854,`N`],[9855,9855,`W`],[9856,9874,`N`],[9875,9875,`W`],[9876,9885,`N`],[9886,9887,`A`],[9888,9888,`N`],[9889,9889,`W`],[9890,9897,`N`],[9898,9899,`W`],[9900,9916,`N`],[9917,9918,`W`],[9919,9919,`A`],[9920,9923,`N`],[9924,9925,`W`],[9926,9933,`A`],[9934,9934,`W`],[9935,9939,`A`],[9940,9940,`W`],[9941,9953,`A`],[9954,9954,`N`],[9955,9955,`A`],[9956,9959,`N`],[9960,9961,`A`],[9962,9962,`W`],[9963,9969,`A`],[9970,9971,`W`],[9972,9972,`A`],[9973,9973,`W`],[9974,9977,`A`],[9978,9978,`W`],[9979,9980,`A`],[9981,9981,`W`],[9982,9983,`A`],[9984,9988,`N`],[9989,9989,`W`],[9990,9993,`N`],[9994,9995,`W`],[9996,10023,`N`],[10024,10024,`W`],[10025,10044,`N`],[10045,10045,`A`],[10046,10059,`N`],[10060,10060,`W`],[10061,10061,`N`],[10062,10062,`W`],[10063,10066,`N`],[10067,10069,`W`],[10070,10070,`N`],[10071,10071,`W`],[10072,10101,`N`],[10102,10111,`A`],[10112,10132,`N`],[10133,10135,`W`],[10136,10159,`N`],[10160,10160,`W`],[10161,10174,`N`],[10175,10175,`W`],[10176,10213,`N`],[10214,10221,`Na`],[10222,10628,`N`],[10629,10630,`Na`],[10631,11034,`N`],[11035,11036,`W`],[11037,11087,`N`],[11088,11088,`W`],[11089,11092,`N`],[11093,11093,`W`],[11094,11097,`A`],[11098,11903,`N`],[11904,11929,`W`],[11930,11930,`N`],[11931,12019,`W`],[12020,12031,`N`],[12032,12245,`W`],[12246,12271,`N`],[12272,12287,`W`],[12288,12288,`F`],[12289,12350,`W`],[12351,12352,`N`],[12353,12438,`W`],[12439,12440,`N`],[12441,12543,`W`],[12544,12548,`N`],[12549,12591,`W`],[12592,12592,`N`],[12593,12686,`W`],[12687,12687,`N`],[12688,12771,`W`],[12772,12782,`N`],[12783,12830,`W`],[12831,12831,`N`],[12832,12871,`W`],[12872,12879,`A`],[12880,19903,`W`],[19904,19967,`N`],[19968,42124,`W`],[42125,42127,`N`],[42128,42182,`W`],[42183,43359,`N`],[43360,43388,`W`],[43389,44031,`N`],[44032,55203,`W`],[55204,57343,`N`],[57344,63743,`A`],[63744,64255,`W`],[64256,65023,`N`],[65024,65039,`A`],[65040,65049,`W`],[65050,65071,`N`],[65072,65106,`W`],[65107,65107,`N`],[65108,65126,`W`],[65127,65127,`N`],[65128,65131,`W`],[65132,65280,`N`],[65281,65376,`F`],[65377,65470,`H`],[65471,65473,`N`],[65474,65479,`H`],[65480,65481,`N`],[65482,65487,`H`],[65488,65489,`N`],[65490,65495,`H`],[65496,65497,`N`],[65498,65500,`H`],[65501,65503,`N`],[65504,65510,`F`],[65511,65511,`N`],[65512,65518,`H`],[65519,65532,`N`],[65533,65533,`A`],[65534,94175,`N`],[94176,94180,`W`],[94181,94191,`N`],[94192,94193,`W`],[94194,94207,`N`],[94208,100343,`W`],[100344,100351,`N`],[100352,101589,`W`],[101590,101631,`N`],[101632,101640,`W`],[101641,110575,`N`],[110576,110579,`W`],[110580,110580,`N`],[110581,110587,`W`],[110588,110588,`N`],[110589,110590,`W`],[110591,110591,`N`],[110592,110882,`W`],[110883,110897,`N`],[110898,110898,`W`],[110899,110927,`N`],[110928,110930,`W`],[110931,110932,`N`],[110933,110933,`W`],[110934,110947,`N`],[110948,110951,`W`],[110952,110959,`N`],[110960,111355,`W`],[111356,126979,`N`],[126980,126980,`W`],[126981,127182,`N`],[127183,127183,`W`],[127184,127231,`N`],[127232,127242,`A`],[127243,127247,`N`],[127248,127277,`A`],[127278,127279,`N`],[127280,127337,`A`],[127338,127343,`N`],[127344,127373,`A`],[127374,127374,`W`],[127375,127376,`A`],[127377,127386,`W`],[127387,127404,`A`],[127405,127487,`N`],[127488,127490,`W`],[127491,127503,`N`],[127504,127547,`W`],[127548,127551,`N`],[127552,127560,`W`],[127561,127567,`N`],[127568,127569,`W`],[127570,127583,`N`],[127584,127589,`W`],[127590,127743,`N`],[127744,127776,`W`],[127777,127788,`N`],[127789,127797,`W`],[127798,127798,`N`],[127799,127868,`W`],[127869,127869,`N`],[127870,127891,`W`],[127892,127903,`N`],[127904,127946,`W`],[127947,127950,`N`],[127951,127955,`W`],[127956,127967,`N`],[127968,127984,`W`],[127985,127987,`N`],[127988,127988,`W`],[127989,127991,`N`],[127992,128062,`W`],[128063,128063,`N`],[128064,128064,`W`],[128065,128065,`N`],[128066,128252,`W`],[128253,128254,`N`],[128255,128317,`W`],[128318,128330,`N`],[128331,128334,`W`],[128335,128335,`N`],[128336,128359,`W`],[128360,128377,`N`],[128378,128378,`W`],[128379,128404,`N`],[128405,128406,`W`],[128407,128419,`N`],[128420,128420,`W`],[128421,128506,`N`],[128507,128591,`W`],[128592,128639,`N`],[128640,128709,`W`],[128710,128715,`N`],[128716,128716,`W`],[128717,128719,`N`],[128720,128722,`W`],[128723,128724,`N`],[128725,128727,`W`],[128728,128731,`N`],[128732,128735,`W`],[128736,128746,`N`],[128747,128748,`W`],[128749,128755,`N`],[128756,128764,`W`],[128765,128991,`N`],[128992,129003,`W`],[129004,129007,`N`],[129008,129008,`W`],[129009,129291,`N`],[129292,129338,`W`],[129339,129339,`N`],[129340,129349,`W`],[129350,129350,`N`],[129351,129535,`W`],[129536,129647,`N`],[129648,129660,`W`],[129661,129663,`N`],[129664,129672,`W`],[129673,129679,`N`],[129680,129725,`W`],[129726,129726,`N`],[129727,129733,`W`],[129734,129741,`N`],[129742,129755,`W`],[129756,129759,`N`],[129760,129768,`W`],[129769,129775,`N`],[129776,129784,`W`],[129785,131071,`N`],[131072,196605,`W`],[196606,196607,`N`],[196608,262141,`W`],[262142,917759,`N`],[917760,917999,`A`],[918e3,983039,`N`],[983040,1048573,`A`],[1048574,1048575,`N`],[1048576,1114109,`A`],[1114110,1114111,`N`]],version=`15.1.0`;function getEAWOfCodePoint(e){let t=0,n=defs.length-1;for(;t!==n;){let r=t+(n-t>>1),[i,a,o]=defs[r];if(ea)t=r+1;else return o}return defs[t][2]}function getEAW(e,t=0){let n=e.codePointAt(t);if(n!==void 0)return getEAWOfCodePoint(n)}var defaultWidths={N:1,Na:1,W:2,F:2,H:1,A:1};function computeWidth(e,t){let n=0;for(let r of e){let e=getEAW(r);n+=t&&t[e]||defaultWidths[e]}return n}var textOffsetY=5,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function isWideChar(e){switch(getEAW(e)){case`F`:case`W`:return!0;default:return!1}}function isMacOS(){return window.navigator.userAgent.indexOf(`Mac OS X`)!==-1}function computeFontSize(e){let t=document.createElement(`canvas`).getContext(`2d`);t.font=e;let n=t.measureText(`W`);return[Math.floor(n.width),Math.round(n.fontBoundingBoxAscent+textOffsetY+(n.emHeightDescent||0))]}function drawBlock({ctx:e,x:t,y:n,width:r,height:i,style:a}){e.fillStyle=a,e.fillRect(t,n,r,i)}function drawText({ctx:e,x:t,y:n,text:r,font:i,style:a,option:o}){n+=Math.round(textOffsetY),e.fillStyle=a,e.font=i,e.textBaseline=`top`;for(let i of r)isWideChar(i)?(e.fillText(i,t,n,o.fontWidth*2),t+=o.fontWidth*2):(e.fillText(i,t,n,o.fontWidth),t+=o.fontWidth)}function drawHorizontalLine({ctx:e,x:t,y:n,width:r,style:i,lineWidth:a=1}){e.strokeStyle=i,e.lineWidth=a,e.setLineDash=[],e.beginPath(),e.moveTo(t,n),e.lineTo(t+r,n),e.stroke()}var Option=class{constructor({fontName:e,fontSize:t}){this.setFont(e,t),this.foreground=`#cccccc`,this.background=`#2d2d2d`}setFont(e,t){let n=t+`px `+e,[r,i]=computeFontSize(n);this.fontName=e,this.fontSize=t,this.fontWidth=r,this.fontHeight=i,this.font=n}};function getLemEditorElement(){return document.getElementById(`lem-editor`)}function normalizeWheelDelta(e,t,n,r){switch(n){case 0:return{dx:e/r,dy:t/r};case 2:return{dx:e*20,dy:t*20};default:return{dx:e,dy:t}}}function extractWholeLines(e,t){let n=Math.trunc(e),r=Math.trunc(t);return{scrollX:n,scrollY:r,remainderX:e-n,remainderY:t-r}}function cursorPosition(e,t){let[n,r]=t.getDisplayRectangle(),i=e.clientX-n,a=e.clientY-r;return{pixelX:i,pixelY:a,x:Math.floor(i/t.option.fontWidth),y:Math.floor(a/t.option.fontHeight)}}function makeWheelHandler(e){let t={x:0,y:0},n=!1,r={pixelX:0,pixelY:0,x:0,y:0};return i=>{i.preventDefault(),r=cursorPosition(i,e);let{dx:a,dy:o}=normalizeWheelDelta(i.deltaX,i.deltaY,i.deltaMode,e.option.fontHeight);t={x:t.x+a,y:t.y+o},n||(n=!0,requestAnimationFrame(()=>{n=!1;let{scrollX:i,scrollY:a,remainderX:o,remainderY:s}=extractWholeLines(t.x,t.y);t={x:o,y:s},(i!==0||a!==0)&&e.jsonrpc.notify(`input`,{kind:`wheel`,value:{...r,wheelX:-i,wheelY:-a}})}))}}function addMouseEventListeners({dom:e,editor:t,isDraggable:n,draggableStyle:r}){e.addEventListener(`contextmenu`,e=>{e.preventDefault()});let i=(e,n)=>{e.preventDefault();let[r,i]=t.getDisplayRectangle(),a=e.clientX-r,o=e.clientY-i,s=Math.floor(a/t.option.fontWidth),c=Math.floor(o/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:n,value:{x:s,y:c,pixelX:a,pixelY:o,button:e.button,clicks:e.detail}})};e.addEventListener(`mousedown`,e=>{n&&(document.body.style.cursor=r),t.focusHiddenInput(),i(e,`mousedown`)}),e.addEventListener(`mouseup`,e=>{n&&(document.body.style.cursor=`default`),i(e,`mouseup`)});let a=0;e.addEventListener(`mousemove`,e=>{e.preventDefault();let n=Date.now();if(n-a>50){a=n;let[r,i]=t.getDisplayRectangle(),o=e.clientX-r,s=e.clientY-i,c=Math.floor(o/t.option.fontWidth),l=Math.floor(s/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:`mousemove`,value:{x:c,y:l,pixelX:o,pixelY:s,button:e.buttons===0?null:e.buttons-1}})}}),n&&(e.addEventListener(`mouseover`,()=>{document.body.style.cursor=r}),e.addEventListener(`mouseout`,e=>{e.buttons!==1&&(document.body.style.cursor=`default`)})),e.addEventListener(`wheel`,makeWheelHandler(t))}var zIndexTable={"floating-window":200,modeline:100,"vertical-border":100,"horizontal-border":101};function zindex(e){return zIndexTable[e]||0}var borderOffsetX=5,borderOffsetY=10,BaseSurface=class{constructor({editor:e}){this.editor=e,this.mainDOM=null,this.wrapper=null}delete(){this.wrapper?getLemEditorElement().removeChild(this.wrapper):getLemEditorElement().removeChild(this.mainDOM)}setupDOM({dom:e,isFloating:t,border:n,cssClassName:r}){this.mainDOM=e,t&&n?(this.wrapper=document.createElement(`div`),r&&(this.wrapper.className=r),this.wrapper.style.position=`absolute`,this.wrapper.style.backgroundColor=this.editor.option.background,this.wrapper.style.zIndex=zindex(`floating-window`),this.wrapper.appendChild(e),getLemEditorElement().appendChild(this.wrapper)):(r&&(e.className=r),getLemEditorElement().appendChild(e))}move(e,t,n,r){let[i,a]=this.editor.getDisplayRectangle(),o=Math.floor(n==null?i+e*this.editor.option.fontWidth:i+n),s=Math.floor(r==null?a+t*this.editor.option.fontHeight:a+r);this.wrapper?(this.wrapper.style.left=o-borderOffsetX+`px`,this.wrapper.style.top=s-borderOffsetY+`px`,this.mainDOM.style.left=borderOffsetX+`px`,this.mainDOM.style.top=borderOffsetY+`px`):(this.mainDOM.style.left=o+`px`,this.mainDOM.style.top=s+`px`)}_resize(e,t,n,r){let i=window.devicePixelRatio||1,a=n??e*this.editor.option.fontWidth,o=r??t*this.editor.option.fontHeight;this.mainDOM.width=a*i,this.mainDOM.height=o*i,this.mainDOM.style.width=a+`px`,this.mainDOM.style.height=o+`px`,this.wrapper&&(this.wrapper.style.width=a+borderOffsetX*2+`px`,this.wrapper.style.height=o+borderOffsetY*2+`px`)}drawBlock(e,t,n,r,i){}drawText(e,t,n,r,i){}drawImage(e,t,n,r,i,a,o){}clearImages(e,t){}clearAllImages(){}touch(){}evalIn(code){return eval(code)}},CanvasSurface=class extends BaseSurface{constructor({editor:e,view:t,x:n,y:r,width:i,height:a,styles:o,isFloating:s,border:c,cssClassName:l}){super({editor:e});let u=this.setupCanvas(o);this.setupDOM({dom:u,isFloating:s,border:c,cssClassName:l}),this.move(n,r),this.resize(i,a),this.drawingQueue=[],addMouseEventListeners({dom:u,editor:e})}setupCanvas(e){let t=document.createElement(`canvas`);if(t.style.position=`absolute`,e)for(let n in e)t.style[n]=e[n];return t}resize(e,t,n,r){this._resize(e,t,n,r);let i=window.devicePixelRatio||1;this.mainDOM.getContext(`2d`).scale(i,i)}move(e,t,n,r){if(super.move(e,t,n,r),this.imageEls)for(let[,e]of this.imageEls)this.positionImage(e)}delete(){this.clearAllImages(),super.delete()}drawBlock(e,t,n,r,i){let a=this.editor.option;this.drawingQueue.push(function(o){drawBlock({ctx:o,x:e*a.fontWidth,y:t*a.fontHeight,width:n*a.fontWidth,height:r*a.fontHeight,style:i})})}drawText(e,t,n,r,i,a){let o=this.editor.option;this.drawingQueue.push(function(s){if(a=a?`${o.fontSize}px ${a}`:o.font,!i)drawBlock({ctx:s,x:e*o.fontWidth,y:t*o.fontHeight,width:r*o.fontWidth,height:o.fontHeight,style:o.background}),drawText({ctx:s,x:e*o.fontWidth,y:t*o.fontHeight,text:n,style:o.foreground,font:a,option:o});else{let{foreground:c,background:l,bold:u,reverse:d,underline:f,cursor:p}=i;if(c||=o.foreground,l||=o.background,d){let e=l;l=c,c=e}p&&(l=o.background);let m=e*o.fontWidth,h=t*o.fontHeight;drawBlock({ctx:s,x:m,y:h,width:r*o.fontWidth,height:o.fontHeight,style:l}),drawText({ctx:s,x:m,y:h,text:n,style:c,font:u?`bold `+a:a,option:o}),f&&drawHorizontalLine({ctx:s,x:m,y:h+o.fontHeight-2,width:r*o.fontWidth,style:typeof f==`string`?f:c,lineWidth:2})}})}imageBaseLeft(){return parseFloat(this.mainDOM.style.left)||0}imageBaseTop(){return parseFloat(this.mainDOM.style.top)||0}drawImage(e,t,n,r,i,a,o){this.imageEls||=new Map;let s=e+`,`+t,c=this.imageEls.get(s);if(c&&c.url!==o&&(c.el.remove(),this.imageEls.delete(s),c=null),!c){let e=document.createElement(`img`);e.style.position=`absolute`,e.style.pointerEvents=`none`,e.style.zIndex=`1`,e.src=o,this.mainDOM.parentNode.appendChild(e),c={el:e,url:o},this.imageEls.set(s,c)}c.x=e,c.y=t,c.widthCells=n,c.heightCells=r,c.pixelWidth=i,c.pixelHeight=a,this.positionImage(c)}positionImage(e){let t=this.editor.option,n=e.widthCells*t.fontWidth,r=e.heightCells*t.fontHeight;e.el.style.left=this.imageBaseLeft()+e.x*t.fontWidth+`px`,e.el.style.top=this.imageBaseTop()+e.y*t.fontHeight+`px`,e.el.style.width=(e.pixelWidth==null?n:Math.min(e.pixelWidth,n))+`px`,e.el.style.height=(e.pixelHeight==null?r:Math.min(e.pixelHeight,r))+`px`}clearImages(e,t){if(this.imageEls)for(let[n,r]of this.imageEls)r.ye&&(r.el.remove(),this.imageEls.delete(n))}clearAllImages(){if(this.imageEls){for(let[,e]of this.imageEls)e.el.remove();this.imageEls.clear()}}touch(){let e=this.mainDOM.getContext(`2d`);for(let t of this.drawingQueue)t(e);this.drawingQueue=[]}activate(){this.mainDOM.dataset.store=`active`}deactivate(){this.mainDOM.dataset.store=`inactive`}},HTMLSurface=class extends BaseSurface{constructor({editor:e,x:t,y:n,width:r,height:i,styles:a,option:o,isFloating:s,border:c,html:l}){super({editor:e});let u=document.createElement(`iframe`);this.setupDOM({dom:u,isFloating:s,border:c}),u.style.position=`absolute`,u.style.backgroundColor=o.background,u.setAttribute(`sandbox`,`allow-scripts allow-same-origin`),u.srcdoc=l,u.addEventListener(`load`,()=>{let e=u.contentWindow;e.invokeLem=(e,t)=>parent.postMessage({type:`invoke-lem`,method:e,args:t})}),this.iframe=u,this.move(t,n),this.resize(r,i)}resize(e,t,n,r){this._resize(e,t,n,r)}update(e){let t=this.iframe.contentWindow.scrollY;this.iframe.srcdoc=e,this.iframe.onload=()=>{this.iframe.onload=null,this.iframe.contentWindow.scrollTo(0,t)}}evalIn(e){return this.iframe.contentWindow.eval(e)}},VerticalBorder=class{constructor({x:e,y:t,height:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__vertical-border`,this.line.style.height=n*r.fontHeight+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`vertical-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`col-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=Math.floor(n+e*this.option.fontWidth-this.option.fontWidth/2)+`px`,this.line.style.top=r+t*this.option.fontHeight+`px`}resize(e){this.line.style.height=e*this.option.fontHeight+`px`}},HorizontalBorder=class{constructor({x:e,y:t,width:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__horizontal-border`,this.line.style.width=n*r.fontWidth+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`horizontal-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`row-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=n+e*this.option.fontWidth+`px`,this.line.style.top=Math.floor(r+t*this.option.fontHeight-4)+`px`}resize(e){this.line.style.width=e*this.option.fontWidth+`px`}},viewStyles={header:()=>{},tile:()=>{},floating:e=>({boxSizing:`border-box`,borderColor:e.foreground,backgroundColor:e.background})};function getViewStyle(e,t){return viewStyles[e](t)||{}}var View=class{constructor({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,option:h,editor:g}){switch(this.option=h,this.id=e,this.x=t,this.y=n,this.width=r,this.height=i,this.pixelX=a,this.pixelY=o,this.pixelWidth=s,this.pixelHeight=c,this.useModeline=l,this.kind=u,this.type=d,this.border=p,this.borderShape=m,this.editor=g,this.bottomBar=null,this.leftsideBar=null,u){case`tile`:this.mainSurface=this.makeSurface(d,f),this.leftSideBar=new VerticalBorder({x:t,y:n,height:i+ +!!l,option:h,editor:g}),l||(this.bottomBar=new HorizontalBorder({x:t,y:n+i-1,width:r,option:h,editor:g}));break;case`header`:this.mainSurface=this.makeSurface(d,f);break;case`floating`:this.mainSurface=this.makeSurface(d,f),m===`left-border`&&(this.leftSideBar=new VerticalBorder({x:t,y:n,height:i,option:h,editor:g}));break}this.modelineSurface=l?this.makeModelineSurface():null,u===`floating`&&(a!=null||o!=null)&&this.move(t,n,a,o)}delete(){this.mainSurface.delete(),this.modelineSurface&&this.modelineSurface.delete(),this.leftSideBar&&this.leftSideBar.delete(),this.bottomBar&&this.bottomBar.delete()}move(e,t,n,r){if(this.x=e,this.y=t,this.pixelX=n,this.pixelY=r,this.mainSurface.move(e,t,n,r),this.modelineSurface){let i=r!=null&&this.pixelHeight!=null?r+this.pixelHeight:null;this.modelineSurface.move(e,t+this.height,n,i)}this.leftSideBar&&this.leftSideBar.move(e,t),this.bottomBar&&this.bottomBar.move(e,t+this.height)}resize(e,t,n,r){if(this.width=e,this.height=t,this.pixelWidth=n,this.pixelHeight=r,this.mainSurface.resize(e,t,n,r),this.modelineSurface){let t=this.pixelY!=null&&r!=null?this.pixelY+r:null;this.modelineSurface.move(this.x,this.y+this.height,this.pixelX,t),this.modelineSurface.resize(e,1)}this.leftSideBar&&this.leftSideBar.resize(t+ +!!this.modelineSurface),this.bottomBar&&this.bottomBar.resize(e)}clear(){this.mainSurface.drawBlock(0,0,this.width,this.height,this.option.background)}clearEol(e,t,n=1){this.mainSurface.drawBlock(e,t,this.width-e,n,this.option.background),this.mainSurface.clearImages(t,t+n)}clearEob(e,t){this.mainSurface.drawBlock(e,t,this.width,this.height-t,this.option.background),this.mainSurface.clearImages(t,this.height)}print(e,t,n,r,i,a){this.mainSurface.drawText(e,t,n,r,i,a)}printImage(e,t,n,r,i,a,o){this.mainSurface.drawImage(e,t,n,r,i,a,o)}printToModeline(e,t,n,r,i){this.modelineSurface&&this.modelineSurface.drawText(e,t,n,r,i)}touch(e){this.mainSurface.touch(),this.modelineSurface&&(this.modelineSurface.touch(),e?this.modelineSurface.activate():this.modelineSurface.deactivate())}makeSurface(e,t){switch(e){case`html`:return this.makeHTMLSurface(t);case`editor`:return this.makeEditorSurface();default:console.error(`unknown type: ${e}`)}}makeHTMLSurface(e){return new HTMLSurface({editor:this.editor,x:this.x,y:this.y,width:this.width,height:this.height,styles:getViewStyle(this.kind,this.option),option:this.option,isFloating:this.kind===`floating`,border:this.border,html:e})}makeEditorSurface(){let e=this.borderShape===`left-border`?0:this.border,t=this.kind===`floating`;return new CanvasSurface({option:this.editor.option,x:this.x,y:this.y,width:this.width,height:this.height,styles:getViewStyle(this.kind,this.option),editor:this.editor,border:e,isFloating:t,view:this,cssClassName:t&&e?`lem-editor__floating-window--bordered`:null})}makeModelineSurface(){let e=new CanvasSurface({option:this.editor.option,x:this.x,y:this.y+this.height,width:this.width,height:1,editor:this.editor,view:this,styles:{zIndex:zindex(`modeline`)},cssClassName:`lem-editor__mode-line`});return addMouseEventListeners({dom:e.mainDOM,editor:this.editor,isDraggable:!0,draggableStyle:`row-resize`}),e}changeToHTMLContent(e){this.mainSurface.constructor.name===`HTMLSurface`?this.mainSurface.update(e):(this.mainSurface.delete(),this.mainSurface=this.makeHTMLSurface(e))}changeToEditorContent(){this.mainSurface.delete(),this.mainSurface=this.makeEditorSurface()}evalIn(e){return this.mainSurface.evalIn(e)}};function isPasteKeyEvent(e){return isMacOS()?e.metaKey&&e.key===`v`:e.ctrlKey&&e.shiftKey&&e.key===`V`}var Input=class{constructor(e){let t=e.option;this.editor=e,this.composition=!1,this.ignoreKeydownAfterCompositionend=!1,this.span=document.createElement(`span`),this.span.style.color=t.foreground,this.span.style.backgroundColor=t.background,this.span.style.position=`absolute`,this.span.style.zIndex=1e6,this.span.style.top=`0`,this.span.style.left=`0`,this.span.style.font=t.font,this.input=document.createElement(`input`),this.input.style.backgroundColor=`transparent`,this.input.style.color=`transparent`,this.input.style.width=`0`,this.input.style.padding=`0`,this.input.style.margin=`0`,this.input.style.border=`none`,this.input.style.position=`absolute`,this.input.style.zIndex=`-10`,this.input.style.top=`0`,this.input.style.left=`0`,this.input.style.font=t.font,this.input.addEventListener(`blur`,e=>{this.input.focus()}),this.input.addEventListener(`input`,e=>{this.composition===!1&&(this.input.value=``,this.span.innerHTML=``,this.input.style.width=`0`,isMacOS()||this.editor.emitInputString(e.data))}),this.input.addEventListener(`paste`,async e=>{e.preventDefault();let t=e.clipboardData||window.Clipboard.data,n=t?.getData(`text`)??t?.getData(`text/plain`);if(n&&n.length>0){this.editor.emitInputString(n);return}try{if(navigator.clipboard?.readText){let e=await navigator.clipboard.readText();if(e&&e.length>0){this.editor.emitInputString(e);return}}}catch(e){console.warn(`clipboard.readText() failed:`,e)}alert(`Paste failed (permission/environment restriction`)}),this.input.addEventListener(`keydown`,e=>{if(!isPasteKeyEvent(e)&&!(e.isComposing||this.composition)&&e.key!==`Process`){if(this.ignoreKeydownAfterCompositionend&&(isSafari||isMacOS())){e.preventDefault(),this.ignoreKeydownAfterCompositionend=!1;return}if(!(!isMacOS()&&!e.ctrlKey&&!e.altKey&&e.key.length===1)&&(e.preventDefault(),e.isComposing!==!0&&e.code!==``))return setTimeout(()=>{this.composition||(this.editor.emitInput(e),this.input.value=``)},0),!1}}),this.input.addEventListener(`compositionstart`,e=>{this.composition=!0,this.span.innerHTML=this.input.value,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionupdate`,e=>{this.span.innerHTML=e.data,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionend`,e=>{this.composition=!1,this.editor.emitInputString(this.input.value),this.input.value=``,this.span.innerHTML=this.input.value,this.input.style.width=`0`,this.ignoreKeydownAfterCompositionend=!0}),document.body.appendChild(this.input),document.body.appendChild(this.span),this.input.focus()}finalize(){document.body.removeChild(this.input),document.body.removeChild(this.span)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.span.style.top=r+t+`px`,this.span.style.left=n+e+`px`,this.input.style.top=this.span.offsetTop+`px`,this.input.style.left=this.span.offsetLeft+`px`}updateForeground(e){this.span.style.color=e}updateBackground(e){this.span.style.backgroundColor=e}},MessageTable=class{constructor(){this.map=new Map}register(e,t){for(let n in t){let r=t[n];this.map.set(n,r),e.on(n,r)}}get(e){return this.map.get(e)}};function getDisplayRectangleDefault(){return[0,0,window.innerWidth,window.innerHeight]}var Editor=class{constructor({getDisplayRectangle:e=getDisplayRectangleDefault,fontName:t,fontSize:n,url:r,onExit:i,onClosed:a}){this.getDisplayRectangle=e,this.option=new Option({fontName:t,fontSize:n}),this.onExit=i,this.input=new Input(this),this.cursors=new Map,this.cursorOverlay=document.createElement(`div`),this.cursorOverlay.className=`lem-cursor`,this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.cursorOverlay.style.backgroundColor=`#ffffff`,this.cursorType=`box`,this.viewMap=new Map,this.jsonrpc=new JSONRPC(r,{onClosed:()=>{a()}}),this.messageTable=new MessageTable,this.messageTable.register(this.jsonrpc,{"update-foreground":this.updateForeground.bind(this),"update-background":this.updateBackground.bind(this),"make-view":this.makeView.bind(this),"delete-view":this.deleteView.bind(this),"resize-view":this.resize.bind(this),"move-view":this.move.bind(this),"redraw-view-after":this.redrawViewAfter.bind(this),clear:this.clear.bind(this),"clear-eol":this.clearEol.bind(this),"clear-eob":this.clearEob.bind(this),put:this.put.bind(this),"put-image":this.putImage.bind(this),"modeline-put":this.modelinePut.bind(this),"update-display":this.updateDisplay.bind(this),"move-cursor":this.moveCursor.bind(this),"change-view":this.changeView.bind(this),"resize-display":this.resizeDisplay.bind(this),bulk:this.bulk.bind(this),exit:this.exitEditor.bind(this),"get-clipboard-text":this.getClipboardText.bind(this),"set-clipboard-text":this.setClipboardText.bind(this),"js-eval":this.jsEval.bind(this),"set-font":this.setFont.bind(this),"get-font":this.getFont.bind(this),"get-display-size":this.getDisplaySize.bind(this),"load-css":this.loadCSS.bind(this),"update-cursor-shape":this.updateCursorShape.bind(this)}),this.login(),this.boundedHandleResize=this.handleResize.bind(this),this.focusHiddenInput=this.focusHiddenInput.bind(this)}init(){window.addEventListener(`resize`,this.boundedHandleResize),document.getElementsByTagName(`html`)[0].style[`background-color`]=`#333`,getLemEditorElement().appendChild(this.cursorOverlay)}finalize(){window.removeEventListener(`resize`,this.boundedHandleResize),this.input.finalize(),this.cursorOverlay.parentNode&&this.cursorOverlay.parentNode.removeChild(this.cursorOverlay)}closeConnection(){this.jsonrpc.close()}emitInput(e){let t=convertKeyEvent(e);if(t){if(t.key===`]`&&t.ctrl&&!t.meta&&!t.super&&!t.shift){this.jsonrpc.notify(`input`,{kind:`abort`});return}t.key!==`Unidentified`&&this.jsonrpc.notify(`input`,{kind:`key`,value:t})}}emitInputString(e){e?this.jsonrpc.notify(`input`,{kind:`input-string`,value:e}):console.error(`unexpected argument`,e)}handleResize(e){let t=!0;this.jsonrpc.notify(`redraw`,{size:this.getDisplaySize()})}focusHiddenInput(){let e=this.input?.input;if(e){try{window.focus()}catch{}requestAnimationFrame(()=>{setTimeout(()=>{e.focus({preventScroll:!0})},0)})}}sendNotification(e,t){this.jsonrpc.notify(e,t)}request(e,t,n){this.jsonrpc.request(e,t,n)}getDisplaySize(){let[e,t,n,r]=this.getDisplayRectangle();return{width:Math.floor(n/this.option.fontWidth),height:Math.floor(r/this.option.fontHeight)}}callMessage(e,t){this.messageTable.get(e)(t)}findViewById(e){return this.viewMap.get(e)}login(){this.jsonrpc.request(`login`,{size:this.getDisplaySize(),foreground:this.option.foreground,background:this.option.background,fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight},e=>{if(this.updateForeground(e.foreground),this.updateBackground(e.background),e.views)for(let t of e.views)this.makeView(t);this.jsonrpc.notify(`redraw`,{size:this.getDisplaySize()})})}updateForeground(e){e!=null&&(this.option.foreground=e,this.input.updateForeground(e))}updateBackground(e){if(e==null)return;this.option.background=e,this.input.updateBackground(e);let t=getLemEditorElement();t.style.backgroundColor=e}makeView({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,use_modeline:l,kind:u,type:d,content:f,border:p,border_shape:m}){let h=new View({option:this.option,id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,editor:this});this.viewMap.set(e,h)}deleteView({viewInfo:{id:e}}){this.findViewById(e).delete(),this.viewMap.delete(e)}resize({viewInfo:{id:e},width:t,height:n,pixelWidth:r,pixelHeight:i}){let a=this.findViewById(e);a?a.resize(t,n,r,i):console.warn(`resize: view not found for id ${e}`)}move({viewInfo:{id:e},x:t,y:n,pixelX:r,pixelY:i}){let a=this.findViewById(e);a?a.move(t,n,r,i):console.warn(`move: view not found for id ${e}`)}redrawViewAfter({viewInfo:{id:e},isActive:t}){this.findViewById(e).touch(t)}clear({viewInfo:{id:e}}){this.findViewById(e).clear()}clearEol({viewInfo:{id:e},x:t,y:n,height:r}){this.findViewById(e).clearEol(t,n,r)}clearEob({viewInfo:{id:e},x:t,y:n}){this.findViewById(e).clearEob(t,n)}put({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,font:o}){this.findViewById(e).print(t,n,r,i,a,o)}putImage({viewInfo:{id:e},x:t,y:n,width:r,height:i,pixelWidth:a,pixelHeight:o,url:s}){this.findViewById(e).printImage(t,n,r,i,a,o,s)}modelinePut({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a}){this.findViewById(e).printToModeline(t,n,r,i,a)}updateDisplay(){}moveCursor({viewInfo:{id:e},x:t,y:n,color:r,cursorText:i,cursorForeground:a}){let o=this.findViewById(e),[s,c]=this.getDisplayRectangle(),l=o.x*this.option.fontWidth+t*this.option.fontWidth,u=o.y*this.option.fontHeight+n*this.option.fontHeight;this.input.move(l,u);let d=r||this.option.foreground,f=a||this.option.background,p=this.cursorOverlay;switch(this.cursorType){case`bar`:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=`2px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;case`underline`:p.style.left=s+l+`px`,p.style.top=c+u+this.option.fontHeight-2+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=`2px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;default:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.style.font=this.option.font,p.style.paddingTop=textOffsetY+`px`,p.textContent=i||``,p.style.color=f;break}p.style.animation=`none`,p.offsetHeight,p.style.animation=``}updateCursorShape({cursorType:e}){this.cursorType=e||`box`}changeView({viewInfo:{id:e},type:t,content:n}){let r=this.findViewById(e);switch(t){case`html`:r.changeToHTMLContent(n);break;case`editor`:r.changeToEditorContent();break}}resizeDisplay({width:e,height:t}){let n=getLemEditorElement();n.style.width=Math.floor(e*this.option.fontWidth)+`px`,n.style.height=Math.floor(t*this.option.fontHeight)+`px`}bulk(e){for(let{method:t,argument:n}of e)this.callMessage(t,n)}exitEditor(){this.onExit&&this.onExit()}getClipboardText(){navigator.clipboard?.readText().then(e=>{this.jsonrpc.notify(`got-clipboard-text`,{text:e})})}setClipboardText({text:e}){navigator.clipboard&&navigator.clipboard.writeText(e)}jsEval({viewInfo:{id:e},code:t}){let n=this.findViewById(e).evalIn(t);return n&&n.toString()}setFont({fontName:e,fontSize:t}){this.option.setFont(e||this.option.fontName,t||this.option.fontSize)}getFont(){return{name:this.option.fontName,size:this.option.fontSize}}loadCSS({content:e}){let t=document.createElement(`style`);t.textContent=e,document.head.appendChild(t)}notifyToServer(e,t){this.jsonrpc.notify(`invoke`,{method:e,args:t})}},canvas=document.querySelector(`#editor`);async function main(){await Promise.all([document.fonts.load(`19px file-icons`),document.fonts.load(`19px AllTheIcons`),document.fonts.load(`19px fontawesome`),document.fonts.load(`19px material-design-icons`),document.fonts.load(`19px octicons`)]),await document.fonts.ready;let e=new Editor({canvas,fontName:`Monospace`,fontSize:18,url:`${window.location.protocol===`https:`?`wss`:`ws`}://${window.location.hostname}:${window.location.port}`,onExit:null,onClosed:null});window.addEventListener(`message`,t=>{t.data.type===`invoke-lem`&&e.notifyToServer(t.data.method,t.data.args)}),e.init()}main(); \ No newline at end of file +var __defProp=Object.defineProperty,__commonJSMin=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),__exportAll=(e,t)=>{let n={};for(var r in e)__defProp(n,r,{get:e[r],enumerable:!0});return t||__defProp(n,Symbol.toStringTag,{value:`Module`}),n};(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var require_models=__commonJSMin((e=>{var t=e&&e.__extends||(function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};return function(t,n){if(typeof n!=`function`&&n!==null)throw TypeError(`Class extends value `+String(n)+` is not a constructor or null`);e(t,n);function r(){this.constructor=t}t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}})();Object.defineProperty(e,"__esModule",{value:!0}),e.createJSONRPCNotification=e.createJSONRPCRequest=e.createJSONRPCSuccessResponse=e.createJSONRPCErrorResponse=e.JSONRPCErrorCode=e.JSONRPCErrorException=e.isJSONRPCResponses=e.isJSONRPCResponse=e.isJSONRPCRequests=e.isJSONRPCRequest=e.isJSONRPCID=e.JSONRPC=void 0,e.JSONRPC=`2.0`,e.isJSONRPCID=function(e){return typeof e==`string`||typeof e==`number`||e===null},e.isJSONRPCRequest=function(t){return t.jsonrpc===e.JSONRPC&&t.method!==void 0&&t.result===void 0&&t.error===void 0},e.isJSONRPCRequests=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCRequest)},e.isJSONRPCResponse=function(t){return t.jsonrpc===e.JSONRPC&&t.id!==void 0&&(t.result!==void 0||t.error!==void 0)},e.isJSONRPCResponses=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCResponse)};var n=function(e,t,n){var r={code:e,message:t};return n!=null&&(r.data=n),r};e.JSONRPCErrorException=function(e){t(r,e);function r(t,n,i){var a=e.call(this,t)||this;return Object.setPrototypeOf(a,r.prototype),a.code=n,a.data=i,a}return r.prototype.toObject=function(){return n(this.code,this.message,this.data)},r}(Error),(function(e){e[e.ParseError=-32700]=`ParseError`,e[e.InvalidRequest=-32600]=`InvalidRequest`,e[e.MethodNotFound=-32601]=`MethodNotFound`,e[e.InvalidParams=-32602]=`InvalidParams`,e[e.InternalError=-32603]=`InternalError`})(e.JSONRPCErrorCode||={}),e.createJSONRPCErrorResponse=function(t,r,i,a){return{jsonrpc:e.JSONRPC,id:t,error:n(r,i,a)}},e.createJSONRPCSuccessResponse=function(t,n){return{jsonrpc:e.JSONRPC,id:t,result:n??null}},e.createJSONRPCRequest=function(t,n,r){return{jsonrpc:e.JSONRPC,id:t,method:n,params:r}},e.createJSONRPCNotification=function(t,n){return{jsonrpc:e.JSONRPC,method:t,params:n}}})),require_internal=__commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.DefaultErrorCode=void 0,e.DefaultErrorCode=0})),require_client=__commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{Object.defineProperty(e,"__esModule",{value:!0})})),require_server=__commonJSMin((e=>{var t=e&&e.__assign||function(){return t=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__createBinding||(Object.create?(function(e,t,n,r){r===void 0&&(r=n);var i=Object.getOwnPropertyDescriptor(t,n);(!i||(`get`in i?!t.__esModule:i.writable||i.configurable))&&(i={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,i)}):(function(e,t,n,r){r===void 0&&(r=n),e[r]=t[n]})),n=e&&e.__exportStar||function(e,n){for(var r in e)r!=="default"&&!Object.prototype.hasOwnProperty.call(n,r)&&t(n,e,r)};Object.defineProperty(e,"__esModule",{value:!0}),n(require_client(),e),n(require_interfaces(),e),n(require_models(),e),n(require_server(),e),n(require_server_and_client(),e)})),import_dist=require_dist(),JSONRPC=class{constructor(e,{onConnected:t,onClosed:n}){this.url=e,this.onConnected=t,this.onClosed=n,this.messageQueue=[],this.serverAndClient=null,this.connect(),this.connectionEstablished=!1,this.timerId=null,this.closed=!1}close(){this.timerId&&clearTimeout(this.timerId),this.webSocket.close(),this.closed=!0}on(e,t){this.serverAndClient.addMethod(e,t)}async requestInternal(e,t,n){let r=await this.serverAndClient.request(e,t);n&&n(r)}requestMessageQueue(){this.messageQueue.forEach(e=>{let[t,n,r]=e;this.requestInternal(t,n,r)}),this.messageQueue=[]}request(e,t,n){this.webSocket.readyState===WebSocket.OPEN?this.requestInternal(e,t,n):this.messageQueue.push([e,t,n])}notify(e,t){switch(this.webSocket.readyState){case WebSocket.OPEN:this.serverAndClient.notify(e,t);break;case WebSocket.CLOSED:break}}connect(e){this.closed||(console.log(`connect`,this.url),this.webSocket=new WebSocket(this.url),this.serverAndClient||=new import_dist.JSONRPCServerAndClient(new import_dist.JSONRPCServer,new import_dist.JSONRPCClient(e=>{try{return this.webSocket.send(JSON.stringify(e)),Promise.resolve()}catch(e){return Promise.reject(e)}})),this.webSocket.onmessage=e=>{this.serverAndClient.receiveAndSend(JSON.parse(e.data.toString()))},this.webSocket.onopen=()=>{console.log(`WebSocket connection established`),this.connectionEstablished=!0,this.onConnected&&this.onConnected(),this.requestMessageQueue()},this.webSocket.onclose=e=>{console.error(`WebScoket closed`,e),this.serverAndClient.rejectAllPendingRequests(`Connection is closed (${e.reason}).`),this.connectionEstablished&&this.onClosed(),this.timerId=setTimeout(()=>{this.connect()},3e3)},this.webSocket.onerror=e=>{console.error(`WebSocket error:`,e),this.webSocket.close()})}},keyevent_exports=__exportAll({convertKeyEvent:()=>convertKeyEvent}),modifierKeys=[`Shift`,`Control`,`Alt`,`Meta`,`CapsLock`],convertKeyTable={Enter:`Return`,ArrowRight:`Right`,ArrowLeft:`Left`,ArrowUp:`Up`,ArrowDown:`Down`,"¡":`1`,"™":`2`,"£":`3`,"¢":`4`,"∞":`5`,"§":`6`,"¶":`7`,"•":`8`,ª:`9`,º:`0`,"–":`-`,"≠":`=`,"“":`[`,"‘":`]`,"«":`\\`,"…":`;`,æ:`'`,"≤":`,`,"≥":`.`,"÷":`/`,"⁄":`!`,"€":`@`,"‹":`#`,"›":`$`,fi:`%`,fl:`^`,"‡":`&`,"°":`*`,"·":`(`,"‚":`)`,"—":`_`,"±":`+`,"”":`{`,"’":`}`,"»":`|`,Ú:`:`,Æ:`"`,"¯":`<`,"˘":`>`,"¿":`?`,œ:`q`,"∑":`w`,"´":`e`,"®":`r`,"†":`t`,"¥":`y`,"¨":`u`,ˆ:`i`,ø:`o`,π:`p`,å:`a`,ß:`s`,"∂":`d`,ƒ:`f`,"©":`g`,"˙":`h`,"∆":`j`,"˚":`k`,"¬":`l`,Ω:`z`,"≈":`x`,ç:`c`,"√":`v`,"∫":`b`,"˜":`n`,µ:`m`,Œ:`Q`,"„":`W`,"´":`E`,"‰":`R`,ˇ:`T`,Á:`Y`,"¨":`U`,ˆ:`I`,Ø:`O`,"∏":`P`,Å:`A`,Í:`S`,Î:`D`,Ï:`F`,"˝":`G`,Ó:`H`,Ô:`J`,"":`K`,Ò:`L`,"¸":`Z`,"˛":`X`,Ç:`C`,"◊":`V`,ı:`B`,"˜":`N`,Â:`M`};function getKey(e){return e.altKey?convertKeyTable[e.key]||(e.code.startsWith(`Key`)?e.code[3].toLowerCase():null)||e.key:convertKeyTable[e.key]||e.key}function convertKeyEvent(e){return modifierKeys.indexOf(e.key)===-1?{key:getKey(e),ctrl:e.ctrlKey,meta:e.altKey,super:e.metaKey,shift:e.shiftKey}:null}var lib_exports=__exportAll({computeWidth:()=>computeWidth,eawVersion:()=>version,getEAW:()=>getEAW}),defs=[[0,31,`N`],[32,126,`Na`],[127,160,`N`],[161,161,`A`],[162,163,`Na`],[164,164,`A`],[165,166,`Na`],[167,168,`A`],[169,169,`N`],[170,170,`A`],[171,171,`N`],[172,172,`Na`],[173,174,`A`],[175,175,`Na`],[176,180,`A`],[181,181,`N`],[182,186,`A`],[187,187,`N`],[188,191,`A`],[192,197,`N`],[198,198,`A`],[199,207,`N`],[208,208,`A`],[209,214,`N`],[215,216,`A`],[217,221,`N`],[222,225,`A`],[226,229,`N`],[230,230,`A`],[231,231,`N`],[232,234,`A`],[235,235,`N`],[236,237,`A`],[238,239,`N`],[240,240,`A`],[241,241,`N`],[242,243,`A`],[244,246,`N`],[247,250,`A`],[251,251,`N`],[252,252,`A`],[253,253,`N`],[254,254,`A`],[255,256,`N`],[257,257,`A`],[258,272,`N`],[273,273,`A`],[274,274,`N`],[275,275,`A`],[276,282,`N`],[283,283,`A`],[284,293,`N`],[294,295,`A`],[296,298,`N`],[299,299,`A`],[300,304,`N`],[305,307,`A`],[308,311,`N`],[312,312,`A`],[313,318,`N`],[319,322,`A`],[323,323,`N`],[324,324,`A`],[325,327,`N`],[328,331,`A`],[332,332,`N`],[333,333,`A`],[334,337,`N`],[338,339,`A`],[340,357,`N`],[358,359,`A`],[360,362,`N`],[363,363,`A`],[364,461,`N`],[462,462,`A`],[463,463,`N`],[464,464,`A`],[465,465,`N`],[466,466,`A`],[467,467,`N`],[468,468,`A`],[469,469,`N`],[470,470,`A`],[471,471,`N`],[472,472,`A`],[473,473,`N`],[474,474,`A`],[475,475,`N`],[476,476,`A`],[477,592,`N`],[593,593,`A`],[594,608,`N`],[609,609,`A`],[610,707,`N`],[708,708,`A`],[709,710,`N`],[711,711,`A`],[712,712,`N`],[713,715,`A`],[716,716,`N`],[717,717,`A`],[718,719,`N`],[720,720,`A`],[721,727,`N`],[728,731,`A`],[732,732,`N`],[733,733,`A`],[734,734,`N`],[735,735,`A`],[736,767,`N`],[768,879,`A`],[880,912,`N`],[913,929,`A`],[930,930,`N`],[931,937,`A`],[938,944,`N`],[945,961,`A`],[962,962,`N`],[963,969,`A`],[970,1024,`N`],[1025,1025,`A`],[1026,1039,`N`],[1040,1103,`A`],[1104,1104,`N`],[1105,1105,`A`],[1106,4351,`N`],[4352,4447,`W`],[4448,8207,`N`],[8208,8208,`A`],[8209,8210,`N`],[8211,8214,`A`],[8215,8215,`N`],[8216,8217,`A`],[8218,8219,`N`],[8220,8221,`A`],[8222,8223,`N`],[8224,8226,`A`],[8227,8227,`N`],[8228,8231,`A`],[8232,8239,`N`],[8240,8240,`A`],[8241,8241,`N`],[8242,8243,`A`],[8244,8244,`N`],[8245,8245,`A`],[8246,8250,`N`],[8251,8251,`A`],[8252,8253,`N`],[8254,8254,`A`],[8255,8307,`N`],[8308,8308,`A`],[8309,8318,`N`],[8319,8319,`A`],[8320,8320,`N`],[8321,8324,`A`],[8325,8360,`N`],[8361,8361,`H`],[8362,8363,`N`],[8364,8364,`A`],[8365,8450,`N`],[8451,8451,`A`],[8452,8452,`N`],[8453,8453,`A`],[8454,8456,`N`],[8457,8457,`A`],[8458,8466,`N`],[8467,8467,`A`],[8468,8469,`N`],[8470,8470,`A`],[8471,8480,`N`],[8481,8482,`A`],[8483,8485,`N`],[8486,8486,`A`],[8487,8490,`N`],[8491,8491,`A`],[8492,8530,`N`],[8531,8532,`A`],[8533,8538,`N`],[8539,8542,`A`],[8543,8543,`N`],[8544,8555,`A`],[8556,8559,`N`],[8560,8569,`A`],[8570,8584,`N`],[8585,8585,`A`],[8586,8591,`N`],[8592,8601,`A`],[8602,8631,`N`],[8632,8633,`A`],[8634,8657,`N`],[8658,8658,`A`],[8659,8659,`N`],[8660,8660,`A`],[8661,8678,`N`],[8679,8679,`A`],[8680,8703,`N`],[8704,8704,`A`],[8705,8705,`N`],[8706,8707,`A`],[8708,8710,`N`],[8711,8712,`A`],[8713,8714,`N`],[8715,8715,`A`],[8716,8718,`N`],[8719,8719,`A`],[8720,8720,`N`],[8721,8721,`A`],[8722,8724,`N`],[8725,8725,`A`],[8726,8729,`N`],[8730,8730,`A`],[8731,8732,`N`],[8733,8736,`A`],[8737,8738,`N`],[8739,8739,`A`],[8740,8740,`N`],[8741,8741,`A`],[8742,8742,`N`],[8743,8748,`A`],[8749,8749,`N`],[8750,8750,`A`],[8751,8755,`N`],[8756,8759,`A`],[8760,8763,`N`],[8764,8765,`A`],[8766,8775,`N`],[8776,8776,`A`],[8777,8779,`N`],[8780,8780,`A`],[8781,8785,`N`],[8786,8786,`A`],[8787,8799,`N`],[8800,8801,`A`],[8802,8803,`N`],[8804,8807,`A`],[8808,8809,`N`],[8810,8811,`A`],[8812,8813,`N`],[8814,8815,`A`],[8816,8833,`N`],[8834,8835,`A`],[8836,8837,`N`],[8838,8839,`A`],[8840,8852,`N`],[8853,8853,`A`],[8854,8856,`N`],[8857,8857,`A`],[8858,8868,`N`],[8869,8869,`A`],[8870,8894,`N`],[8895,8895,`A`],[8896,8977,`N`],[8978,8978,`A`],[8979,8985,`N`],[8986,8987,`W`],[8988,9e3,`N`],[9001,9002,`W`],[9003,9192,`N`],[9193,9196,`W`],[9197,9199,`N`],[9200,9200,`W`],[9201,9202,`N`],[9203,9203,`W`],[9204,9311,`N`],[9312,9449,`A`],[9450,9450,`N`],[9451,9547,`A`],[9548,9551,`N`],[9552,9587,`A`],[9588,9599,`N`],[9600,9615,`A`],[9616,9617,`N`],[9618,9621,`A`],[9622,9631,`N`],[9632,9633,`A`],[9634,9634,`N`],[9635,9641,`A`],[9642,9649,`N`],[9650,9651,`A`],[9652,9653,`N`],[9654,9655,`A`],[9656,9659,`N`],[9660,9661,`A`],[9662,9663,`N`],[9664,9665,`A`],[9666,9669,`N`],[9670,9672,`A`],[9673,9674,`N`],[9675,9675,`A`],[9676,9677,`N`],[9678,9681,`A`],[9682,9697,`N`],[9698,9701,`A`],[9702,9710,`N`],[9711,9711,`A`],[9712,9724,`N`],[9725,9726,`W`],[9727,9732,`N`],[9733,9734,`A`],[9735,9736,`N`],[9737,9737,`A`],[9738,9741,`N`],[9742,9743,`A`],[9744,9747,`N`],[9748,9749,`W`],[9750,9755,`N`],[9756,9756,`A`],[9757,9757,`N`],[9758,9758,`A`],[9759,9791,`N`],[9792,9792,`A`],[9793,9793,`N`],[9794,9794,`A`],[9795,9799,`N`],[9800,9811,`W`],[9812,9823,`N`],[9824,9825,`A`],[9826,9826,`N`],[9827,9829,`A`],[9830,9830,`N`],[9831,9834,`A`],[9835,9835,`N`],[9836,9837,`A`],[9838,9838,`N`],[9839,9839,`A`],[9840,9854,`N`],[9855,9855,`W`],[9856,9874,`N`],[9875,9875,`W`],[9876,9885,`N`],[9886,9887,`A`],[9888,9888,`N`],[9889,9889,`W`],[9890,9897,`N`],[9898,9899,`W`],[9900,9916,`N`],[9917,9918,`W`],[9919,9919,`A`],[9920,9923,`N`],[9924,9925,`W`],[9926,9933,`A`],[9934,9934,`W`],[9935,9939,`A`],[9940,9940,`W`],[9941,9953,`A`],[9954,9954,`N`],[9955,9955,`A`],[9956,9959,`N`],[9960,9961,`A`],[9962,9962,`W`],[9963,9969,`A`],[9970,9971,`W`],[9972,9972,`A`],[9973,9973,`W`],[9974,9977,`A`],[9978,9978,`W`],[9979,9980,`A`],[9981,9981,`W`],[9982,9983,`A`],[9984,9988,`N`],[9989,9989,`W`],[9990,9993,`N`],[9994,9995,`W`],[9996,10023,`N`],[10024,10024,`W`],[10025,10044,`N`],[10045,10045,`A`],[10046,10059,`N`],[10060,10060,`W`],[10061,10061,`N`],[10062,10062,`W`],[10063,10066,`N`],[10067,10069,`W`],[10070,10070,`N`],[10071,10071,`W`],[10072,10101,`N`],[10102,10111,`A`],[10112,10132,`N`],[10133,10135,`W`],[10136,10159,`N`],[10160,10160,`W`],[10161,10174,`N`],[10175,10175,`W`],[10176,10213,`N`],[10214,10221,`Na`],[10222,10628,`N`],[10629,10630,`Na`],[10631,11034,`N`],[11035,11036,`W`],[11037,11087,`N`],[11088,11088,`W`],[11089,11092,`N`],[11093,11093,`W`],[11094,11097,`A`],[11098,11903,`N`],[11904,11929,`W`],[11930,11930,`N`],[11931,12019,`W`],[12020,12031,`N`],[12032,12245,`W`],[12246,12271,`N`],[12272,12287,`W`],[12288,12288,`F`],[12289,12350,`W`],[12351,12352,`N`],[12353,12438,`W`],[12439,12440,`N`],[12441,12543,`W`],[12544,12548,`N`],[12549,12591,`W`],[12592,12592,`N`],[12593,12686,`W`],[12687,12687,`N`],[12688,12771,`W`],[12772,12782,`N`],[12783,12830,`W`],[12831,12831,`N`],[12832,12871,`W`],[12872,12879,`A`],[12880,19903,`W`],[19904,19967,`N`],[19968,42124,`W`],[42125,42127,`N`],[42128,42182,`W`],[42183,43359,`N`],[43360,43388,`W`],[43389,44031,`N`],[44032,55203,`W`],[55204,57343,`N`],[57344,63743,`A`],[63744,64255,`W`],[64256,65023,`N`],[65024,65039,`A`],[65040,65049,`W`],[65050,65071,`N`],[65072,65106,`W`],[65107,65107,`N`],[65108,65126,`W`],[65127,65127,`N`],[65128,65131,`W`],[65132,65280,`N`],[65281,65376,`F`],[65377,65470,`H`],[65471,65473,`N`],[65474,65479,`H`],[65480,65481,`N`],[65482,65487,`H`],[65488,65489,`N`],[65490,65495,`H`],[65496,65497,`N`],[65498,65500,`H`],[65501,65503,`N`],[65504,65510,`F`],[65511,65511,`N`],[65512,65518,`H`],[65519,65532,`N`],[65533,65533,`A`],[65534,94175,`N`],[94176,94180,`W`],[94181,94191,`N`],[94192,94193,`W`],[94194,94207,`N`],[94208,100343,`W`],[100344,100351,`N`],[100352,101589,`W`],[101590,101631,`N`],[101632,101640,`W`],[101641,110575,`N`],[110576,110579,`W`],[110580,110580,`N`],[110581,110587,`W`],[110588,110588,`N`],[110589,110590,`W`],[110591,110591,`N`],[110592,110882,`W`],[110883,110897,`N`],[110898,110898,`W`],[110899,110927,`N`],[110928,110930,`W`],[110931,110932,`N`],[110933,110933,`W`],[110934,110947,`N`],[110948,110951,`W`],[110952,110959,`N`],[110960,111355,`W`],[111356,126979,`N`],[126980,126980,`W`],[126981,127182,`N`],[127183,127183,`W`],[127184,127231,`N`],[127232,127242,`A`],[127243,127247,`N`],[127248,127277,`A`],[127278,127279,`N`],[127280,127337,`A`],[127338,127343,`N`],[127344,127373,`A`],[127374,127374,`W`],[127375,127376,`A`],[127377,127386,`W`],[127387,127404,`A`],[127405,127487,`N`],[127488,127490,`W`],[127491,127503,`N`],[127504,127547,`W`],[127548,127551,`N`],[127552,127560,`W`],[127561,127567,`N`],[127568,127569,`W`],[127570,127583,`N`],[127584,127589,`W`],[127590,127743,`N`],[127744,127776,`W`],[127777,127788,`N`],[127789,127797,`W`],[127798,127798,`N`],[127799,127868,`W`],[127869,127869,`N`],[127870,127891,`W`],[127892,127903,`N`],[127904,127946,`W`],[127947,127950,`N`],[127951,127955,`W`],[127956,127967,`N`],[127968,127984,`W`],[127985,127987,`N`],[127988,127988,`W`],[127989,127991,`N`],[127992,128062,`W`],[128063,128063,`N`],[128064,128064,`W`],[128065,128065,`N`],[128066,128252,`W`],[128253,128254,`N`],[128255,128317,`W`],[128318,128330,`N`],[128331,128334,`W`],[128335,128335,`N`],[128336,128359,`W`],[128360,128377,`N`],[128378,128378,`W`],[128379,128404,`N`],[128405,128406,`W`],[128407,128419,`N`],[128420,128420,`W`],[128421,128506,`N`],[128507,128591,`W`],[128592,128639,`N`],[128640,128709,`W`],[128710,128715,`N`],[128716,128716,`W`],[128717,128719,`N`],[128720,128722,`W`],[128723,128724,`N`],[128725,128727,`W`],[128728,128731,`N`],[128732,128735,`W`],[128736,128746,`N`],[128747,128748,`W`],[128749,128755,`N`],[128756,128764,`W`],[128765,128991,`N`],[128992,129003,`W`],[129004,129007,`N`],[129008,129008,`W`],[129009,129291,`N`],[129292,129338,`W`],[129339,129339,`N`],[129340,129349,`W`],[129350,129350,`N`],[129351,129535,`W`],[129536,129647,`N`],[129648,129660,`W`],[129661,129663,`N`],[129664,129672,`W`],[129673,129679,`N`],[129680,129725,`W`],[129726,129726,`N`],[129727,129733,`W`],[129734,129741,`N`],[129742,129755,`W`],[129756,129759,`N`],[129760,129768,`W`],[129769,129775,`N`],[129776,129784,`W`],[129785,131071,`N`],[131072,196605,`W`],[196606,196607,`N`],[196608,262141,`W`],[262142,917759,`N`],[917760,917999,`A`],[918e3,983039,`N`],[983040,1048573,`A`],[1048574,1048575,`N`],[1048576,1114109,`A`],[1114110,1114111,`N`]],version=`15.1.0`;function getEAWOfCodePoint(e){let t=0,n=defs.length-1;for(;t!==n;){let r=t+(n-t>>1),[i,a,o]=defs[r];if(ea)t=r+1;else return o}return defs[t][2]}function getEAW(e,t=0){let n=e.codePointAt(t);if(n!==void 0)return getEAWOfCodePoint(n)}var defaultWidths={N:1,Na:1,W:2,F:2,H:1,A:1};function computeWidth(e,t){let n=0;for(let r of e){let e=getEAW(r);n+=t&&t[e]||defaultWidths[e]}return n}var textOffsetY=5,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function isWideChar(e){switch(getEAW(e)){case`F`:case`W`:return!0;default:return!1}}function isMacOS(){return window.navigator.userAgent.indexOf(`Mac OS X`)!==-1}function computeFontSize(e){let t=document.createElement(`canvas`).getContext(`2d`);t.font=e;let n=t.measureText(`W`);return[Math.floor(n.width),Math.round(n.fontBoundingBoxAscent+textOffsetY+(n.emHeightDescent||0)),Math.round(n.fontBoundingBoxAscent+textOffsetY)]}function drawBlock({ctx:e,x:t,y:n,width:r,height:i,style:a}){e.fillStyle=a,e.fillRect(t,n,r,i)}function drawText({ctx:e,x:t,y:n,text:r,font:i,style:a,option:o}){n+=Math.round(textOffsetY),e.fillStyle=a,e.font=i,e.textBaseline=`top`;for(let i of r)isWideChar(i)?(e.fillText(i,t,n,o.fontWidth*2),t+=o.fontWidth*2):(e.fillText(i,t,n,o.fontWidth),t+=o.fontWidth)}function drawHorizontalLine({ctx:e,x:t,y:n,width:r,style:i,lineWidth:a=1}){e.strokeStyle=i,e.lineWidth=a,e.setLineDash=[],e.beginPath(),e.moveTo(t,n),e.lineTo(t+r,n),e.stroke()}var Option=class{constructor({fontName:e,fontSize:t}){this.setFont(e,t),this.foreground=`#cccccc`,this.background=`#2d2d2d`}setFont(e,t){let n=t+`px `+e,[r,i,a]=computeFontSize(n);this.fontName=e,this.fontSize=t,this.fontWidth=r,this.fontHeight=i,this.fontAscent=a,this.font=n}};function getLemEditorElement(){return document.getElementById(`lem-editor`)}function normalizeWheelDelta(e,t,n,r){switch(n){case 0:return{dx:e/r,dy:t/r};case 2:return{dx:e*20,dy:t*20};default:return{dx:e,dy:t}}}function extractWholeLines(e,t){let n=Math.trunc(e),r=Math.trunc(t);return{scrollX:n,scrollY:r,remainderX:e-n,remainderY:t-r}}function cursorPosition(e,t){let[n,r]=t.getDisplayRectangle(),i=e.clientX-n,a=e.clientY-r;return{pixelX:i,pixelY:a,x:Math.floor(i/t.option.fontWidth),y:Math.floor(a/t.option.fontHeight)}}function makeWheelHandler(e){let t={x:0,y:0},n=!1,r={pixelX:0,pixelY:0,x:0,y:0};return i=>{i.preventDefault(),r=cursorPosition(i,e);let{dx:a,dy:o}=normalizeWheelDelta(i.deltaX,i.deltaY,i.deltaMode,e.option.fontHeight);t={x:t.x+a,y:t.y+o},n||(n=!0,requestAnimationFrame(()=>{n=!1;let{scrollX:i,scrollY:a,remainderX:o,remainderY:s}=extractWholeLines(t.x,t.y);t={x:o,y:s},(i!==0||a!==0)&&e.jsonrpc.notify(`input`,{kind:`wheel`,value:{...r,wheelX:-i,wheelY:-a}})}))}}function addMouseEventListeners({dom:e,editor:t,isDraggable:n,draggableStyle:r}){e.addEventListener(`contextmenu`,e=>{e.preventDefault()});let i=(e,n)=>{e.preventDefault();let[r,i]=t.getDisplayRectangle(),a=e.clientX-r,o=e.clientY-i,s=Math.floor(a/t.option.fontWidth),c=Math.floor(o/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:n,value:{x:s,y:c,pixelX:a,pixelY:o,button:e.button,clicks:e.detail}})};e.addEventListener(`mousedown`,e=>{n&&(document.body.style.cursor=r),t.focusHiddenInput(),i(e,`mousedown`)}),e.addEventListener(`mouseup`,e=>{n&&(document.body.style.cursor=`default`),i(e,`mouseup`)});let a=0;e.addEventListener(`mousemove`,e=>{e.preventDefault();let n=Date.now();if(n-a>50){a=n;let[r,i]=t.getDisplayRectangle(),o=e.clientX-r,s=e.clientY-i,c=Math.floor(o/t.option.fontWidth),l=Math.floor(s/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:`mousemove`,value:{x:c,y:l,pixelX:o,pixelY:s,button:e.buttons===0?null:e.buttons-1}})}}),n&&(e.addEventListener(`mouseover`,()=>{document.body.style.cursor=r}),e.addEventListener(`mouseout`,e=>{e.buttons!==1&&(document.body.style.cursor=`default`)})),e.addEventListener(`wheel`,makeWheelHandler(t))}var zIndexTable={"floating-window":200,modeline:100,"vertical-border":100,"horizontal-border":101};function zindex(e){return zIndexTable[e]||0}var borderOffsetX=5,borderOffsetY=10,BaseSurface=class{constructor({editor:e}){this.editor=e,this.mainDOM=null,this.wrapper=null}delete(){this.wrapper?getLemEditorElement().removeChild(this.wrapper):getLemEditorElement().removeChild(this.mainDOM)}setupDOM({dom:e,isFloating:t,border:n,cssClassName:r}){this.mainDOM=e,t&&n?(this.wrapper=document.createElement(`div`),r&&(this.wrapper.className=r),this.wrapper.style.position=`absolute`,this.wrapper.style.backgroundColor=this.editor.option.background,this.wrapper.style.zIndex=zindex(`floating-window`),this.wrapper.appendChild(e),getLemEditorElement().appendChild(this.wrapper)):(r&&(e.className=r),getLemEditorElement().appendChild(e))}move(e,t){let[n,r]=this.editor.getDisplayRectangle(),i=Math.floor(n+e),a=Math.floor(r+t);this.wrapper?(this.wrapper.style.left=i-borderOffsetX+`px`,this.wrapper.style.top=a-borderOffsetY+`px`,this.mainDOM.style.left=borderOffsetX+`px`,this.mainDOM.style.top=borderOffsetY+`px`):(this.mainDOM.style.left=i+`px`,this.mainDOM.style.top=a+`px`)}_resize(e,t){let n=window.devicePixelRatio||1;this.mainDOM.width=e*n,this.mainDOM.height=t*n,this.mainDOM.style.width=e+`px`,this.mainDOM.style.height=t+`px`,this.wrapper&&(this.wrapper.style.width=e+borderOffsetX*2+`px`,this.wrapper.style.height=t+borderOffsetY*2+`px`)}drawBlock(e,t,n,r,i){}drawText(e,t,n,r,i,a,o){}drawImage(e,t,n,r,i){}clearImages(e,t){}clearAllImages(){}touch(){}evalIn(code){return eval(code)}},CanvasSurface=class extends BaseSurface{constructor({editor:e,view:t,pixelX:n,pixelY:r,pixelWidth:i,pixelHeight:a,styles:o,isFloating:s,border:c,cssClassName:l}){super({editor:e});let u=this.setupCanvas(o);this.setupDOM({dom:u,isFloating:s,border:c,cssClassName:l}),this.move(n,r),this.resize(i,a),this.drawingQueue=[],addMouseEventListeners({dom:u,editor:e})}setupCanvas(e){let t=document.createElement(`canvas`);if(t.style.position=`absolute`,e)for(let n in e)t.style[n]=e[n];return t}resize(e,t){this._resize(e,t);let n=window.devicePixelRatio||1;this.mainDOM.getContext(`2d`).scale(n,n)}move(e,t){if(super.move(e,t),this.imageEls)for(let[,e]of this.imageEls)this.positionImage(e)}delete(){this.clearAllImages(),super.delete()}drawBlock(e,t,n,r,i){this.drawingQueue.push(function(a){drawBlock({ctx:a,x:e,y:t,width:n,height:r,style:i})})}drawText(e,t,n,r,i,a,o){let s=this.editor.option,c=o||s.fontHeight;this.drawingQueue.push(function(o){if(a=a?`${s.fontSize}px ${a}`:s.font,!i)drawBlock({ctx:o,x:e,y:t,width:r,height:c,style:s.background}),drawText({ctx:o,x:e,y:t,text:n,style:s.foreground,font:a,option:s});else{let{foreground:l,background:u,bold:d,reverse:f,underline:p,cursor:m}=i;if(l||=s.foreground,u||=s.background,f){let e=u;u=l,l=e}m&&(u=s.background),drawBlock({ctx:o,x:e,y:t,width:r,height:c,style:u}),drawText({ctx:o,x:e,y:t,text:n,style:l,font:d?`bold `+a:a,option:s}),p&&drawHorizontalLine({ctx:o,x:e,y:t+s.fontHeight-2,width:r,style:typeof p==`string`?p:l,lineWidth:2})}})}imageBaseLeft(){return parseFloat(this.mainDOM.style.left)||0}imageBaseTop(){return parseFloat(this.mainDOM.style.top)||0}drawImage(e,t,n,r,i){this.imageEls||=new Map;let a=e+`,`+t,o=this.imageEls.get(a);if(o&&o.url!==i&&(o.el.remove(),this.imageEls.delete(a),o=null),!o){let e=document.createElement(`img`);e.style.position=`absolute`,e.style.pointerEvents=`none`,e.style.zIndex=`1`,e.src=i,this.mainDOM.parentNode.appendChild(e),o={el:e,url:i},this.imageEls.set(a,o)}o.x=e,o.y=t,o.width=n,o.height=r,this.positionImage(o)}positionImage(e){e.el.style.left=this.imageBaseLeft()+e.x+`px`,e.el.style.top=this.imageBaseTop()+e.y+`px`,e.el.style.width=e.width+`px`,e.el.style.height=e.height+`px`}clearImages(e,t){if(this.imageEls)for(let[n,r]of this.imageEls){let i=r.y+(r.height||0);r.ye&&(r.el.remove(),this.imageEls.delete(n))}}clearAllImages(){if(this.imageEls){for(let[,e]of this.imageEls)e.el.remove();this.imageEls.clear()}}touch(){let e=this.mainDOM.getContext(`2d`);for(let t of this.drawingQueue)t(e);this.drawingQueue=[]}activate(){this.mainDOM.dataset.store=`active`}deactivate(){this.mainDOM.dataset.store=`inactive`}},HTMLSurface=class extends BaseSurface{constructor({editor:e,pixelX:t,pixelY:n,pixelWidth:r,pixelHeight:i,styles:a,option:o,isFloating:s,border:c,html:l}){super({editor:e});let u=document.createElement(`iframe`);this.setupDOM({dom:u,isFloating:s,border:c}),u.style.position=`absolute`,u.style.backgroundColor=o.background,u.setAttribute(`sandbox`,`allow-scripts allow-same-origin`),u.srcdoc=l,u.addEventListener(`load`,()=>{let e=u.contentWindow;e.invokeLem=(e,t)=>parent.postMessage({type:`invoke-lem`,method:e,args:t})}),this.iframe=u,this.move(t,n),this.resize(r,i)}resize(e,t){this._resize(e,t)}update(e){let t=this.iframe.contentWindow.scrollY;this.iframe.srcdoc=e,this.iframe.onload=()=>{this.iframe.onload=null,this.iframe.contentWindow.scrollTo(0,t)}}evalIn(e){return this.iframe.contentWindow.eval(e)}},VerticalBorder=class{constructor({x:e,y:t,height:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__vertical-border`,this.line.style.height=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`vertical-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`col-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=Math.floor(n+e-this.option.fontWidth/2)+`px`,this.line.style.top=r+t+`px`}resize(e){this.line.style.height=e+`px`}},HorizontalBorder=class{constructor({x:e,y:t,width:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__horizontal-border`,this.line.style.width=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`horizontal-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`row-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=n+e+`px`,this.line.style.top=Math.floor(r+t-4)+`px`}resize(e){this.line.style.width=e+`px`}},viewStyles={header:()=>{},tile:()=>{},floating:e=>({boxSizing:`border-box`,borderColor:e.foreground,backgroundColor:e.background})};function getViewStyle(e,t){return viewStyles[e](t)||{}}var View=class{constructor({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,option:h,editor:g}){switch(this.option=h,this.id=e,this.x=t,this.y=n,this.width=r,this.height=i,this.pixelX=a,this.pixelY=o,this.pixelWidth=s,this.pixelHeight=c,this.useModeline=l,this.kind=u,this.type=d,this.border=p,this.borderShape=m,this.editor=g,this.bottomBar=null,this.leftsideBar=null,u){case`tile`:this.mainSurface=this.makeSurface(d,f),this.leftSideBar=new VerticalBorder({x:a,y:o,height:c+(l?h.fontHeight:0),option:h,editor:g}),l||(this.bottomBar=new HorizontalBorder({x:a,y:o+c-h.fontHeight,width:s,option:h,editor:g}));break;case`header`:this.mainSurface=this.makeSurface(d,f);break;case`floating`:this.mainSurface=this.makeSurface(d,f),m===`left-border`&&(this.leftSideBar=new VerticalBorder({x:a,y:o,height:c,option:h,editor:g}));break}this.modelineSurface=l?this.makeModelineSurface():null}delete(){this.mainSurface.delete(),this.modelineSurface&&this.modelineSurface.delete(),this.leftSideBar&&this.leftSideBar.delete(),this.bottomBar&&this.bottomBar.delete()}move(e,t,n,r){this.x=e,this.y=t,this.pixelX=n,this.pixelY=r,this.mainSurface.move(n,r),this.modelineSurface&&this.modelineSurface.move(n,r+this.pixelHeight),this.leftSideBar&&this.leftSideBar.move(n,r),this.bottomBar&&this.bottomBar.move(n,r+this.pixelHeight)}resize(e,t,n,r){this.width=e,this.height=t,this.pixelWidth=n,this.pixelHeight=r,this.mainSurface.resize(n,r),this.modelineSurface&&(this.modelineSurface.move(this.pixelX,this.pixelY+r),this.modelineSurface.resize(n,this.option.fontHeight)),this.leftSideBar&&this.leftSideBar.resize(r+(this.modelineSurface?this.option.fontHeight:0)),this.bottomBar&&this.bottomBar.resize(n)}clear(){this.mainSurface.drawBlock(0,0,this.pixelWidth,this.pixelHeight,this.option.background),this.mainSurface.clearImages(0,this.pixelHeight)}clearEol(e,t,n){n??=this.option.fontHeight,this.mainSurface.drawBlock(e,t,this.pixelWidth-e,n,this.option.background),this.mainSurface.clearImages(t,t+n)}clearEob(e,t){this.mainSurface.drawBlock(e,t,this.pixelWidth,this.pixelHeight-t,this.option.background),this.mainSurface.clearImages(t,this.pixelHeight)}print(e,t,n,r,i,a,o){this.mainSurface.drawText(e,t,n,r,i,a,o)}printImage(e,t,n,r,i){this.mainSurface.drawImage(e,t,n,r,i)}printToModeline(e,t,n,r,i,a){this.modelineSurface&&this.modelineSurface.drawText(e,t,n,r,i,null,a)}touch(e){this.mainSurface.touch(),this.modelineSurface&&(this.modelineSurface.touch(),e?this.modelineSurface.activate():this.modelineSurface.deactivate())}makeSurface(e,t){switch(e){case`html`:return this.makeHTMLSurface(t);case`editor`:return this.makeEditorSurface();default:console.error(`unknown type: ${e}`)}}makeHTMLSurface(e){return new HTMLSurface({editor:this.editor,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),option:this.option,isFloating:this.kind===`floating`,border:this.border,html:e})}makeEditorSurface(){let e=this.borderShape===`left-border`?0:this.border,t=this.kind===`floating`;return new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),editor:this.editor,border:e,isFloating:t,view:this,cssClassName:t&&e?`lem-editor__floating-window--bordered`:null})}makeModelineSurface(){let e=new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY+this.pixelHeight,pixelWidth:this.pixelWidth,pixelHeight:this.option.fontHeight,editor:this.editor,view:this,styles:{zIndex:zindex(`modeline`)},cssClassName:`lem-editor__mode-line`});return addMouseEventListeners({dom:e.mainDOM,editor:this.editor,isDraggable:!0,draggableStyle:`row-resize`}),e}changeToHTMLContent(e){this.mainSurface.constructor.name===`HTMLSurface`?this.mainSurface.update(e):(this.mainSurface.delete(),this.mainSurface=this.makeHTMLSurface(e))}changeToEditorContent(){this.mainSurface.delete(),this.mainSurface=this.makeEditorSurface()}evalIn(e){return this.mainSurface.evalIn(e)}};function isPasteKeyEvent(e){return isMacOS()?e.metaKey&&e.key===`v`:e.ctrlKey&&e.shiftKey&&e.key===`V`}var Input=class{constructor(e){let t=e.option;this.editor=e,this.composition=!1,this.ignoreKeydownAfterCompositionend=!1,this.span=document.createElement(`span`),this.span.style.color=t.foreground,this.span.style.backgroundColor=t.background,this.span.style.position=`absolute`,this.span.style.zIndex=1e6,this.span.style.top=`0`,this.span.style.left=`0`,this.span.style.font=t.font,this.input=document.createElement(`input`),this.input.style.backgroundColor=`transparent`,this.input.style.color=`transparent`,this.input.style.width=`0`,this.input.style.padding=`0`,this.input.style.margin=`0`,this.input.style.border=`none`,this.input.style.position=`absolute`,this.input.style.zIndex=`-10`,this.input.style.top=`0`,this.input.style.left=`0`,this.input.style.font=t.font,this.input.addEventListener(`blur`,e=>{this.input.focus()}),this.input.addEventListener(`input`,e=>{this.composition===!1&&(this.input.value=``,this.span.innerHTML=``,this.input.style.width=`0`,isMacOS()||this.editor.emitInputString(e.data))}),this.input.addEventListener(`paste`,async e=>{e.preventDefault();let t=e.clipboardData||window.Clipboard.data,n=t?.getData(`text`)??t?.getData(`text/plain`);if(n&&n.length>0){this.editor.emitInputString(n);return}try{if(navigator.clipboard?.readText){let e=await navigator.clipboard.readText();if(e&&e.length>0){this.editor.emitInputString(e);return}}}catch(e){console.warn(`clipboard.readText() failed:`,e)}alert(`Paste failed (permission/environment restriction`)}),this.input.addEventListener(`keydown`,e=>{if(!isPasteKeyEvent(e)&&!(e.isComposing||this.composition)&&e.key!==`Process`){if(this.ignoreKeydownAfterCompositionend&&(isSafari||isMacOS())){e.preventDefault(),this.ignoreKeydownAfterCompositionend=!1;return}if(!(!isMacOS()&&!e.ctrlKey&&!e.altKey&&e.key.length===1)&&(e.preventDefault(),e.isComposing!==!0&&e.code!==``))return setTimeout(()=>{this.composition||(this.editor.emitInput(e),this.input.value=``)},0),!1}}),this.input.addEventListener(`compositionstart`,e=>{this.composition=!0,this.span.innerHTML=this.input.value,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionupdate`,e=>{this.span.innerHTML=e.data,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionend`,e=>{this.composition=!1,this.editor.emitInputString(this.input.value),this.input.value=``,this.span.innerHTML=this.input.value,this.input.style.width=`0`,this.ignoreKeydownAfterCompositionend=!0}),document.body.appendChild(this.input),document.body.appendChild(this.span),this.input.focus()}finalize(){document.body.removeChild(this.input),document.body.removeChild(this.span)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.span.style.top=r+t+`px`,this.span.style.left=n+e+`px`,this.input.style.top=this.span.offsetTop+`px`,this.input.style.left=this.span.offsetLeft+`px`}updateForeground(e){this.span.style.color=e}updateBackground(e){this.span.style.backgroundColor=e}},MessageTable=class{constructor(){this.map=new Map}register(e,t){for(let n in t){let r=t[n];this.map.set(n,r),e.on(n,r)}}get(e){return this.map.get(e)}};function getDisplayRectangleDefault(){return[0,0,window.innerWidth,window.innerHeight]}var Editor=class{constructor({getDisplayRectangle:e=getDisplayRectangleDefault,fontName:t,fontSize:n,url:r,onExit:i,onClosed:a}){this.getDisplayRectangle=e,this.option=new Option({fontName:t,fontSize:n}),this.onExit=i,this.input=new Input(this),this.cursors=new Map,this.cursorOverlay=document.createElement(`div`),this.cursorOverlay.className=`lem-cursor`,this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.cursorOverlay.style.backgroundColor=`#ffffff`,this.cursorType=`box`,this.viewMap=new Map,this.jsonrpc=new JSONRPC(r,{onClosed:()=>{a()}}),this.messageTable=new MessageTable,this.messageTable.register(this.jsonrpc,{"update-foreground":this.updateForeground.bind(this),"update-background":this.updateBackground.bind(this),"make-view":this.makeView.bind(this),"delete-view":this.deleteView.bind(this),"resize-view":this.resize.bind(this),"move-view":this.move.bind(this),"redraw-view-after":this.redrawViewAfter.bind(this),clear:this.clear.bind(this),"clear-eol":this.clearEol.bind(this),"clear-eob":this.clearEob.bind(this),put:this.put.bind(this),"put-image":this.putImage.bind(this),"modeline-put":this.modelinePut.bind(this),"update-display":this.updateDisplay.bind(this),"move-cursor":this.moveCursor.bind(this),"change-view":this.changeView.bind(this),"resize-display":this.resizeDisplay.bind(this),bulk:this.bulk.bind(this),exit:this.exitEditor.bind(this),"get-clipboard-text":this.getClipboardText.bind(this),"set-clipboard-text":this.setClipboardText.bind(this),"js-eval":this.jsEval.bind(this),"set-font":this.setFont.bind(this),"get-font":this.getFont.bind(this),"get-display-size":this.getDisplaySize.bind(this),"load-css":this.loadCSS.bind(this),"update-cursor-shape":this.updateCursorShape.bind(this)}),this.login(),this.boundedHandleResize=this.handleResize.bind(this),this.focusHiddenInput=this.focusHiddenInput.bind(this)}init(){window.addEventListener(`resize`,this.boundedHandleResize),document.getElementsByTagName(`html`)[0].style[`background-color`]=`#333`,getLemEditorElement().appendChild(this.cursorOverlay)}finalize(){window.removeEventListener(`resize`,this.boundedHandleResize),this.input.finalize(),this.cursorOverlay.parentNode&&this.cursorOverlay.parentNode.removeChild(this.cursorOverlay)}closeConnection(){this.jsonrpc.close()}emitInput(e){let t=convertKeyEvent(e);if(t){if(t.key===`]`&&t.ctrl&&!t.meta&&!t.super&&!t.shift){this.jsonrpc.notify(`input`,{kind:`abort`});return}t.key!==`Unidentified`&&this.jsonrpc.notify(`input`,{kind:`key`,value:t})}}emitInputString(e){e?this.jsonrpc.notify(`input`,{kind:`input-string`,value:e}):console.error(`unexpected argument`,e)}redrawParams(){return{size:this.getDisplaySize(),fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent}}handleResize(e){this.jsonrpc.notify(`redraw`,this.redrawParams())}focusHiddenInput(){let e=this.input?.input;if(e){try{window.focus()}catch{}requestAnimationFrame(()=>{setTimeout(()=>{e.focus({preventScroll:!0})},0)})}}sendNotification(e,t){this.jsonrpc.notify(e,t)}request(e,t,n){this.jsonrpc.request(e,t,n)}getDisplaySize(){let[e,t,n,r]=this.getDisplayRectangle();return{width:Math.floor(n/this.option.fontWidth),height:Math.floor(r/this.option.fontHeight)}}callMessage(e,t){this.messageTable.get(e)(t)}findViewById(e){return this.viewMap.get(e)}login(){this.jsonrpc.request(`login`,{size:this.getDisplaySize(),foreground:this.option.foreground,background:this.option.background,fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent},e=>{if(this.updateForeground(e.foreground),this.updateBackground(e.background),e.views)for(let t of e.views)this.makeView(t);this.jsonrpc.notify(`redraw`,this.redrawParams())})}updateForeground(e){e!=null&&(this.option.foreground=e,this.input.updateForeground(e))}updateBackground(e){if(e==null)return;this.option.background=e,this.input.updateBackground(e);let t=getLemEditorElement();t.style.backgroundColor=e}makeView({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,use_modeline:l,kind:u,type:d,content:f,border:p,border_shape:m}){let h=new View({option:this.option,id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,editor:this});this.viewMap.set(e,h)}deleteView({viewInfo:{id:e}}){this.findViewById(e).delete(),this.viewMap.delete(e)}resize({viewInfo:{id:e},width:t,height:n,pixelWidth:r,pixelHeight:i}){let a=this.findViewById(e);a?a.resize(t,n,r,i):console.warn(`resize: view not found for id ${e}`)}move({viewInfo:{id:e},x:t,y:n,pixelX:r,pixelY:i}){let a=this.findViewById(e);a?a.move(t,n,r,i):console.warn(`move: view not found for id ${e}`)}redrawViewAfter({viewInfo:{id:e},isActive:t}){this.findViewById(e).touch(t)}clear({viewInfo:{id:e}}){this.findViewById(e).clear()}clearEol({viewInfo:{id:e},x:t,y:n,height:r}){this.findViewById(e).clearEol(t,n,r)}clearEob({viewInfo:{id:e},x:t,y:n}){this.findViewById(e).clearEob(t,n)}put({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,font:o,height:s}){this.findViewById(e).print(t,n,r,i,a,o,s)}putImage({viewInfo:{id:e},x:t,y:n,pixelWidth:r,pixelHeight:i,url:a}){this.findViewById(e).printImage(t,n,r,i,a)}modelinePut({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,height:o}){this.findViewById(e).printToModeline(t,n,r,i,a,o)}updateDisplay(){}moveCursor({viewInfo:{id:e},x:t,y:n,color:r,cursorText:i,cursorForeground:a}){let o=this.findViewById(e),[s,c]=this.getDisplayRectangle(),l=o.pixelX+t,u=o.pixelY+n;this.input.move(l,u);let d=r||this.option.foreground,f=a||this.option.background,p=this.cursorOverlay;switch(this.cursorType){case`bar`:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=`2px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;case`underline`:p.style.left=s+l+`px`,p.style.top=c+u+this.option.fontHeight-2+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=`2px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;default:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.style.font=this.option.font,p.style.paddingTop=textOffsetY+`px`,p.textContent=i||``,p.style.color=f;break}p.style.animation=`none`,p.offsetHeight,p.style.animation=``}updateCursorShape({cursorType:e}){this.cursorType=e||`box`}changeView({viewInfo:{id:e},type:t,content:n}){let r=this.findViewById(e);switch(t){case`html`:r.changeToHTMLContent(n);break;case`editor`:r.changeToEditorContent();break}}resizeDisplay({width:e,height:t}){let n=getLemEditorElement();n.style.width=Math.floor(e*this.option.fontWidth)+`px`,n.style.height=Math.floor(t*this.option.fontHeight)+`px`}bulk(e){for(let{method:t,argument:n}of e)this.callMessage(t,n)}exitEditor(){this.onExit&&this.onExit()}getClipboardText(){navigator.clipboard?.readText().then(e=>{this.jsonrpc.notify(`got-clipboard-text`,{text:e})})}setClipboardText({text:e}){navigator.clipboard&&navigator.clipboard.writeText(e)}jsEval({viewInfo:{id:e},code:t}){let n=this.findViewById(e).evalIn(t);return n&&n.toString()}setFont({fontName:e,fontSize:t}){this.option.setFont(e||this.option.fontName,t||this.option.fontSize),this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.jsonrpc.notify(`redraw`,this.redrawParams())}getFont(){return{name:this.option.fontName,size:this.option.fontSize}}loadCSS({content:e}){let t=document.createElement(`style`);t.textContent=e,document.head.appendChild(t)}notifyToServer(e,t){this.jsonrpc.notify(`invoke`,{method:e,args:t})}},canvas=document.querySelector(`#editor`);async function main(){await Promise.all([document.fonts.load(`19px file-icons`),document.fonts.load(`19px AllTheIcons`),document.fonts.load(`19px fontawesome`),document.fonts.load(`19px material-design-icons`),document.fonts.load(`19px octicons`)]),await document.fonts.ready;let e=new Editor({canvas,fontName:`Monospace`,fontSize:18,url:`${window.location.protocol===`https:`?`wss`:`ws`}://${window.location.hostname}:${window.location.port}`,onExit:null,onClosed:null});window.addEventListener(`message`,t=>{t.data.type===`invoke-lem`&&e.notifyToServer(t.data.method,t.data.args)}),e.init()}main(); \ No newline at end of file diff --git a/frontends/server/frontend/editor.js b/frontends/server/frontend/editor.js index c52afb54b..baa0e2af4 100644 --- a/frontends/server/frontend/editor.js +++ b/frontends/server/frontend/editor.js @@ -36,6 +36,7 @@ function computeFontSize(font) { return [ Math.floor(textMetrics.width), Math.round(textMetrics.fontBoundingBoxAscent + textOffsetY + (textMetrics.emHeightDescent || 0)), + Math.round(textMetrics.fontBoundingBoxAscent + textOffsetY), ]; } @@ -80,11 +81,12 @@ class Option { setFont(fontName, fontSize) { const font = fontSize + 'px ' + fontName; - const [width, height] = computeFontSize(font); + const [width, height, ascent] = computeFontSize(font); this.fontName = fontName; this.fontSize = fontSize; this.fontWidth = width; this.fontHeight = height; + this.fontAscent = ascent; this.font = font; } } @@ -313,11 +315,11 @@ class BaseSurface { } } - move(x, y, pixelX, pixelY) { + // every coordinate and size in this class and its subclasses use pixels as a unit (not cells) + move(x, y) { const [x0, y0] = this.editor.getDisplayRectangle(); - // Use pixel coordinates if provided, otherwise calculate from character coordinates - const left = (pixelX != null) ? Math.floor(x0 + pixelX) : Math.floor(x0 + x * this.editor.option.fontWidth); - const top = (pixelY != null) ? Math.floor(y0 + pixelY) : Math.floor(y0 + y * this.editor.option.fontHeight); + const left = Math.floor(x0 + x); + const top = Math.floor(y0 + y); if (this.wrapper) { this.wrapper.style.left = left - borderOffsetX + 'px'; this.wrapper.style.top = top - borderOffsetY + 'px'; @@ -329,24 +331,22 @@ class BaseSurface { } } - _resize(width, height, pixelWidth, pixelHeight) { + _resize(width, height) { const ratio = window.devicePixelRatio || 1; - // Use pixel dimensions if provided, otherwise calculate from character dimensions - const actualWidth = (pixelWidth != null) ? pixelWidth : width * this.editor.option.fontWidth; - const actualHeight = (pixelHeight != null) ? pixelHeight : height * this.editor.option.fontHeight; - this.mainDOM.width = actualWidth * ratio; - this.mainDOM.height = actualHeight * ratio; - this.mainDOM.style.width = actualWidth + 'px'; - this.mainDOM.style.height = actualHeight + 'px'; + this.mainDOM.width = width * ratio; + this.mainDOM.height = height * ratio; + this.mainDOM.style.width = width + 'px'; + this.mainDOM.style.height = height + 'px'; if (this.wrapper) { - this.wrapper.style.width = actualWidth + borderOffsetX * 2 + 'px'; - this.wrapper.style.height = actualHeight + borderOffsetY * 2 + 'px'; + this.wrapper.style.width = width + borderOffsetX * 2 + 'px'; + this.wrapper.style.height = height + borderOffsetY * 2 + 'px'; } } + // drawing coordinates are relative to the surface's own top-left corner. drawBlock(x, y, width, height, color) { } - drawText(x, y, text, textWidth, attribute) { } - drawImage(x, y, widthCells, heightCells, pixelWidth, pixelHeight, url) { } + drawText(x, y, text, textWidth, attribute, font, height) { } + drawImage(x, y, width, height, url) { } clearImages(yStart, yEnd) { } clearAllImages() { } @@ -361,13 +361,14 @@ class BaseSurface { } class CanvasSurface extends BaseSurface { - constructor({ editor, view, x, y, width, height, styles, isFloating, border, cssClassName }) { + constructor({ editor, view, pixelX, pixelY, pixelWidth, pixelHeight, + styles, isFloating, border, cssClassName }) { super({ editor }); const canvas = this.setupCanvas(styles); this.setupDOM({ dom: canvas, isFloating, border, cssClassName }); - this.move(x, y); - this.resize(width, height); + this.move(pixelX, pixelY); + this.resize(pixelWidth, pixelHeight); this.drawingQueue = []; @@ -385,15 +386,15 @@ class CanvasSurface extends BaseSurface { return canvas; } - resize(width, height, pixelWidth, pixelHeight) { - this._resize(width, height, pixelWidth, pixelHeight); + resize(width, height) { + this._resize(width, height); const ratio = window.devicePixelRatio || 1; const ctx = this.mainDOM.getContext('2d'); ctx.scale(ratio, ratio); } - move(x, y, pixelX, pixelY) { - super.move(x, y, pixelX, pixelY); + move(x, y) { + super.move(x, y); if (this.imageEls) { for (const [, entry] of this.imageEls) this.positionImage(entry); } @@ -405,36 +406,32 @@ class CanvasSurface extends BaseSurface { } drawBlock(x, y, width, height, color) { - const option = this.editor.option; this.drawingQueue.push(function(ctx) { - drawBlock({ - ctx, - x: x * option.fontWidth, - y: y * option.fontHeight, - width: width * option.fontWidth, - height: height * option.fontHeight, - style: color, - }) + drawBlock({ ctx, x, y, width, height, style: color }) }); } - drawText(x, y, text, textWidth, attribute, font) { + // the background is filled first, textWidth by blockHeight, then the text drawn over it, so a + // fill with no text is an empty string with a width. only those fills pass a height, to cover a + // row an image made taller than one line of text. text keeps its own cell height. + drawText(x, y, text, textWidth, attribute, font, height) { const option = this.editor.option; + const blockHeight = height || option.fontHeight; this.drawingQueue.push(function(ctx) { font = font ? `${option.fontSize}px ${font}` : option.font; if (!attribute) { drawBlock({ ctx, - x: x * option.fontWidth, - y: y * option.fontHeight, - width: textWidth * option.fontWidth, - height: option.fontHeight, + x: x, + y: y, + width: textWidth, + height: blockHeight, style: option.background, }); drawText({ ctx, - x: x * option.fontWidth, - y: y * option.fontHeight, + x: x, + y: y, text: text, style: option.foreground, font: font, @@ -458,20 +455,18 @@ class CanvasSurface extends BaseSurface { // when the cursor overlay blinks off. background = option.background; } - const gx = x * option.fontWidth; - const gy = y * option.fontHeight; drawBlock({ ctx, - x: gx, - y: gy, - width: textWidth * option.fontWidth, - height: option.fontHeight, + x: x, + y: y, + width: textWidth, + height: blockHeight, style: background, }); drawText({ ctx, - x: gx, - y: gy, + x: x, + y: y, text: text, style: foreground, font: bold ? ('bold ' + font) : font, @@ -480,9 +475,9 @@ class CanvasSurface extends BaseSurface { if (underline) { drawHorizontalLine({ ctx, - x: gx, - y: gy + option.fontHeight - 2, - width: textWidth * option.fontWidth, + x: x, + y: y + option.fontHeight - 2, + width: textWidth, style: typeof (underline) === 'string' ? underline : foreground, lineWidth: 2 }); @@ -495,9 +490,9 @@ class CanvasSurface extends BaseSurface { imageBaseLeft() { return parseFloat(this.mainDOM.style.left) || 0; } imageBaseTop() { return parseFloat(this.mainDOM.style.top) || 0; } - drawImage(x, y, widthCells, heightCells, pixelWidth, pixelHeight, url) { + drawImage(x, y, width, height, url) { if (!this.imageEls) - // mapping "x,y" to { el, url, x, y, widthCells, heightCells, pixelWidth, pixelHeight } + // mapping "x,y" to { el, url, x, y, width, height } this.imageEls = new Map(); const key = x + ',' + y; let entry = this.imageEls.get(key); @@ -519,29 +514,24 @@ class CanvasSurface extends BaseSurface { } entry.x = x; entry.y = y; - entry.widthCells = widthCells; - entry.heightCells = heightCells; - entry.pixelWidth = pixelWidth; - entry.pixelHeight = pixelHeight; + entry.width = width; + entry.height = height; this.positionImage(entry); } positionImage(entry) { - const option = this.editor.option; - // we reserved widthCells x heightCells cells for this image. - const boxWidth = entry.widthCells * option.fontWidth; - const boxHeight = entry.heightCells * option.fontHeight; - entry.el.style.left = (this.imageBaseLeft() + entry.x * option.fontWidth) + 'px'; - entry.el.style.top = (this.imageBaseTop() + entry.y * option.fontHeight) + 'px'; - entry.el.style.width = (entry.pixelWidth != null ? Math.min(entry.pixelWidth, boxWidth) : boxWidth) + 'px'; - entry.el.style.height = (entry.pixelHeight != null ? Math.min(entry.pixelHeight, boxHeight) : boxHeight) + 'px'; + entry.el.style.left = (this.imageBaseLeft() + entry.x) + 'px'; + entry.el.style.top = (this.imageBaseTop() + entry.y) + 'px'; + entry.el.style.width = entry.width + 'px'; + entry.el.style.height = entry.height + 'px'; } - // remove image elements whose row span intersects [yStart, yEnd). + // remove image elements whose vertical span intersects [yStart, yEnd). clearImages(yStart, yEnd) { if (!this.imageEls) return; for (const [key, entry] of this.imageEls) { - if (entry.y < yEnd && (entry.y + entry.heightCells) > yStart) { + const bottom = entry.y + (entry.height || 0); + if (entry.y < yEnd && bottom > yStart) { entry.el.remove(); this.imageEls.delete(key); } @@ -572,7 +562,8 @@ class CanvasSurface extends BaseSurface { } class HTMLSurface extends BaseSurface { - constructor({ editor, x, y, width, height, styles, option, isFloating, border, html }) { + constructor({ editor, pixelX, pixelY, pixelWidth, pixelHeight, + styles, option, isFloating, border, html }) { super({ editor }); const iframe = document.createElement('iframe'); @@ -590,12 +581,12 @@ class HTMLSurface extends BaseSurface { this.iframe = iframe; - this.move(x, y); - this.resize(width, height); + this.move(pixelX, pixelY); + this.resize(pixelWidth, pixelHeight); } - resize(width, height, pixelWidth, pixelHeight) { - this._resize(width, height, pixelWidth, pixelHeight); + resize(width, height) { + this._resize(width, height); } update(content) { @@ -612,13 +603,14 @@ class HTMLSurface extends BaseSurface { } } +// x, y and height are in pixels. class VerticalBorder { constructor({ x, y, height, option, editor }) { this.option = option; this.editor = editor; this.line = document.createElement('div'); this.line.className = 'lem-editor__vertical-border'; - this.line.style.height = height * option.fontHeight + 'px'; + this.line.style.height = height + 'px'; this.line.style.position = 'absolute'; this.line.style.zIndex = zindex('vertical-border'); @@ -640,22 +632,23 @@ class VerticalBorder { move(x, y) { const [x0, y0] = this.editor.getDisplayRectangle(); - this.line.style.left = Math.floor(x0 + x * this.option.fontWidth - this.option.fontWidth / 2) + 'px'; - this.line.style.top = (y0 + y * this.option.fontHeight) + 'px'; + this.line.style.left = Math.floor(x0 + x - this.option.fontWidth / 2) + 'px'; + this.line.style.top = (y0 + y) + 'px'; } resize(height) { - this.line.style.height = height * this.option.fontHeight + 'px'; + this.line.style.height = height + 'px'; } } +// x, y and width are in pixels. class HorizontalBorder { constructor({ x, y, width, option, editor }) { this.option = option; this.editor = editor; this.line = document.createElement('div'); this.line.className = 'lem-editor__horizontal-border'; - this.line.style.width = width * option.fontWidth + 'px'; + this.line.style.width = width + 'px'; this.line.style.position = 'absolute'; this.line.style.zIndex = zindex('horizontal-border'); @@ -677,12 +670,12 @@ class HorizontalBorder { move(x, y) { const [x0, y0] = this.editor.getDisplayRectangle(); - this.line.style.left = (x0 + x * this.option.fontWidth) + 'px'; - this.line.style.top = Math.floor(y0 + y * this.option.fontHeight - 4) + 'px'; + this.line.style.left = (x0 + x) + 'px'; + this.line.style.top = Math.floor(y0 + y - 4) + 'px'; } resize(width) { - this.line.style.width = (width * this.option.fontWidth) + 'px'; + this.line.style.width = width + 'px'; } } @@ -744,17 +737,18 @@ class View { case 'tile': this.mainSurface = this.makeSurface(type, content); this.leftSideBar = new VerticalBorder({ - x: x, - y: y, - height: height + (useModeline ? 1 : 0), + x: pixelX, + y: pixelY, + height: pixelHeight + (useModeline ? option.fontHeight : 0), option: option, editor: editor, }); if (!useModeline) { this.bottomBar = new HorizontalBorder({ - x: x, - y: y + height - 1, - width: width, + x: pixelX, + // along the last row of the view, not below it. + y: pixelY + pixelHeight - option.fontHeight, + width: pixelWidth, option: option, editor: editor, }); @@ -767,9 +761,9 @@ class View { this.mainSurface = this.makeSurface(type, content); if (borderShape === 'left-border') { this.leftSideBar = new VerticalBorder({ - x: x, - y: y, - height: height, + x: pixelX, + y: pixelY, + height: pixelHeight, option: option, editor: editor, }); @@ -778,11 +772,6 @@ class View { } this.modelineSurface = useModeline ? this.makeModelineSurface() : null; - - // For floating windows with pixel coordinates, reposition using pixel coordinates - if (kind === 'floating' && (pixelX != null || pixelY != null)) { - this.move(x, y, pixelX, pixelY); - } } delete() { @@ -804,19 +793,15 @@ class View { this.pixelX = pixelX; this.pixelY = pixelY; - this.mainSurface.move(x, y, pixelX, pixelY); + this.mainSurface.move(pixelX, pixelY); if (this.modelineSurface) { - // Calculate modeline pixel position if pixel coordinates are provided - const modelinePixelY = (pixelY != null && this.pixelHeight != null) - ? pixelY + this.pixelHeight - : null; - this.modelineSurface.move(x, y + this.height, pixelX, modelinePixelY); + this.modelineSurface.move(pixelX, pixelY + this.pixelHeight); } if (this.leftSideBar) { - this.leftSideBar.move(x, y); + this.leftSideBar.move(pixelX, pixelY); } if (this.bottomBar) { - this.bottomBar.move(x, y + this.height); + this.bottomBar.move(pixelX, pixelY + this.pixelHeight); } } @@ -825,25 +810,16 @@ class View { this.height = height; this.pixelWidth = pixelWidth; this.pixelHeight = pixelHeight; - this.mainSurface.resize(width, height, pixelWidth, pixelHeight); + this.mainSurface.resize(pixelWidth, pixelHeight); if (this.modelineSurface) { - // Calculate modeline pixel position if pixel coordinates are provided - const modelinePixelY = (this.pixelY != null && pixelHeight != null) - ? this.pixelY + pixelHeight - : null; - this.modelineSurface.move( - this.x, - this.y + this.height, - this.pixelX, - modelinePixelY, - ); - this.modelineSurface.resize(width, 1); + this.modelineSurface.move(this.pixelX, this.pixelY + pixelHeight); + this.modelineSurface.resize(pixelWidth, this.option.fontHeight); } if (this.leftSideBar) { - this.leftSideBar.resize(height + (this.modelineSurface ? 1 : 0)); + this.leftSideBar.resize(pixelHeight + (this.modelineSurface ? this.option.fontHeight : 0)); } if (this.bottomBar) { - this.bottomBar.resize(width); + this.bottomBar.resize(pixelWidth); } } @@ -851,17 +827,19 @@ class View { this.mainSurface.drawBlock( 0, 0, - this.width, - this.height, + this.pixelWidth, + this.pixelHeight, this.option.background, ); + this.mainSurface.clearImages(0, this.pixelHeight); } - clearEol(x, y, height=1) { + clearEol(x, y, height) { + if (height == null) height = this.option.fontHeight; this.mainSurface.drawBlock( x, y, - this.width - x, + this.pixelWidth - x, height, this.option.background, ); @@ -872,14 +850,14 @@ class View { this.mainSurface.drawBlock( x, // x === 0 y, - this.width, - this.height - y, + this.pixelWidth, + this.pixelHeight - y, this.option.background, ); - this.mainSurface.clearImages(y, this.height); + this.mainSurface.clearImages(y, this.pixelHeight); } - print(x, y, text, textWidth, attribute, font) { + print(x, y, text, textWidth, attribute, font, height) { this.mainSurface.drawText( x, y, @@ -887,14 +865,15 @@ class View { textWidth, attribute, font, + height, ); } - printImage(x, y, width, height, pixelWidth, pixelHeight, url) { - this.mainSurface.drawImage(x, y, width, height, pixelWidth, pixelHeight, url); + printImage(x, y, pixelWidth, pixelHeight, url) { + this.mainSurface.drawImage(x, y, pixelWidth, pixelHeight, url); } - printToModeline(x, y, text, textWidth, attribute) { + printToModeline(x, y, text, textWidth, attribute, height) { if (this.modelineSurface) { this.modelineSurface.drawText( x, @@ -902,6 +881,8 @@ class View { text, textWidth, attribute, + null, + height, ); } } @@ -932,10 +913,10 @@ class View { makeHTMLSurface(content) { return new HTMLSurface({ editor: this.editor, - x: this.x, - y: this.y, - width: this.width, - height: this.height, + pixelX: this.pixelX, + pixelY: this.pixelY, + pixelWidth: this.pixelWidth, + pixelHeight: this.pixelHeight, styles: getViewStyle(this.kind, this.option), option: this.option, isFloating: this.kind === 'floating', @@ -950,10 +931,10 @@ class View { return new CanvasSurface({ option: this.editor.option, - x: this.x, - y: this.y, - width: this.width, - height: this.height, + pixelX: this.pixelX, + pixelY: this.pixelY, + pixelWidth: this.pixelWidth, + pixelHeight: this.pixelHeight, styles: getViewStyle(this.kind, this.option), editor: this.editor, border, @@ -966,10 +947,10 @@ class View { makeModelineSurface() { const surface = new CanvasSurface({ option: this.editor.option, - x: this.x, - y: this.y + this.height, - width: this.width, - height: 1, + pixelX: this.pixelX, + pixelY: this.pixelY + this.pixelHeight, + pixelWidth: this.pixelWidth, + pixelHeight: this.option.fontHeight, editor: this.editor, view: this, styles: { zIndex: zindex('modeline') }, @@ -1316,13 +1297,19 @@ export class Editor { } } + // the server draws in pixels, so it needs our cell size. sent with every redraw, which is how a + // font change reaches it. + redrawParams() { + return { + size: this.getDisplaySize(), + fontWidth: this.option.fontWidth, + fontHeight: this.option.fontHeight, + fontAscent: this.option.fontAscent, + }; + } + handleResize(event) { - const canResize = true; - if (canResize) { - this.jsonrpc.notify('redraw', { size: this.getDisplaySize() }); - } else { - this.jsonrpc.notify('redraw'); - } + this.jsonrpc.notify('redraw', this.redrawParams()); } focusHiddenInput() { @@ -1368,6 +1355,7 @@ export class Editor { background: this.option.background, fontWidth: this.option.fontWidth, fontHeight: this.option.fontHeight, + fontAscent: this.option.fontAscent, }, (response) => { this.updateForeground(response.foreground); this.updateBackground(response.background); @@ -1377,7 +1365,7 @@ export class Editor { } } - this.jsonrpc.notify('redraw', { size: this.getDisplaySize() }); + this.jsonrpc.notify('redraw', this.redrawParams()); }); } @@ -1462,19 +1450,19 @@ export class Editor { view.clearEob(x, y); } - put({ viewInfo: { id }, x, y, text, textWidth, attribute, font }) { + put({ viewInfo: { id }, x, y, text, textWidth, attribute, font, height }) { const view = this.findViewById(id); - view.print(x, y, text, textWidth, attribute, font); + view.print(x, y, text, textWidth, attribute, font, height); } - putImage({ viewInfo: { id }, x, y, width, height, pixelWidth, pixelHeight, url }) { + putImage({ viewInfo: { id }, x, y, pixelWidth, pixelHeight, url }) { const view = this.findViewById(id); - view.printImage(x, y, width, height, pixelWidth, pixelHeight, url); + view.printImage(x, y, pixelWidth, pixelHeight, url); } - modelinePut({ viewInfo: { id }, x, y, text, textWidth, attribute }) { + modelinePut({ viewInfo: { id }, x, y, text, textWidth, attribute, height }) { const view = this.findViewById(id); - view.printToModeline(x, y, text, textWidth, attribute); + view.printToModeline(x, y, text, textWidth, attribute, height); } updateDisplay() { @@ -1483,8 +1471,9 @@ export class Editor { moveCursor({ viewInfo: { id }, x, y, color, cursorText, cursorForeground }) { const view = this.findViewById(id); const [x0, y0] = this.getDisplayRectangle(); - const left = view.x * this.option.fontWidth + x * this.option.fontWidth; - const top = view.y * this.option.fontHeight + y * this.option.fontHeight; + // x and y are pixels within the view. the view's own origin is in pixels too. + const left = view.pixelX + x; + const top = view.pixelY + y; this.input.move(left, top); const cursorColor = color || this.option.foreground; @@ -1596,6 +1585,11 @@ export class Editor { fontName || this.option.fontName, fontSize || this.option.fontSize, ); + this.cursorOverlay.style.width = this.option.fontWidth + 'px'; + this.cursorOverlay.style.height = this.option.fontHeight + 'px'; + // the cell size is the unit the server draws in, so nothing on screen is still correct, + // send the new params and let the server lay the display out again. + this.jsonrpc.notify('redraw', this.redrawParams()); } getFont() { diff --git a/frontends/server/main.lisp b/frontends/server/main.lisp index 0165dad06..1a79a6c83 100644 --- a/frontends/server/main.lisp +++ b/frontends/server/main.lisp @@ -110,11 +110,15 @@ quits by itself afterwards.") :reader jsonrpc-message-queue) (editor-thread :initform nil :accessor jsonrpc-editor-thread) - ;; pixel size of one character cell, reported by the client. - (cell-width :initform nil + ;; pixel size of one character cell. multiplied into every coordinate we send, so never NIL: + ;; we guess, and the client corrects at login. + (cell-width :initform 8 :accessor jsonrpc-cell-width) - (cell-height :initform nil - :accessor jsonrpc-cell-height)) + (cell-height :initform 16 + :accessor jsonrpc-cell-height) + ;; how far below a cell's top the client puts the text baseline. + (cell-ascent :initform nil + :accessor jsonrpc-cell-ascent)) (:default-initargs :name :jsonrpc :redraw-after-modifying-floating-window t @@ -165,6 +169,21 @@ the same immutable instance for every subsequent message." 'vector))) (notify jsonrpc "bulk" argument))) +(defun update-cell-metrics (jsonrpc params) + "take the client's font metrics out of PARAMS, if it sent any. +returns true when one of them changed, since nothing already measured survives a new cell size." + (let ((changed)) + (flet ((update (key accessor) + (alexandria:when-let ((value (gethash key params))) + (when (and (realp value) (plusp value) + (not (eql value (funcall accessor jsonrpc)))) + (funcall (fdefinition `(setf ,accessor)) value jsonrpc) + (setf changed t))))) + (update "fontWidth" 'jsonrpc-cell-width) + (update "fontHeight" 'jsonrpc-cell-height) + (update "fontAscent" 'jsonrpc-cell-ascent)) + changed)) + (defun handle-login (jsonrpc logged-in-callback params) (with-error-handler () (let* ((size (gethash "size" params)) @@ -175,10 +194,7 @@ the same immutable instance for every subsequent message." (let ((width (gethash "width" size)) (height (gethash "height" size))) (resize-display jsonrpc width height))) - (alexandria:when-let ((fw (gethash "fontWidth" params))) - (when (plusp fw) (setf (jsonrpc-cell-width jsonrpc) fw))) - (alexandria:when-let ((fh (gethash "fontHeight" params))) - (when (plusp fh) (setf (jsonrpc-cell-height jsonrpc) fh))) + (update-cell-metrics jsonrpc params) (when background (alexandria:when-let (color (lem:parse-color background)) (setf (jsonrpc-background-color jsonrpc) color))) @@ -200,14 +216,22 @@ the same immutable instance for every subsequent message." (defun redraw (args) (with-error-handler () - (let ((size (and args (gethash "size" args)))) + (let ((size (and args (gethash "size" args))) + ;; the client re-sends its font metrics here, so a font change reaches us by the same + ;; path as a resize instead of needing one of its own. + (metrics-changed (and args (update-cell-metrics (lem:implementation) args)))) (when size (let ((width (gethash "width" size)) (height (gethash "height" size))) (resize-display (lem:implementation) width height) (notify (lem:implementation) "resize-display" size))) (lem:send-event (lambda () + (when metrics-changed + ;; the scroll position was recorded in the old cell size + (dolist (window (lem:window-list)) + (setf (lem-core::horizontal-scroll-start window) 0))) (lem-core::adjust-all-window-size) + ;; :force clears the caches, whose widths are stale after a cell-size change (lem:redraw-display :force t)))))) (defvar *invoke-method-table* (make-hash-table :test 'equal)) @@ -324,10 +348,10 @@ the same immutable instance for every subsequent message." view)) (defmethod lem-if:view-width ((jsonrpc jsonrpc) view) - (view-width view)) + (view-px-width view)) (defmethod lem-if:view-height ((jsonrpc jsonrpc) view) - (view-height view)) + (view-px-height view)) (defmethod lem-if:delete-view ((jsonrpc jsonrpc) view) (with-error-handler () @@ -344,7 +368,9 @@ the same immutable instance for every subsequent message." "resize-view" (hash "viewInfo" (view-id-hash view) "width" width - "height" height)))) + "height" height + "pixelWidth" (view-px-width view) + "pixelHeight" (view-px-height view))))) (defmethod lem-if:set-view-pos ((jsonrpc jsonrpc) view x y) (with-error-handler () @@ -353,7 +379,9 @@ the same immutable instance for every subsequent message." "move-view" (hash "viewInfo" (view-id-hash view) "x" x - "y" y)))) + "y" y + "pixelX" (view-px-x view) + "pixelY" (view-px-y view))))) (defmethod lem-if:make-view-with-pixels ((jsonrpc jsonrpc) window x y width height pixel-x pixel-y pixel-width pixel-height @@ -389,8 +417,8 @@ the same immutable instance for every subsequent message." (hash "viewInfo" (view-id-hash view) "x" x "y" y - "pixelX" pixel-x - "pixelY" pixel-y)))) + "pixelX" (view-px-x view) + "pixelY" (view-px-y view))))) (defmethod lem-if:set-view-size-pixels ((jsonrpc jsonrpc) view width height pixel-width pixel-height) (with-error-handler () @@ -400,8 +428,8 @@ the same immutable instance for every subsequent message." (hash "viewInfo" (view-id-hash view) "width" width "height" height - "pixelWidth" pixel-width - "pixelHeight" pixel-height)))) + "pixelWidth" (view-px-width view) + "pixelHeight" (view-px-height view))))) (defmethod lem-if:redraw-view-before ((jsonrpc jsonrpc) view) ) @@ -479,11 +507,15 @@ the same immutable instance for every subsequent message." (mouse:get-position)) (defmethod lem-if:cell-width ((jsonrpc jsonrpc)) - ;; TODO - 1) + (jsonrpc-cell-width jsonrpc)) + (defmethod lem-if:cell-height ((jsonrpc jsonrpc)) - ;; TODO - 1) + (jsonrpc-cell-height jsonrpc)) + +(defmethod lem-if:cell-pixel-size ((jsonrpc jsonrpc)) + (values (jsonrpc-cell-width jsonrpc) + (jsonrpc-cell-height jsonrpc) + (jsonrpc-cell-ascent jsonrpc))) (defun call (method params) (let ((mailbox (sb-concurrency:make-mailbox :name "lem-server-call-async"))) @@ -583,54 +615,11 @@ the same immutable instance for every subsequent message." ;;; drawing -(defgeneric object-width (drawing-object)) - -(defmethod object-width ((drawing-object display:void-object)) - 0) - -(defmethod object-width ((drawing-object display:text-object)) - (lem-core:string-width (display:text-object-string drawing-object))) - -(defmethod object-width ((drawing-object display:eol-cursor-object)) - 0) -(defmethod object-width ((drawing-object display:extend-to-eol-object)) - 0) - -(defmethod object-width ((drawing-object display:line-end-object)) - (lem-core:string-width (lem-core/display:text-object-string drawing-object))) - -(defmethod object-width ((drawing-object display:image-object)) - ;; width in character cells. when :pixel-width is given (and the client's cell size is known), - ;; round it up to whole cells so the column reserves enough grid space. otherwise use :width - ;; (a cell count) from the attribute. - (let ((pw (image-pixel-dimension drawing-object :pixel-width)) - (cw (jsonrpc-cell-width (lem-core:implementation)))) - (if (and pw cw) - (ceiling pw cw) - (or (display:image-object-width drawing-object) 1)))) - -(defgeneric object-height (drawing-object) - (:documentation "height of DRAWING-OBJECT in character cells. -`lem-core/display:layout-row' grows the row to fit everything on it, so returning more than 1 for -an image gives it the cells it needs.")) - -(defmethod object-height (drawing-object) - 1) - -(defmethod object-height ((drawing-object display:image-object)) - (let ((ph (image-pixel-dimension drawing-object :pixel-height)) - (ch (jsonrpc-cell-height (lem-core:implementation)))) - (if (and ph ch) - (ceiling ph ch) - (or (display:image-object-height drawing-object) 1)))) - -(defun image-pixel-dimension (object key) - "pixel value of KEY (:pixel-width / :pixel-height) on OBJECT's attribute, or NIL." - (let ((attribute (display:image-object-attribute object))) - (and attribute (lem:attribute-value attribute key)))) - -(defgeneric draw-object (jsonrpc object x y view)) +(defgeneric draw-object (jsonrpc object x y view) + (:documentation "draw OBJECT into VIEW with its top-left corner at pixel position X, Y. +`lem-core/display:layout-row' already chose Y as the row's baseline minus this object's ascent, so +a method never needs to know the row's own top or height.")) (defmethod draw-object (jsonrpc (object display:void-object) x y view) (values)) @@ -670,7 +659,9 @@ same hash." (setf attribute (lem:make-attribute :background lem-if:*background-color-of-drawing-window*))) (attribute-to-hash attribute))) -(defun put (jsonrpc view x y string attribute &key font text-width) +(defun put (jsonrpc view x y string attribute &key font text-width height) + "draw STRING at pixel position X, Y in VIEW, over a TEXT-WIDTH by HEIGHT pixel background. +HEIGHT defaults to one line of text." (with-error-handler () (notify* jsonrpc (ecase *put-target* @@ -680,7 +671,8 @@ same hash." "x" x "y" y "text" string - "textWidth" (or text-width (lem:string-width string)) + "textWidth" (or text-width (* (lem:string-width string) (jsonrpc-cell-width jsonrpc))) + "height" height "attribute" (ensure-attribute attribute) "font" font)))) @@ -688,7 +680,7 @@ same hash." (let* ((string (display:text-object-string object)) (attribute (display:text-object-attribute object)) (type (display:text-object-type object)) - (width (object-width object))) + (width (lem-if:object-width jsonrpc object))) (when (and attribute (lem-core:cursor-attribute-p attribute)) (lem-core:set-last-print-cursor (view-window view) x y)) (put jsonrpc @@ -703,7 +695,7 @@ same hash." (let* ((string (display:text-object-string object)) (attribute (display:text-object-attribute object)) (type (display:text-object-type object)) - (width (object-width object))) + (width (lem-if:object-width jsonrpc object))) (when (and attribute (lem-core:cursor-attribute-p attribute)) (lem-core:set-last-print-cursor (view-window view) x y)) (put jsonrpc @@ -722,15 +714,16 @@ same hash." :background (lem:color-to-hex-string (display:eol-cursor-object-color object))))) (lem-core:set-cursor-attribute attr) - (put jsonrpc view x y " " attr :text-width 1))) + (put jsonrpc view x y " " attr :text-width (jsonrpc-cell-width jsonrpc)))) (defmethod draw-object (jsonrpc (object display:line-end-object) x y view) (let ((string (display:text-object-string object)) (attribute (display:text-object-attribute object)) - (width (object-width object))) + (width (lem-if:object-width jsonrpc object))) (put jsonrpc view - (+ x (display:line-end-object-offset object)) + ;; the offset is a column count, unlike the x it is added to. + (+ x (* (display:line-end-object-offset object) (jsonrpc-cell-width jsonrpc))) y string attribute @@ -754,42 +747,35 @@ a string already carrying a data:/https: URL is passed through unchanged." (let ((url (image-object-url object))) (when url (with-error-handler () - ;; use the attribute's :pixel-width/:pixel-height if given, else the reserved cell box - ;; (cells * cell pixel size) when the cell size is known. - (let ((pw (or (image-pixel-dimension object :pixel-width) - (alexandria:when-let ((cw (jsonrpc-cell-width jsonrpc))) - (* (object-width object) cw)))) - (ph (or (image-pixel-dimension object :pixel-height) - (alexandria:when-let ((ch (jsonrpc-cell-height jsonrpc))) - (* (object-height object) ch))))) + (let ((pw (display:image-draw-width jsonrpc object)) + (ph (display:image-draw-height jsonrpc object))) (notify* jsonrpc "put-image" (hash "viewInfo" (view-id-hash view) "x" x "y" y - "width" (object-width object) - "height" (object-height object) "pixelWidth" pw "pixelHeight" ph "url" url))))))) (defun draw-row (jsonrpc view row) "draw ROW's background fill, then everything placed on it. -`clear-eol'/`clear-eob' only ever paint the editor's plain background, so a fill in an arbitrary -color (e.g. a highlighted row) goes out as spaces carrying that color via `put'." - (let ((width (view-width view))) +the client paints a put's background before its text, so the fill goes as an empty string sized +TEXT-WIDTH by HEIGHT, the row's full height, which may exceed a single text line's height when a +tall object (e.g. an image) sits on the row." + (let ((width (view-px-width view))) (when (and (display:row-fill-color row) (< (display:row-fill-x row) width)) - (let ((fill-width (- width (display:row-fill-x row)))) - (put jsonrpc - view - (display:row-fill-x row) - (display:row-top row) - (make-string fill-width :initial-element #\space) - (lem:make-attribute - :background - (lem:color-to-hex-string (display:row-fill-color row))) - :text-width fill-width)))) + (put jsonrpc + view + (display:row-fill-x row) + (display:row-top row) + "" + (lem:make-attribute + :background + (lem:color-to-hex-string (display:row-fill-color row))) + :text-width (- width (display:row-fill-x row)) + :height (display:row-height row)))) (loop :for placement :in (display:row-placements row) :do (draw-object jsonrpc (display:placement-object placement) @@ -799,8 +785,6 @@ color (e.g. a highlighted row) goes out as spaces carrying that color via `put'. (defmethod lem-if:render-row ((jsonrpc jsonrpc) view row) (with-error-handler () - ;; clear the row's full height (not just one line of text) since a tall object such as an image - ;; may occupy several. (notify* jsonrpc "clear-eol" (hash "viewInfo" (view-id-hash view) @@ -818,17 +802,13 @@ color (e.g. a highlighted row) goes out as spaces carrying that color via `put'. (hash "viewInfo" (view-id-hash view) "x" 0 "y" (display:row-top row) - "text" (make-string (view-width view) :initial-element #\space) - "textWidth" (view-width view) + ;; the modeline's own background: no text, just fill + "text" "" + "textWidth" (view-px-width view) + "height" (display:row-height row) "attribute" (attribute-to-hash default-attribute))) (draw-row jsonrpc view row)))) -(defmethod lem-if:object-width ((jsonrpc jsonrpc) drawing-object) - (object-width drawing-object)) - -(defmethod lem-if:object-height ((jsonrpc jsonrpc) drawing-object) - (object-height drawing-object)) - (defmethod lem-if:clear-to-end-of-window ((jsonrpc jsonrpc) view y) (notify* jsonrpc "clear-eob" diff --git a/frontends/server/view.lisp b/frontends/server/view.lisp index fe607b8e8..b5c26de81 100644 --- a/frontends/server/view.lisp +++ b/frontends/server/view.lisp @@ -13,6 +13,10 @@ :view-pixel-y :view-pixel-width :view-pixel-height + :view-px-x + :view-px-y + :view-px-width + :view-px-height :view-use-modeline :view-kind :move-view @@ -51,35 +55,63 @@ use-modeline kind border border-shape)) (apply #'%make-view args)) +(defun cell-pixel-size () + "The pixel size of one character cell, as (values WIDTH HEIGHT). +Never NIL here: this frontend starts from a guess and the client corrects it at login." + (lem-if:cell-pixel-size (lem:implementation))) + +(defun view-px-x (view) + "VIEW's left edge in pixels." + (or (view-pixel-x view) + (* (view-x view) (nth-value 0 (cell-pixel-size))))) + +(defun view-px-y (view) + "VIEW's top edge in pixels." + (or (view-pixel-y view) + (* (view-y view) (nth-value 1 (cell-pixel-size))))) + +(defun view-px-width (view) + "VIEW's width in pixels." + (or (view-pixel-width view) + (* (view-width view) (nth-value 0 (cell-pixel-size))))) + +(defun view-px-height (view) + "VIEW's height in pixels, the edit area only, since the modeline is a surface of its own." + (or (view-pixel-height view) + (* (view-height view) (nth-value 1 (cell-pixel-size))))) + (defun move-view (view x y &optional pixel-x pixel-y) - "Move view to new position. Pixel coordinates are optional." + "Move VIEW to cell position X, Y, or to PIXEL-X / PIXEL-Y for an axis given in pixels. +Passing no pixel position clears any earlier one, so the view follows the cell grid again." (setf (view-x view) x - (view-y view) y) - (when pixel-x (setf (view-pixel-x view) pixel-x)) - (when pixel-y (setf (view-pixel-y view) pixel-y))) + (view-y view) y + (view-pixel-x view) pixel-x + (view-pixel-y view) pixel-y) + (values)) (defun resize-view (view width height &optional pixel-width pixel-height) - "Resize view. Pixel dimensions are optional." + "Resize VIEW to WIDTH x HEIGHT cells, or to PIXEL-WIDTH / PIXEL-HEIGHT for a dimension given in +pixels. As in `move-view', passing no pixel size clears any earlier one." (setf (view-width view) width - (view-height view) height) - (when pixel-width (setf (view-pixel-width view) pixel-width)) - (when pixel-height (setf (view-pixel-height view) pixel-height)) + (view-height view) height + (view-pixel-width view) pixel-width + (view-pixel-height view) pixel-height) (values)) (defmethod yason:encode ((view view) &optional (stream *standard-output*)) (yason:with-output (stream) (yason:with-object () (yason:encode-object-element "id" (view-id view)) - ;; Character-unit coordinates (for backward compatibility) + ;; the cell geometry the core laid this view out on (yason:encode-object-element "x" (view-x view)) (yason:encode-object-element "y" (view-y view)) (yason:encode-object-element "width" (view-width view)) (yason:encode-object-element "height" (view-height view)) - ;; Pixel coordinates (new) - (yason:encode-object-element "pixelX" (view-pixel-x view)) - (yason:encode-object-element "pixelY" (view-pixel-y view)) - (yason:encode-object-element "pixelWidth" (view-pixel-width view)) - (yason:encode-object-element "pixelHeight" (view-pixel-height view)) + ;; and in pixels, always present, so the client never needs the cell size + (yason:encode-object-element "pixelX" (view-px-x view)) + (yason:encode-object-element "pixelY" (view-px-y view)) + (yason:encode-object-element "pixelWidth" (view-px-width view)) + (yason:encode-object-element "pixelHeight" (view-px-height view)) ;; Other existing fields (yason:encode-object-element "use_modeline" (view-use-modeline view)) (yason:encode-object-element "kind" (view-kind view)) From 8568235851e4fecbaa56f4e1a66677134c1c29f4 Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Sat, 1 Aug 2026 14:26:09 +0300 Subject: [PATCH 08/18] let an image sit on the baseline and be cropped at the edge images take an :ascent property, so one can be raised off the baseline. an image that overflows is cropped rather than wrapped; the crop narrows what is shown, not the drawn size. --- frontends/sdl2/drawing.lisp | 35 +++++++---- .../server/frontend/dist/assets/index.js | 2 +- frontends/server/frontend/editor.js | 25 +++++--- frontends/server/main.lisp | 14 ++++- src/display/physical-line.lisp | 59 +++++++++++++++++-- src/internal-packages.lisp | 2 + 6 files changed, 113 insertions(+), 24 deletions(-) diff --git a/frontends/sdl2/drawing.lisp b/frontends/sdl2/drawing.lisp index ec949b938..ddfb30837 100644 --- a/frontends/sdl2/drawing.lisp +++ b/frontends/sdl2/drawing.lisp @@ -291,18 +291,33 @@ width so the rasterizer's right-edge anti-aliasing tail is preserved." view)) (defmethod draw-object ((drawing-object image-object) x top display view) - (let* ((surface-width (object-width drawing-object)) + (let* ((draw-width (max 1 (image-draw-width (lem-core:implementation) drawing-object))) + (visible-width (object-width drawing-object)) (surface-height (object-height drawing-object)) - (texture (sdl2:create-texture-from-surface (display:display-renderer display) - (image-object-image drawing-object)))) - (display:with-scratch-rect (dest-rect display x top surface-width surface-height) - (sdl2:render-copy-ex (display:display-renderer display) - texture - :source-rect nil - :dest-rect dest-rect - :flip (list :none))) + (surface (image-object-image drawing-object)) + (texture (sdl2:create-texture-from-surface (display:display-renderer display) surface))) + (if (< visible-width draw-width) + ;; copy the leading fraction of the source into a dest that wide + (sdl2:with-rects ((dest-rect x top visible-width surface-height) + (source-rect 0 + 0 + (max 1 (round (* (sdl2:surface-width surface) + visible-width) + draw-width)) + (sdl2:surface-height surface))) + (sdl2:render-copy-ex (display:display-renderer display) + texture + :source-rect source-rect + :dest-rect dest-rect + :flip (list :none))) + (display:with-scratch-rect (dest-rect display x top visible-width surface-height) + (sdl2:render-copy-ex (display:display-renderer display) + texture + :source-rect nil + :dest-rect dest-rect + :flip (list :none)))) (sdl2:destroy-texture texture) - surface-width)) + visible-width)) (defun plain-text-object-p (object) "True when OBJECT is an instance of the base `text-object' class (and not diff --git a/frontends/server/frontend/dist/assets/index.js b/frontends/server/frontend/dist/assets/index.js index 136c84167..79fd24e7d 100644 --- a/frontends/server/frontend/dist/assets/index.js +++ b/frontends/server/frontend/dist/assets/index.js @@ -1 +1 @@ -var __defProp=Object.defineProperty,__commonJSMin=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),__exportAll=(e,t)=>{let n={};for(var r in e)__defProp(n,r,{get:e[r],enumerable:!0});return t||__defProp(n,Symbol.toStringTag,{value:`Module`}),n};(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var require_models=__commonJSMin((e=>{var t=e&&e.__extends||(function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};return function(t,n){if(typeof n!=`function`&&n!==null)throw TypeError(`Class extends value `+String(n)+` is not a constructor or null`);e(t,n);function r(){this.constructor=t}t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}})();Object.defineProperty(e,"__esModule",{value:!0}),e.createJSONRPCNotification=e.createJSONRPCRequest=e.createJSONRPCSuccessResponse=e.createJSONRPCErrorResponse=e.JSONRPCErrorCode=e.JSONRPCErrorException=e.isJSONRPCResponses=e.isJSONRPCResponse=e.isJSONRPCRequests=e.isJSONRPCRequest=e.isJSONRPCID=e.JSONRPC=void 0,e.JSONRPC=`2.0`,e.isJSONRPCID=function(e){return typeof e==`string`||typeof e==`number`||e===null},e.isJSONRPCRequest=function(t){return t.jsonrpc===e.JSONRPC&&t.method!==void 0&&t.result===void 0&&t.error===void 0},e.isJSONRPCRequests=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCRequest)},e.isJSONRPCResponse=function(t){return t.jsonrpc===e.JSONRPC&&t.id!==void 0&&(t.result!==void 0||t.error!==void 0)},e.isJSONRPCResponses=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCResponse)};var n=function(e,t,n){var r={code:e,message:t};return n!=null&&(r.data=n),r};e.JSONRPCErrorException=function(e){t(r,e);function r(t,n,i){var a=e.call(this,t)||this;return Object.setPrototypeOf(a,r.prototype),a.code=n,a.data=i,a}return r.prototype.toObject=function(){return n(this.code,this.message,this.data)},r}(Error),(function(e){e[e.ParseError=-32700]=`ParseError`,e[e.InvalidRequest=-32600]=`InvalidRequest`,e[e.MethodNotFound=-32601]=`MethodNotFound`,e[e.InvalidParams=-32602]=`InvalidParams`,e[e.InternalError=-32603]=`InternalError`})(e.JSONRPCErrorCode||={}),e.createJSONRPCErrorResponse=function(t,r,i,a){return{jsonrpc:e.JSONRPC,id:t,error:n(r,i,a)}},e.createJSONRPCSuccessResponse=function(t,n){return{jsonrpc:e.JSONRPC,id:t,result:n??null}},e.createJSONRPCRequest=function(t,n,r){return{jsonrpc:e.JSONRPC,id:t,method:n,params:r}},e.createJSONRPCNotification=function(t,n){return{jsonrpc:e.JSONRPC,method:t,params:n}}})),require_internal=__commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.DefaultErrorCode=void 0,e.DefaultErrorCode=0})),require_client=__commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{Object.defineProperty(e,"__esModule",{value:!0})})),require_server=__commonJSMin((e=>{var t=e&&e.__assign||function(){return t=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__createBinding||(Object.create?(function(e,t,n,r){r===void 0&&(r=n);var i=Object.getOwnPropertyDescriptor(t,n);(!i||(`get`in i?!t.__esModule:i.writable||i.configurable))&&(i={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,i)}):(function(e,t,n,r){r===void 0&&(r=n),e[r]=t[n]})),n=e&&e.__exportStar||function(e,n){for(var r in e)r!=="default"&&!Object.prototype.hasOwnProperty.call(n,r)&&t(n,e,r)};Object.defineProperty(e,"__esModule",{value:!0}),n(require_client(),e),n(require_interfaces(),e),n(require_models(),e),n(require_server(),e),n(require_server_and_client(),e)})),import_dist=require_dist(),JSONRPC=class{constructor(e,{onConnected:t,onClosed:n}){this.url=e,this.onConnected=t,this.onClosed=n,this.messageQueue=[],this.serverAndClient=null,this.connect(),this.connectionEstablished=!1,this.timerId=null,this.closed=!1}close(){this.timerId&&clearTimeout(this.timerId),this.webSocket.close(),this.closed=!0}on(e,t){this.serverAndClient.addMethod(e,t)}async requestInternal(e,t,n){let r=await this.serverAndClient.request(e,t);n&&n(r)}requestMessageQueue(){this.messageQueue.forEach(e=>{let[t,n,r]=e;this.requestInternal(t,n,r)}),this.messageQueue=[]}request(e,t,n){this.webSocket.readyState===WebSocket.OPEN?this.requestInternal(e,t,n):this.messageQueue.push([e,t,n])}notify(e,t){switch(this.webSocket.readyState){case WebSocket.OPEN:this.serverAndClient.notify(e,t);break;case WebSocket.CLOSED:break}}connect(e){this.closed||(console.log(`connect`,this.url),this.webSocket=new WebSocket(this.url),this.serverAndClient||=new import_dist.JSONRPCServerAndClient(new import_dist.JSONRPCServer,new import_dist.JSONRPCClient(e=>{try{return this.webSocket.send(JSON.stringify(e)),Promise.resolve()}catch(e){return Promise.reject(e)}})),this.webSocket.onmessage=e=>{this.serverAndClient.receiveAndSend(JSON.parse(e.data.toString()))},this.webSocket.onopen=()=>{console.log(`WebSocket connection established`),this.connectionEstablished=!0,this.onConnected&&this.onConnected(),this.requestMessageQueue()},this.webSocket.onclose=e=>{console.error(`WebScoket closed`,e),this.serverAndClient.rejectAllPendingRequests(`Connection is closed (${e.reason}).`),this.connectionEstablished&&this.onClosed(),this.timerId=setTimeout(()=>{this.connect()},3e3)},this.webSocket.onerror=e=>{console.error(`WebSocket error:`,e),this.webSocket.close()})}},keyevent_exports=__exportAll({convertKeyEvent:()=>convertKeyEvent}),modifierKeys=[`Shift`,`Control`,`Alt`,`Meta`,`CapsLock`],convertKeyTable={Enter:`Return`,ArrowRight:`Right`,ArrowLeft:`Left`,ArrowUp:`Up`,ArrowDown:`Down`,"¡":`1`,"™":`2`,"£":`3`,"¢":`4`,"∞":`5`,"§":`6`,"¶":`7`,"•":`8`,ª:`9`,º:`0`,"–":`-`,"≠":`=`,"“":`[`,"‘":`]`,"«":`\\`,"…":`;`,æ:`'`,"≤":`,`,"≥":`.`,"÷":`/`,"⁄":`!`,"€":`@`,"‹":`#`,"›":`$`,fi:`%`,fl:`^`,"‡":`&`,"°":`*`,"·":`(`,"‚":`)`,"—":`_`,"±":`+`,"”":`{`,"’":`}`,"»":`|`,Ú:`:`,Æ:`"`,"¯":`<`,"˘":`>`,"¿":`?`,œ:`q`,"∑":`w`,"´":`e`,"®":`r`,"†":`t`,"¥":`y`,"¨":`u`,ˆ:`i`,ø:`o`,π:`p`,å:`a`,ß:`s`,"∂":`d`,ƒ:`f`,"©":`g`,"˙":`h`,"∆":`j`,"˚":`k`,"¬":`l`,Ω:`z`,"≈":`x`,ç:`c`,"√":`v`,"∫":`b`,"˜":`n`,µ:`m`,Œ:`Q`,"„":`W`,"´":`E`,"‰":`R`,ˇ:`T`,Á:`Y`,"¨":`U`,ˆ:`I`,Ø:`O`,"∏":`P`,Å:`A`,Í:`S`,Î:`D`,Ï:`F`,"˝":`G`,Ó:`H`,Ô:`J`,"":`K`,Ò:`L`,"¸":`Z`,"˛":`X`,Ç:`C`,"◊":`V`,ı:`B`,"˜":`N`,Â:`M`};function getKey(e){return e.altKey?convertKeyTable[e.key]||(e.code.startsWith(`Key`)?e.code[3].toLowerCase():null)||e.key:convertKeyTable[e.key]||e.key}function convertKeyEvent(e){return modifierKeys.indexOf(e.key)===-1?{key:getKey(e),ctrl:e.ctrlKey,meta:e.altKey,super:e.metaKey,shift:e.shiftKey}:null}var lib_exports=__exportAll({computeWidth:()=>computeWidth,eawVersion:()=>version,getEAW:()=>getEAW}),defs=[[0,31,`N`],[32,126,`Na`],[127,160,`N`],[161,161,`A`],[162,163,`Na`],[164,164,`A`],[165,166,`Na`],[167,168,`A`],[169,169,`N`],[170,170,`A`],[171,171,`N`],[172,172,`Na`],[173,174,`A`],[175,175,`Na`],[176,180,`A`],[181,181,`N`],[182,186,`A`],[187,187,`N`],[188,191,`A`],[192,197,`N`],[198,198,`A`],[199,207,`N`],[208,208,`A`],[209,214,`N`],[215,216,`A`],[217,221,`N`],[222,225,`A`],[226,229,`N`],[230,230,`A`],[231,231,`N`],[232,234,`A`],[235,235,`N`],[236,237,`A`],[238,239,`N`],[240,240,`A`],[241,241,`N`],[242,243,`A`],[244,246,`N`],[247,250,`A`],[251,251,`N`],[252,252,`A`],[253,253,`N`],[254,254,`A`],[255,256,`N`],[257,257,`A`],[258,272,`N`],[273,273,`A`],[274,274,`N`],[275,275,`A`],[276,282,`N`],[283,283,`A`],[284,293,`N`],[294,295,`A`],[296,298,`N`],[299,299,`A`],[300,304,`N`],[305,307,`A`],[308,311,`N`],[312,312,`A`],[313,318,`N`],[319,322,`A`],[323,323,`N`],[324,324,`A`],[325,327,`N`],[328,331,`A`],[332,332,`N`],[333,333,`A`],[334,337,`N`],[338,339,`A`],[340,357,`N`],[358,359,`A`],[360,362,`N`],[363,363,`A`],[364,461,`N`],[462,462,`A`],[463,463,`N`],[464,464,`A`],[465,465,`N`],[466,466,`A`],[467,467,`N`],[468,468,`A`],[469,469,`N`],[470,470,`A`],[471,471,`N`],[472,472,`A`],[473,473,`N`],[474,474,`A`],[475,475,`N`],[476,476,`A`],[477,592,`N`],[593,593,`A`],[594,608,`N`],[609,609,`A`],[610,707,`N`],[708,708,`A`],[709,710,`N`],[711,711,`A`],[712,712,`N`],[713,715,`A`],[716,716,`N`],[717,717,`A`],[718,719,`N`],[720,720,`A`],[721,727,`N`],[728,731,`A`],[732,732,`N`],[733,733,`A`],[734,734,`N`],[735,735,`A`],[736,767,`N`],[768,879,`A`],[880,912,`N`],[913,929,`A`],[930,930,`N`],[931,937,`A`],[938,944,`N`],[945,961,`A`],[962,962,`N`],[963,969,`A`],[970,1024,`N`],[1025,1025,`A`],[1026,1039,`N`],[1040,1103,`A`],[1104,1104,`N`],[1105,1105,`A`],[1106,4351,`N`],[4352,4447,`W`],[4448,8207,`N`],[8208,8208,`A`],[8209,8210,`N`],[8211,8214,`A`],[8215,8215,`N`],[8216,8217,`A`],[8218,8219,`N`],[8220,8221,`A`],[8222,8223,`N`],[8224,8226,`A`],[8227,8227,`N`],[8228,8231,`A`],[8232,8239,`N`],[8240,8240,`A`],[8241,8241,`N`],[8242,8243,`A`],[8244,8244,`N`],[8245,8245,`A`],[8246,8250,`N`],[8251,8251,`A`],[8252,8253,`N`],[8254,8254,`A`],[8255,8307,`N`],[8308,8308,`A`],[8309,8318,`N`],[8319,8319,`A`],[8320,8320,`N`],[8321,8324,`A`],[8325,8360,`N`],[8361,8361,`H`],[8362,8363,`N`],[8364,8364,`A`],[8365,8450,`N`],[8451,8451,`A`],[8452,8452,`N`],[8453,8453,`A`],[8454,8456,`N`],[8457,8457,`A`],[8458,8466,`N`],[8467,8467,`A`],[8468,8469,`N`],[8470,8470,`A`],[8471,8480,`N`],[8481,8482,`A`],[8483,8485,`N`],[8486,8486,`A`],[8487,8490,`N`],[8491,8491,`A`],[8492,8530,`N`],[8531,8532,`A`],[8533,8538,`N`],[8539,8542,`A`],[8543,8543,`N`],[8544,8555,`A`],[8556,8559,`N`],[8560,8569,`A`],[8570,8584,`N`],[8585,8585,`A`],[8586,8591,`N`],[8592,8601,`A`],[8602,8631,`N`],[8632,8633,`A`],[8634,8657,`N`],[8658,8658,`A`],[8659,8659,`N`],[8660,8660,`A`],[8661,8678,`N`],[8679,8679,`A`],[8680,8703,`N`],[8704,8704,`A`],[8705,8705,`N`],[8706,8707,`A`],[8708,8710,`N`],[8711,8712,`A`],[8713,8714,`N`],[8715,8715,`A`],[8716,8718,`N`],[8719,8719,`A`],[8720,8720,`N`],[8721,8721,`A`],[8722,8724,`N`],[8725,8725,`A`],[8726,8729,`N`],[8730,8730,`A`],[8731,8732,`N`],[8733,8736,`A`],[8737,8738,`N`],[8739,8739,`A`],[8740,8740,`N`],[8741,8741,`A`],[8742,8742,`N`],[8743,8748,`A`],[8749,8749,`N`],[8750,8750,`A`],[8751,8755,`N`],[8756,8759,`A`],[8760,8763,`N`],[8764,8765,`A`],[8766,8775,`N`],[8776,8776,`A`],[8777,8779,`N`],[8780,8780,`A`],[8781,8785,`N`],[8786,8786,`A`],[8787,8799,`N`],[8800,8801,`A`],[8802,8803,`N`],[8804,8807,`A`],[8808,8809,`N`],[8810,8811,`A`],[8812,8813,`N`],[8814,8815,`A`],[8816,8833,`N`],[8834,8835,`A`],[8836,8837,`N`],[8838,8839,`A`],[8840,8852,`N`],[8853,8853,`A`],[8854,8856,`N`],[8857,8857,`A`],[8858,8868,`N`],[8869,8869,`A`],[8870,8894,`N`],[8895,8895,`A`],[8896,8977,`N`],[8978,8978,`A`],[8979,8985,`N`],[8986,8987,`W`],[8988,9e3,`N`],[9001,9002,`W`],[9003,9192,`N`],[9193,9196,`W`],[9197,9199,`N`],[9200,9200,`W`],[9201,9202,`N`],[9203,9203,`W`],[9204,9311,`N`],[9312,9449,`A`],[9450,9450,`N`],[9451,9547,`A`],[9548,9551,`N`],[9552,9587,`A`],[9588,9599,`N`],[9600,9615,`A`],[9616,9617,`N`],[9618,9621,`A`],[9622,9631,`N`],[9632,9633,`A`],[9634,9634,`N`],[9635,9641,`A`],[9642,9649,`N`],[9650,9651,`A`],[9652,9653,`N`],[9654,9655,`A`],[9656,9659,`N`],[9660,9661,`A`],[9662,9663,`N`],[9664,9665,`A`],[9666,9669,`N`],[9670,9672,`A`],[9673,9674,`N`],[9675,9675,`A`],[9676,9677,`N`],[9678,9681,`A`],[9682,9697,`N`],[9698,9701,`A`],[9702,9710,`N`],[9711,9711,`A`],[9712,9724,`N`],[9725,9726,`W`],[9727,9732,`N`],[9733,9734,`A`],[9735,9736,`N`],[9737,9737,`A`],[9738,9741,`N`],[9742,9743,`A`],[9744,9747,`N`],[9748,9749,`W`],[9750,9755,`N`],[9756,9756,`A`],[9757,9757,`N`],[9758,9758,`A`],[9759,9791,`N`],[9792,9792,`A`],[9793,9793,`N`],[9794,9794,`A`],[9795,9799,`N`],[9800,9811,`W`],[9812,9823,`N`],[9824,9825,`A`],[9826,9826,`N`],[9827,9829,`A`],[9830,9830,`N`],[9831,9834,`A`],[9835,9835,`N`],[9836,9837,`A`],[9838,9838,`N`],[9839,9839,`A`],[9840,9854,`N`],[9855,9855,`W`],[9856,9874,`N`],[9875,9875,`W`],[9876,9885,`N`],[9886,9887,`A`],[9888,9888,`N`],[9889,9889,`W`],[9890,9897,`N`],[9898,9899,`W`],[9900,9916,`N`],[9917,9918,`W`],[9919,9919,`A`],[9920,9923,`N`],[9924,9925,`W`],[9926,9933,`A`],[9934,9934,`W`],[9935,9939,`A`],[9940,9940,`W`],[9941,9953,`A`],[9954,9954,`N`],[9955,9955,`A`],[9956,9959,`N`],[9960,9961,`A`],[9962,9962,`W`],[9963,9969,`A`],[9970,9971,`W`],[9972,9972,`A`],[9973,9973,`W`],[9974,9977,`A`],[9978,9978,`W`],[9979,9980,`A`],[9981,9981,`W`],[9982,9983,`A`],[9984,9988,`N`],[9989,9989,`W`],[9990,9993,`N`],[9994,9995,`W`],[9996,10023,`N`],[10024,10024,`W`],[10025,10044,`N`],[10045,10045,`A`],[10046,10059,`N`],[10060,10060,`W`],[10061,10061,`N`],[10062,10062,`W`],[10063,10066,`N`],[10067,10069,`W`],[10070,10070,`N`],[10071,10071,`W`],[10072,10101,`N`],[10102,10111,`A`],[10112,10132,`N`],[10133,10135,`W`],[10136,10159,`N`],[10160,10160,`W`],[10161,10174,`N`],[10175,10175,`W`],[10176,10213,`N`],[10214,10221,`Na`],[10222,10628,`N`],[10629,10630,`Na`],[10631,11034,`N`],[11035,11036,`W`],[11037,11087,`N`],[11088,11088,`W`],[11089,11092,`N`],[11093,11093,`W`],[11094,11097,`A`],[11098,11903,`N`],[11904,11929,`W`],[11930,11930,`N`],[11931,12019,`W`],[12020,12031,`N`],[12032,12245,`W`],[12246,12271,`N`],[12272,12287,`W`],[12288,12288,`F`],[12289,12350,`W`],[12351,12352,`N`],[12353,12438,`W`],[12439,12440,`N`],[12441,12543,`W`],[12544,12548,`N`],[12549,12591,`W`],[12592,12592,`N`],[12593,12686,`W`],[12687,12687,`N`],[12688,12771,`W`],[12772,12782,`N`],[12783,12830,`W`],[12831,12831,`N`],[12832,12871,`W`],[12872,12879,`A`],[12880,19903,`W`],[19904,19967,`N`],[19968,42124,`W`],[42125,42127,`N`],[42128,42182,`W`],[42183,43359,`N`],[43360,43388,`W`],[43389,44031,`N`],[44032,55203,`W`],[55204,57343,`N`],[57344,63743,`A`],[63744,64255,`W`],[64256,65023,`N`],[65024,65039,`A`],[65040,65049,`W`],[65050,65071,`N`],[65072,65106,`W`],[65107,65107,`N`],[65108,65126,`W`],[65127,65127,`N`],[65128,65131,`W`],[65132,65280,`N`],[65281,65376,`F`],[65377,65470,`H`],[65471,65473,`N`],[65474,65479,`H`],[65480,65481,`N`],[65482,65487,`H`],[65488,65489,`N`],[65490,65495,`H`],[65496,65497,`N`],[65498,65500,`H`],[65501,65503,`N`],[65504,65510,`F`],[65511,65511,`N`],[65512,65518,`H`],[65519,65532,`N`],[65533,65533,`A`],[65534,94175,`N`],[94176,94180,`W`],[94181,94191,`N`],[94192,94193,`W`],[94194,94207,`N`],[94208,100343,`W`],[100344,100351,`N`],[100352,101589,`W`],[101590,101631,`N`],[101632,101640,`W`],[101641,110575,`N`],[110576,110579,`W`],[110580,110580,`N`],[110581,110587,`W`],[110588,110588,`N`],[110589,110590,`W`],[110591,110591,`N`],[110592,110882,`W`],[110883,110897,`N`],[110898,110898,`W`],[110899,110927,`N`],[110928,110930,`W`],[110931,110932,`N`],[110933,110933,`W`],[110934,110947,`N`],[110948,110951,`W`],[110952,110959,`N`],[110960,111355,`W`],[111356,126979,`N`],[126980,126980,`W`],[126981,127182,`N`],[127183,127183,`W`],[127184,127231,`N`],[127232,127242,`A`],[127243,127247,`N`],[127248,127277,`A`],[127278,127279,`N`],[127280,127337,`A`],[127338,127343,`N`],[127344,127373,`A`],[127374,127374,`W`],[127375,127376,`A`],[127377,127386,`W`],[127387,127404,`A`],[127405,127487,`N`],[127488,127490,`W`],[127491,127503,`N`],[127504,127547,`W`],[127548,127551,`N`],[127552,127560,`W`],[127561,127567,`N`],[127568,127569,`W`],[127570,127583,`N`],[127584,127589,`W`],[127590,127743,`N`],[127744,127776,`W`],[127777,127788,`N`],[127789,127797,`W`],[127798,127798,`N`],[127799,127868,`W`],[127869,127869,`N`],[127870,127891,`W`],[127892,127903,`N`],[127904,127946,`W`],[127947,127950,`N`],[127951,127955,`W`],[127956,127967,`N`],[127968,127984,`W`],[127985,127987,`N`],[127988,127988,`W`],[127989,127991,`N`],[127992,128062,`W`],[128063,128063,`N`],[128064,128064,`W`],[128065,128065,`N`],[128066,128252,`W`],[128253,128254,`N`],[128255,128317,`W`],[128318,128330,`N`],[128331,128334,`W`],[128335,128335,`N`],[128336,128359,`W`],[128360,128377,`N`],[128378,128378,`W`],[128379,128404,`N`],[128405,128406,`W`],[128407,128419,`N`],[128420,128420,`W`],[128421,128506,`N`],[128507,128591,`W`],[128592,128639,`N`],[128640,128709,`W`],[128710,128715,`N`],[128716,128716,`W`],[128717,128719,`N`],[128720,128722,`W`],[128723,128724,`N`],[128725,128727,`W`],[128728,128731,`N`],[128732,128735,`W`],[128736,128746,`N`],[128747,128748,`W`],[128749,128755,`N`],[128756,128764,`W`],[128765,128991,`N`],[128992,129003,`W`],[129004,129007,`N`],[129008,129008,`W`],[129009,129291,`N`],[129292,129338,`W`],[129339,129339,`N`],[129340,129349,`W`],[129350,129350,`N`],[129351,129535,`W`],[129536,129647,`N`],[129648,129660,`W`],[129661,129663,`N`],[129664,129672,`W`],[129673,129679,`N`],[129680,129725,`W`],[129726,129726,`N`],[129727,129733,`W`],[129734,129741,`N`],[129742,129755,`W`],[129756,129759,`N`],[129760,129768,`W`],[129769,129775,`N`],[129776,129784,`W`],[129785,131071,`N`],[131072,196605,`W`],[196606,196607,`N`],[196608,262141,`W`],[262142,917759,`N`],[917760,917999,`A`],[918e3,983039,`N`],[983040,1048573,`A`],[1048574,1048575,`N`],[1048576,1114109,`A`],[1114110,1114111,`N`]],version=`15.1.0`;function getEAWOfCodePoint(e){let t=0,n=defs.length-1;for(;t!==n;){let r=t+(n-t>>1),[i,a,o]=defs[r];if(ea)t=r+1;else return o}return defs[t][2]}function getEAW(e,t=0){let n=e.codePointAt(t);if(n!==void 0)return getEAWOfCodePoint(n)}var defaultWidths={N:1,Na:1,W:2,F:2,H:1,A:1};function computeWidth(e,t){let n=0;for(let r of e){let e=getEAW(r);n+=t&&t[e]||defaultWidths[e]}return n}var textOffsetY=5,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function isWideChar(e){switch(getEAW(e)){case`F`:case`W`:return!0;default:return!1}}function isMacOS(){return window.navigator.userAgent.indexOf(`Mac OS X`)!==-1}function computeFontSize(e){let t=document.createElement(`canvas`).getContext(`2d`);t.font=e;let n=t.measureText(`W`);return[Math.floor(n.width),Math.round(n.fontBoundingBoxAscent+textOffsetY+(n.emHeightDescent||0)),Math.round(n.fontBoundingBoxAscent+textOffsetY)]}function drawBlock({ctx:e,x:t,y:n,width:r,height:i,style:a}){e.fillStyle=a,e.fillRect(t,n,r,i)}function drawText({ctx:e,x:t,y:n,text:r,font:i,style:a,option:o}){n+=Math.round(textOffsetY),e.fillStyle=a,e.font=i,e.textBaseline=`top`;for(let i of r)isWideChar(i)?(e.fillText(i,t,n,o.fontWidth*2),t+=o.fontWidth*2):(e.fillText(i,t,n,o.fontWidth),t+=o.fontWidth)}function drawHorizontalLine({ctx:e,x:t,y:n,width:r,style:i,lineWidth:a=1}){e.strokeStyle=i,e.lineWidth=a,e.setLineDash=[],e.beginPath(),e.moveTo(t,n),e.lineTo(t+r,n),e.stroke()}var Option=class{constructor({fontName:e,fontSize:t}){this.setFont(e,t),this.foreground=`#cccccc`,this.background=`#2d2d2d`}setFont(e,t){let n=t+`px `+e,[r,i,a]=computeFontSize(n);this.fontName=e,this.fontSize=t,this.fontWidth=r,this.fontHeight=i,this.fontAscent=a,this.font=n}};function getLemEditorElement(){return document.getElementById(`lem-editor`)}function normalizeWheelDelta(e,t,n,r){switch(n){case 0:return{dx:e/r,dy:t/r};case 2:return{dx:e*20,dy:t*20};default:return{dx:e,dy:t}}}function extractWholeLines(e,t){let n=Math.trunc(e),r=Math.trunc(t);return{scrollX:n,scrollY:r,remainderX:e-n,remainderY:t-r}}function cursorPosition(e,t){let[n,r]=t.getDisplayRectangle(),i=e.clientX-n,a=e.clientY-r;return{pixelX:i,pixelY:a,x:Math.floor(i/t.option.fontWidth),y:Math.floor(a/t.option.fontHeight)}}function makeWheelHandler(e){let t={x:0,y:0},n=!1,r={pixelX:0,pixelY:0,x:0,y:0};return i=>{i.preventDefault(),r=cursorPosition(i,e);let{dx:a,dy:o}=normalizeWheelDelta(i.deltaX,i.deltaY,i.deltaMode,e.option.fontHeight);t={x:t.x+a,y:t.y+o},n||(n=!0,requestAnimationFrame(()=>{n=!1;let{scrollX:i,scrollY:a,remainderX:o,remainderY:s}=extractWholeLines(t.x,t.y);t={x:o,y:s},(i!==0||a!==0)&&e.jsonrpc.notify(`input`,{kind:`wheel`,value:{...r,wheelX:-i,wheelY:-a}})}))}}function addMouseEventListeners({dom:e,editor:t,isDraggable:n,draggableStyle:r}){e.addEventListener(`contextmenu`,e=>{e.preventDefault()});let i=(e,n)=>{e.preventDefault();let[r,i]=t.getDisplayRectangle(),a=e.clientX-r,o=e.clientY-i,s=Math.floor(a/t.option.fontWidth),c=Math.floor(o/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:n,value:{x:s,y:c,pixelX:a,pixelY:o,button:e.button,clicks:e.detail}})};e.addEventListener(`mousedown`,e=>{n&&(document.body.style.cursor=r),t.focusHiddenInput(),i(e,`mousedown`)}),e.addEventListener(`mouseup`,e=>{n&&(document.body.style.cursor=`default`),i(e,`mouseup`)});let a=0;e.addEventListener(`mousemove`,e=>{e.preventDefault();let n=Date.now();if(n-a>50){a=n;let[r,i]=t.getDisplayRectangle(),o=e.clientX-r,s=e.clientY-i,c=Math.floor(o/t.option.fontWidth),l=Math.floor(s/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:`mousemove`,value:{x:c,y:l,pixelX:o,pixelY:s,button:e.buttons===0?null:e.buttons-1}})}}),n&&(e.addEventListener(`mouseover`,()=>{document.body.style.cursor=r}),e.addEventListener(`mouseout`,e=>{e.buttons!==1&&(document.body.style.cursor=`default`)})),e.addEventListener(`wheel`,makeWheelHandler(t))}var zIndexTable={"floating-window":200,modeline:100,"vertical-border":100,"horizontal-border":101};function zindex(e){return zIndexTable[e]||0}var borderOffsetX=5,borderOffsetY=10,BaseSurface=class{constructor({editor:e}){this.editor=e,this.mainDOM=null,this.wrapper=null}delete(){this.wrapper?getLemEditorElement().removeChild(this.wrapper):getLemEditorElement().removeChild(this.mainDOM)}setupDOM({dom:e,isFloating:t,border:n,cssClassName:r}){this.mainDOM=e,t&&n?(this.wrapper=document.createElement(`div`),r&&(this.wrapper.className=r),this.wrapper.style.position=`absolute`,this.wrapper.style.backgroundColor=this.editor.option.background,this.wrapper.style.zIndex=zindex(`floating-window`),this.wrapper.appendChild(e),getLemEditorElement().appendChild(this.wrapper)):(r&&(e.className=r),getLemEditorElement().appendChild(e))}move(e,t){let[n,r]=this.editor.getDisplayRectangle(),i=Math.floor(n+e),a=Math.floor(r+t);this.wrapper?(this.wrapper.style.left=i-borderOffsetX+`px`,this.wrapper.style.top=a-borderOffsetY+`px`,this.mainDOM.style.left=borderOffsetX+`px`,this.mainDOM.style.top=borderOffsetY+`px`):(this.mainDOM.style.left=i+`px`,this.mainDOM.style.top=a+`px`)}_resize(e,t){let n=window.devicePixelRatio||1;this.mainDOM.width=e*n,this.mainDOM.height=t*n,this.mainDOM.style.width=e+`px`,this.mainDOM.style.height=t+`px`,this.wrapper&&(this.wrapper.style.width=e+borderOffsetX*2+`px`,this.wrapper.style.height=t+borderOffsetY*2+`px`)}drawBlock(e,t,n,r,i){}drawText(e,t,n,r,i,a,o){}drawImage(e,t,n,r,i){}clearImages(e,t){}clearAllImages(){}touch(){}evalIn(code){return eval(code)}},CanvasSurface=class extends BaseSurface{constructor({editor:e,view:t,pixelX:n,pixelY:r,pixelWidth:i,pixelHeight:a,styles:o,isFloating:s,border:c,cssClassName:l}){super({editor:e});let u=this.setupCanvas(o);this.setupDOM({dom:u,isFloating:s,border:c,cssClassName:l}),this.move(n,r),this.resize(i,a),this.drawingQueue=[],addMouseEventListeners({dom:u,editor:e})}setupCanvas(e){let t=document.createElement(`canvas`);if(t.style.position=`absolute`,e)for(let n in e)t.style[n]=e[n];return t}resize(e,t){this._resize(e,t);let n=window.devicePixelRatio||1;this.mainDOM.getContext(`2d`).scale(n,n)}move(e,t){if(super.move(e,t),this.imageEls)for(let[,e]of this.imageEls)this.positionImage(e)}delete(){this.clearAllImages(),super.delete()}drawBlock(e,t,n,r,i){this.drawingQueue.push(function(a){drawBlock({ctx:a,x:e,y:t,width:n,height:r,style:i})})}drawText(e,t,n,r,i,a,o){let s=this.editor.option,c=o||s.fontHeight;this.drawingQueue.push(function(o){if(a=a?`${s.fontSize}px ${a}`:s.font,!i)drawBlock({ctx:o,x:e,y:t,width:r,height:c,style:s.background}),drawText({ctx:o,x:e,y:t,text:n,style:s.foreground,font:a,option:s});else{let{foreground:l,background:u,bold:d,reverse:f,underline:p,cursor:m}=i;if(l||=s.foreground,u||=s.background,f){let e=u;u=l,l=e}m&&(u=s.background),drawBlock({ctx:o,x:e,y:t,width:r,height:c,style:u}),drawText({ctx:o,x:e,y:t,text:n,style:l,font:d?`bold `+a:a,option:s}),p&&drawHorizontalLine({ctx:o,x:e,y:t+s.fontHeight-2,width:r,style:typeof p==`string`?p:l,lineWidth:2})}})}imageBaseLeft(){return parseFloat(this.mainDOM.style.left)||0}imageBaseTop(){return parseFloat(this.mainDOM.style.top)||0}drawImage(e,t,n,r,i){this.imageEls||=new Map;let a=e+`,`+t,o=this.imageEls.get(a);if(o&&o.url!==i&&(o.el.remove(),this.imageEls.delete(a),o=null),!o){let e=document.createElement(`img`);e.style.position=`absolute`,e.style.pointerEvents=`none`,e.style.zIndex=`1`,e.src=i,this.mainDOM.parentNode.appendChild(e),o={el:e,url:i},this.imageEls.set(a,o)}o.x=e,o.y=t,o.width=n,o.height=r,this.positionImage(o)}positionImage(e){e.el.style.left=this.imageBaseLeft()+e.x+`px`,e.el.style.top=this.imageBaseTop()+e.y+`px`,e.el.style.width=e.width+`px`,e.el.style.height=e.height+`px`}clearImages(e,t){if(this.imageEls)for(let[n,r]of this.imageEls){let i=r.y+(r.height||0);r.ye&&(r.el.remove(),this.imageEls.delete(n))}}clearAllImages(){if(this.imageEls){for(let[,e]of this.imageEls)e.el.remove();this.imageEls.clear()}}touch(){let e=this.mainDOM.getContext(`2d`);for(let t of this.drawingQueue)t(e);this.drawingQueue=[]}activate(){this.mainDOM.dataset.store=`active`}deactivate(){this.mainDOM.dataset.store=`inactive`}},HTMLSurface=class extends BaseSurface{constructor({editor:e,pixelX:t,pixelY:n,pixelWidth:r,pixelHeight:i,styles:a,option:o,isFloating:s,border:c,html:l}){super({editor:e});let u=document.createElement(`iframe`);this.setupDOM({dom:u,isFloating:s,border:c}),u.style.position=`absolute`,u.style.backgroundColor=o.background,u.setAttribute(`sandbox`,`allow-scripts allow-same-origin`),u.srcdoc=l,u.addEventListener(`load`,()=>{let e=u.contentWindow;e.invokeLem=(e,t)=>parent.postMessage({type:`invoke-lem`,method:e,args:t})}),this.iframe=u,this.move(t,n),this.resize(r,i)}resize(e,t){this._resize(e,t)}update(e){let t=this.iframe.contentWindow.scrollY;this.iframe.srcdoc=e,this.iframe.onload=()=>{this.iframe.onload=null,this.iframe.contentWindow.scrollTo(0,t)}}evalIn(e){return this.iframe.contentWindow.eval(e)}},VerticalBorder=class{constructor({x:e,y:t,height:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__vertical-border`,this.line.style.height=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`vertical-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`col-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=Math.floor(n+e-this.option.fontWidth/2)+`px`,this.line.style.top=r+t+`px`}resize(e){this.line.style.height=e+`px`}},HorizontalBorder=class{constructor({x:e,y:t,width:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__horizontal-border`,this.line.style.width=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`horizontal-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`row-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=n+e+`px`,this.line.style.top=Math.floor(r+t-4)+`px`}resize(e){this.line.style.width=e+`px`}},viewStyles={header:()=>{},tile:()=>{},floating:e=>({boxSizing:`border-box`,borderColor:e.foreground,backgroundColor:e.background})};function getViewStyle(e,t){return viewStyles[e](t)||{}}var View=class{constructor({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,option:h,editor:g}){switch(this.option=h,this.id=e,this.x=t,this.y=n,this.width=r,this.height=i,this.pixelX=a,this.pixelY=o,this.pixelWidth=s,this.pixelHeight=c,this.useModeline=l,this.kind=u,this.type=d,this.border=p,this.borderShape=m,this.editor=g,this.bottomBar=null,this.leftsideBar=null,u){case`tile`:this.mainSurface=this.makeSurface(d,f),this.leftSideBar=new VerticalBorder({x:a,y:o,height:c+(l?h.fontHeight:0),option:h,editor:g}),l||(this.bottomBar=new HorizontalBorder({x:a,y:o+c-h.fontHeight,width:s,option:h,editor:g}));break;case`header`:this.mainSurface=this.makeSurface(d,f);break;case`floating`:this.mainSurface=this.makeSurface(d,f),m===`left-border`&&(this.leftSideBar=new VerticalBorder({x:a,y:o,height:c,option:h,editor:g}));break}this.modelineSurface=l?this.makeModelineSurface():null}delete(){this.mainSurface.delete(),this.modelineSurface&&this.modelineSurface.delete(),this.leftSideBar&&this.leftSideBar.delete(),this.bottomBar&&this.bottomBar.delete()}move(e,t,n,r){this.x=e,this.y=t,this.pixelX=n,this.pixelY=r,this.mainSurface.move(n,r),this.modelineSurface&&this.modelineSurface.move(n,r+this.pixelHeight),this.leftSideBar&&this.leftSideBar.move(n,r),this.bottomBar&&this.bottomBar.move(n,r+this.pixelHeight)}resize(e,t,n,r){this.width=e,this.height=t,this.pixelWidth=n,this.pixelHeight=r,this.mainSurface.resize(n,r),this.modelineSurface&&(this.modelineSurface.move(this.pixelX,this.pixelY+r),this.modelineSurface.resize(n,this.option.fontHeight)),this.leftSideBar&&this.leftSideBar.resize(r+(this.modelineSurface?this.option.fontHeight:0)),this.bottomBar&&this.bottomBar.resize(n)}clear(){this.mainSurface.drawBlock(0,0,this.pixelWidth,this.pixelHeight,this.option.background),this.mainSurface.clearImages(0,this.pixelHeight)}clearEol(e,t,n){n??=this.option.fontHeight,this.mainSurface.drawBlock(e,t,this.pixelWidth-e,n,this.option.background),this.mainSurface.clearImages(t,t+n)}clearEob(e,t){this.mainSurface.drawBlock(e,t,this.pixelWidth,this.pixelHeight-t,this.option.background),this.mainSurface.clearImages(t,this.pixelHeight)}print(e,t,n,r,i,a,o){this.mainSurface.drawText(e,t,n,r,i,a,o)}printImage(e,t,n,r,i){this.mainSurface.drawImage(e,t,n,r,i)}printToModeline(e,t,n,r,i,a){this.modelineSurface&&this.modelineSurface.drawText(e,t,n,r,i,null,a)}touch(e){this.mainSurface.touch(),this.modelineSurface&&(this.modelineSurface.touch(),e?this.modelineSurface.activate():this.modelineSurface.deactivate())}makeSurface(e,t){switch(e){case`html`:return this.makeHTMLSurface(t);case`editor`:return this.makeEditorSurface();default:console.error(`unknown type: ${e}`)}}makeHTMLSurface(e){return new HTMLSurface({editor:this.editor,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),option:this.option,isFloating:this.kind===`floating`,border:this.border,html:e})}makeEditorSurface(){let e=this.borderShape===`left-border`?0:this.border,t=this.kind===`floating`;return new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),editor:this.editor,border:e,isFloating:t,view:this,cssClassName:t&&e?`lem-editor__floating-window--bordered`:null})}makeModelineSurface(){let e=new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY+this.pixelHeight,pixelWidth:this.pixelWidth,pixelHeight:this.option.fontHeight,editor:this.editor,view:this,styles:{zIndex:zindex(`modeline`)},cssClassName:`lem-editor__mode-line`});return addMouseEventListeners({dom:e.mainDOM,editor:this.editor,isDraggable:!0,draggableStyle:`row-resize`}),e}changeToHTMLContent(e){this.mainSurface.constructor.name===`HTMLSurface`?this.mainSurface.update(e):(this.mainSurface.delete(),this.mainSurface=this.makeHTMLSurface(e))}changeToEditorContent(){this.mainSurface.delete(),this.mainSurface=this.makeEditorSurface()}evalIn(e){return this.mainSurface.evalIn(e)}};function isPasteKeyEvent(e){return isMacOS()?e.metaKey&&e.key===`v`:e.ctrlKey&&e.shiftKey&&e.key===`V`}var Input=class{constructor(e){let t=e.option;this.editor=e,this.composition=!1,this.ignoreKeydownAfterCompositionend=!1,this.span=document.createElement(`span`),this.span.style.color=t.foreground,this.span.style.backgroundColor=t.background,this.span.style.position=`absolute`,this.span.style.zIndex=1e6,this.span.style.top=`0`,this.span.style.left=`0`,this.span.style.font=t.font,this.input=document.createElement(`input`),this.input.style.backgroundColor=`transparent`,this.input.style.color=`transparent`,this.input.style.width=`0`,this.input.style.padding=`0`,this.input.style.margin=`0`,this.input.style.border=`none`,this.input.style.position=`absolute`,this.input.style.zIndex=`-10`,this.input.style.top=`0`,this.input.style.left=`0`,this.input.style.font=t.font,this.input.addEventListener(`blur`,e=>{this.input.focus()}),this.input.addEventListener(`input`,e=>{this.composition===!1&&(this.input.value=``,this.span.innerHTML=``,this.input.style.width=`0`,isMacOS()||this.editor.emitInputString(e.data))}),this.input.addEventListener(`paste`,async e=>{e.preventDefault();let t=e.clipboardData||window.Clipboard.data,n=t?.getData(`text`)??t?.getData(`text/plain`);if(n&&n.length>0){this.editor.emitInputString(n);return}try{if(navigator.clipboard?.readText){let e=await navigator.clipboard.readText();if(e&&e.length>0){this.editor.emitInputString(e);return}}}catch(e){console.warn(`clipboard.readText() failed:`,e)}alert(`Paste failed (permission/environment restriction`)}),this.input.addEventListener(`keydown`,e=>{if(!isPasteKeyEvent(e)&&!(e.isComposing||this.composition)&&e.key!==`Process`){if(this.ignoreKeydownAfterCompositionend&&(isSafari||isMacOS())){e.preventDefault(),this.ignoreKeydownAfterCompositionend=!1;return}if(!(!isMacOS()&&!e.ctrlKey&&!e.altKey&&e.key.length===1)&&(e.preventDefault(),e.isComposing!==!0&&e.code!==``))return setTimeout(()=>{this.composition||(this.editor.emitInput(e),this.input.value=``)},0),!1}}),this.input.addEventListener(`compositionstart`,e=>{this.composition=!0,this.span.innerHTML=this.input.value,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionupdate`,e=>{this.span.innerHTML=e.data,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionend`,e=>{this.composition=!1,this.editor.emitInputString(this.input.value),this.input.value=``,this.span.innerHTML=this.input.value,this.input.style.width=`0`,this.ignoreKeydownAfterCompositionend=!0}),document.body.appendChild(this.input),document.body.appendChild(this.span),this.input.focus()}finalize(){document.body.removeChild(this.input),document.body.removeChild(this.span)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.span.style.top=r+t+`px`,this.span.style.left=n+e+`px`,this.input.style.top=this.span.offsetTop+`px`,this.input.style.left=this.span.offsetLeft+`px`}updateForeground(e){this.span.style.color=e}updateBackground(e){this.span.style.backgroundColor=e}},MessageTable=class{constructor(){this.map=new Map}register(e,t){for(let n in t){let r=t[n];this.map.set(n,r),e.on(n,r)}}get(e){return this.map.get(e)}};function getDisplayRectangleDefault(){return[0,0,window.innerWidth,window.innerHeight]}var Editor=class{constructor({getDisplayRectangle:e=getDisplayRectangleDefault,fontName:t,fontSize:n,url:r,onExit:i,onClosed:a}){this.getDisplayRectangle=e,this.option=new Option({fontName:t,fontSize:n}),this.onExit=i,this.input=new Input(this),this.cursors=new Map,this.cursorOverlay=document.createElement(`div`),this.cursorOverlay.className=`lem-cursor`,this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.cursorOverlay.style.backgroundColor=`#ffffff`,this.cursorType=`box`,this.viewMap=new Map,this.jsonrpc=new JSONRPC(r,{onClosed:()=>{a()}}),this.messageTable=new MessageTable,this.messageTable.register(this.jsonrpc,{"update-foreground":this.updateForeground.bind(this),"update-background":this.updateBackground.bind(this),"make-view":this.makeView.bind(this),"delete-view":this.deleteView.bind(this),"resize-view":this.resize.bind(this),"move-view":this.move.bind(this),"redraw-view-after":this.redrawViewAfter.bind(this),clear:this.clear.bind(this),"clear-eol":this.clearEol.bind(this),"clear-eob":this.clearEob.bind(this),put:this.put.bind(this),"put-image":this.putImage.bind(this),"modeline-put":this.modelinePut.bind(this),"update-display":this.updateDisplay.bind(this),"move-cursor":this.moveCursor.bind(this),"change-view":this.changeView.bind(this),"resize-display":this.resizeDisplay.bind(this),bulk:this.bulk.bind(this),exit:this.exitEditor.bind(this),"get-clipboard-text":this.getClipboardText.bind(this),"set-clipboard-text":this.setClipboardText.bind(this),"js-eval":this.jsEval.bind(this),"set-font":this.setFont.bind(this),"get-font":this.getFont.bind(this),"get-display-size":this.getDisplaySize.bind(this),"load-css":this.loadCSS.bind(this),"update-cursor-shape":this.updateCursorShape.bind(this)}),this.login(),this.boundedHandleResize=this.handleResize.bind(this),this.focusHiddenInput=this.focusHiddenInput.bind(this)}init(){window.addEventListener(`resize`,this.boundedHandleResize),document.getElementsByTagName(`html`)[0].style[`background-color`]=`#333`,getLemEditorElement().appendChild(this.cursorOverlay)}finalize(){window.removeEventListener(`resize`,this.boundedHandleResize),this.input.finalize(),this.cursorOverlay.parentNode&&this.cursorOverlay.parentNode.removeChild(this.cursorOverlay)}closeConnection(){this.jsonrpc.close()}emitInput(e){let t=convertKeyEvent(e);if(t){if(t.key===`]`&&t.ctrl&&!t.meta&&!t.super&&!t.shift){this.jsonrpc.notify(`input`,{kind:`abort`});return}t.key!==`Unidentified`&&this.jsonrpc.notify(`input`,{kind:`key`,value:t})}}emitInputString(e){e?this.jsonrpc.notify(`input`,{kind:`input-string`,value:e}):console.error(`unexpected argument`,e)}redrawParams(){return{size:this.getDisplaySize(),fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent}}handleResize(e){this.jsonrpc.notify(`redraw`,this.redrawParams())}focusHiddenInput(){let e=this.input?.input;if(e){try{window.focus()}catch{}requestAnimationFrame(()=>{setTimeout(()=>{e.focus({preventScroll:!0})},0)})}}sendNotification(e,t){this.jsonrpc.notify(e,t)}request(e,t,n){this.jsonrpc.request(e,t,n)}getDisplaySize(){let[e,t,n,r]=this.getDisplayRectangle();return{width:Math.floor(n/this.option.fontWidth),height:Math.floor(r/this.option.fontHeight)}}callMessage(e,t){this.messageTable.get(e)(t)}findViewById(e){return this.viewMap.get(e)}login(){this.jsonrpc.request(`login`,{size:this.getDisplaySize(),foreground:this.option.foreground,background:this.option.background,fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent},e=>{if(this.updateForeground(e.foreground),this.updateBackground(e.background),e.views)for(let t of e.views)this.makeView(t);this.jsonrpc.notify(`redraw`,this.redrawParams())})}updateForeground(e){e!=null&&(this.option.foreground=e,this.input.updateForeground(e))}updateBackground(e){if(e==null)return;this.option.background=e,this.input.updateBackground(e);let t=getLemEditorElement();t.style.backgroundColor=e}makeView({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,use_modeline:l,kind:u,type:d,content:f,border:p,border_shape:m}){let h=new View({option:this.option,id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,editor:this});this.viewMap.set(e,h)}deleteView({viewInfo:{id:e}}){this.findViewById(e).delete(),this.viewMap.delete(e)}resize({viewInfo:{id:e},width:t,height:n,pixelWidth:r,pixelHeight:i}){let a=this.findViewById(e);a?a.resize(t,n,r,i):console.warn(`resize: view not found for id ${e}`)}move({viewInfo:{id:e},x:t,y:n,pixelX:r,pixelY:i}){let a=this.findViewById(e);a?a.move(t,n,r,i):console.warn(`move: view not found for id ${e}`)}redrawViewAfter({viewInfo:{id:e},isActive:t}){this.findViewById(e).touch(t)}clear({viewInfo:{id:e}}){this.findViewById(e).clear()}clearEol({viewInfo:{id:e},x:t,y:n,height:r}){this.findViewById(e).clearEol(t,n,r)}clearEob({viewInfo:{id:e},x:t,y:n}){this.findViewById(e).clearEob(t,n)}put({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,font:o,height:s}){this.findViewById(e).print(t,n,r,i,a,o,s)}putImage({viewInfo:{id:e},x:t,y:n,pixelWidth:r,pixelHeight:i,url:a}){this.findViewById(e).printImage(t,n,r,i,a)}modelinePut({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,height:o}){this.findViewById(e).printToModeline(t,n,r,i,a,o)}updateDisplay(){}moveCursor({viewInfo:{id:e},x:t,y:n,color:r,cursorText:i,cursorForeground:a}){let o=this.findViewById(e),[s,c]=this.getDisplayRectangle(),l=o.pixelX+t,u=o.pixelY+n;this.input.move(l,u);let d=r||this.option.foreground,f=a||this.option.background,p=this.cursorOverlay;switch(this.cursorType){case`bar`:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=`2px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;case`underline`:p.style.left=s+l+`px`,p.style.top=c+u+this.option.fontHeight-2+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=`2px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;default:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.style.font=this.option.font,p.style.paddingTop=textOffsetY+`px`,p.textContent=i||``,p.style.color=f;break}p.style.animation=`none`,p.offsetHeight,p.style.animation=``}updateCursorShape({cursorType:e}){this.cursorType=e||`box`}changeView({viewInfo:{id:e},type:t,content:n}){let r=this.findViewById(e);switch(t){case`html`:r.changeToHTMLContent(n);break;case`editor`:r.changeToEditorContent();break}}resizeDisplay({width:e,height:t}){let n=getLemEditorElement();n.style.width=Math.floor(e*this.option.fontWidth)+`px`,n.style.height=Math.floor(t*this.option.fontHeight)+`px`}bulk(e){for(let{method:t,argument:n}of e)this.callMessage(t,n)}exitEditor(){this.onExit&&this.onExit()}getClipboardText(){navigator.clipboard?.readText().then(e=>{this.jsonrpc.notify(`got-clipboard-text`,{text:e})})}setClipboardText({text:e}){navigator.clipboard&&navigator.clipboard.writeText(e)}jsEval({viewInfo:{id:e},code:t}){let n=this.findViewById(e).evalIn(t);return n&&n.toString()}setFont({fontName:e,fontSize:t}){this.option.setFont(e||this.option.fontName,t||this.option.fontSize),this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.jsonrpc.notify(`redraw`,this.redrawParams())}getFont(){return{name:this.option.fontName,size:this.option.fontSize}}loadCSS({content:e}){let t=document.createElement(`style`);t.textContent=e,document.head.appendChild(t)}notifyToServer(e,t){this.jsonrpc.notify(`invoke`,{method:e,args:t})}},canvas=document.querySelector(`#editor`);async function main(){await Promise.all([document.fonts.load(`19px file-icons`),document.fonts.load(`19px AllTheIcons`),document.fonts.load(`19px fontawesome`),document.fonts.load(`19px material-design-icons`),document.fonts.load(`19px octicons`)]),await document.fonts.ready;let e=new Editor({canvas,fontName:`Monospace`,fontSize:18,url:`${window.location.protocol===`https:`?`wss`:`ws`}://${window.location.hostname}:${window.location.port}`,onExit:null,onClosed:null});window.addEventListener(`message`,t=>{t.data.type===`invoke-lem`&&e.notifyToServer(t.data.method,t.data.args)}),e.init()}main(); \ No newline at end of file +var __defProp=Object.defineProperty,__commonJSMin=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),__exportAll=(e,t)=>{let n={};for(var r in e)__defProp(n,r,{get:e[r],enumerable:!0});return t||__defProp(n,Symbol.toStringTag,{value:`Module`}),n};(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var require_models=__commonJSMin((e=>{var t=e&&e.__extends||(function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};return function(t,n){if(typeof n!=`function`&&n!==null)throw TypeError(`Class extends value `+String(n)+` is not a constructor or null`);e(t,n);function r(){this.constructor=t}t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}})();Object.defineProperty(e,"__esModule",{value:!0}),e.createJSONRPCNotification=e.createJSONRPCRequest=e.createJSONRPCSuccessResponse=e.createJSONRPCErrorResponse=e.JSONRPCErrorCode=e.JSONRPCErrorException=e.isJSONRPCResponses=e.isJSONRPCResponse=e.isJSONRPCRequests=e.isJSONRPCRequest=e.isJSONRPCID=e.JSONRPC=void 0,e.JSONRPC=`2.0`,e.isJSONRPCID=function(e){return typeof e==`string`||typeof e==`number`||e===null},e.isJSONRPCRequest=function(t){return t.jsonrpc===e.JSONRPC&&t.method!==void 0&&t.result===void 0&&t.error===void 0},e.isJSONRPCRequests=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCRequest)},e.isJSONRPCResponse=function(t){return t.jsonrpc===e.JSONRPC&&t.id!==void 0&&(t.result!==void 0||t.error!==void 0)},e.isJSONRPCResponses=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCResponse)};var n=function(e,t,n){var r={code:e,message:t};return n!=null&&(r.data=n),r};e.JSONRPCErrorException=function(e){t(r,e);function r(t,n,i){var a=e.call(this,t)||this;return Object.setPrototypeOf(a,r.prototype),a.code=n,a.data=i,a}return r.prototype.toObject=function(){return n(this.code,this.message,this.data)},r}(Error),(function(e){e[e.ParseError=-32700]=`ParseError`,e[e.InvalidRequest=-32600]=`InvalidRequest`,e[e.MethodNotFound=-32601]=`MethodNotFound`,e[e.InvalidParams=-32602]=`InvalidParams`,e[e.InternalError=-32603]=`InternalError`})(e.JSONRPCErrorCode||={}),e.createJSONRPCErrorResponse=function(t,r,i,a){return{jsonrpc:e.JSONRPC,id:t,error:n(r,i,a)}},e.createJSONRPCSuccessResponse=function(t,n){return{jsonrpc:e.JSONRPC,id:t,result:n??null}},e.createJSONRPCRequest=function(t,n,r){return{jsonrpc:e.JSONRPC,id:t,method:n,params:r}},e.createJSONRPCNotification=function(t,n){return{jsonrpc:e.JSONRPC,method:t,params:n}}})),require_internal=__commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.DefaultErrorCode=void 0,e.DefaultErrorCode=0})),require_client=__commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{Object.defineProperty(e,"__esModule",{value:!0})})),require_server=__commonJSMin((e=>{var t=e&&e.__assign||function(){return t=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__createBinding||(Object.create?(function(e,t,n,r){r===void 0&&(r=n);var i=Object.getOwnPropertyDescriptor(t,n);(!i||(`get`in i?!t.__esModule:i.writable||i.configurable))&&(i={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,i)}):(function(e,t,n,r){r===void 0&&(r=n),e[r]=t[n]})),n=e&&e.__exportStar||function(e,n){for(var r in e)r!=="default"&&!Object.prototype.hasOwnProperty.call(n,r)&&t(n,e,r)};Object.defineProperty(e,"__esModule",{value:!0}),n(require_client(),e),n(require_interfaces(),e),n(require_models(),e),n(require_server(),e),n(require_server_and_client(),e)})),import_dist=require_dist(),JSONRPC=class{constructor(e,{onConnected:t,onClosed:n}){this.url=e,this.onConnected=t,this.onClosed=n,this.messageQueue=[],this.serverAndClient=null,this.connect(),this.connectionEstablished=!1,this.timerId=null,this.closed=!1}close(){this.timerId&&clearTimeout(this.timerId),this.webSocket.close(),this.closed=!0}on(e,t){this.serverAndClient.addMethod(e,t)}async requestInternal(e,t,n){let r=await this.serverAndClient.request(e,t);n&&n(r)}requestMessageQueue(){this.messageQueue.forEach(e=>{let[t,n,r]=e;this.requestInternal(t,n,r)}),this.messageQueue=[]}request(e,t,n){this.webSocket.readyState===WebSocket.OPEN?this.requestInternal(e,t,n):this.messageQueue.push([e,t,n])}notify(e,t){switch(this.webSocket.readyState){case WebSocket.OPEN:this.serverAndClient.notify(e,t);break;case WebSocket.CLOSED:break}}connect(e){this.closed||(console.log(`connect`,this.url),this.webSocket=new WebSocket(this.url),this.serverAndClient||=new import_dist.JSONRPCServerAndClient(new import_dist.JSONRPCServer,new import_dist.JSONRPCClient(e=>{try{return this.webSocket.send(JSON.stringify(e)),Promise.resolve()}catch(e){return Promise.reject(e)}})),this.webSocket.onmessage=e=>{this.serverAndClient.receiveAndSend(JSON.parse(e.data.toString()))},this.webSocket.onopen=()=>{console.log(`WebSocket connection established`),this.connectionEstablished=!0,this.onConnected&&this.onConnected(),this.requestMessageQueue()},this.webSocket.onclose=e=>{console.error(`WebScoket closed`,e),this.serverAndClient.rejectAllPendingRequests(`Connection is closed (${e.reason}).`),this.connectionEstablished&&this.onClosed(),this.timerId=setTimeout(()=>{this.connect()},3e3)},this.webSocket.onerror=e=>{console.error(`WebSocket error:`,e),this.webSocket.close()})}},keyevent_exports=__exportAll({convertKeyEvent:()=>convertKeyEvent}),modifierKeys=[`Shift`,`Control`,`Alt`,`Meta`,`CapsLock`],convertKeyTable={Enter:`Return`,ArrowRight:`Right`,ArrowLeft:`Left`,ArrowUp:`Up`,ArrowDown:`Down`,"¡":`1`,"™":`2`,"£":`3`,"¢":`4`,"∞":`5`,"§":`6`,"¶":`7`,"•":`8`,ª:`9`,º:`0`,"–":`-`,"≠":`=`,"“":`[`,"‘":`]`,"«":`\\`,"…":`;`,æ:`'`,"≤":`,`,"≥":`.`,"÷":`/`,"⁄":`!`,"€":`@`,"‹":`#`,"›":`$`,fi:`%`,fl:`^`,"‡":`&`,"°":`*`,"·":`(`,"‚":`)`,"—":`_`,"±":`+`,"”":`{`,"’":`}`,"»":`|`,Ú:`:`,Æ:`"`,"¯":`<`,"˘":`>`,"¿":`?`,œ:`q`,"∑":`w`,"´":`e`,"®":`r`,"†":`t`,"¥":`y`,"¨":`u`,ˆ:`i`,ø:`o`,π:`p`,å:`a`,ß:`s`,"∂":`d`,ƒ:`f`,"©":`g`,"˙":`h`,"∆":`j`,"˚":`k`,"¬":`l`,Ω:`z`,"≈":`x`,ç:`c`,"√":`v`,"∫":`b`,"˜":`n`,µ:`m`,Œ:`Q`,"„":`W`,"´":`E`,"‰":`R`,ˇ:`T`,Á:`Y`,"¨":`U`,ˆ:`I`,Ø:`O`,"∏":`P`,Å:`A`,Í:`S`,Î:`D`,Ï:`F`,"˝":`G`,Ó:`H`,Ô:`J`,"":`K`,Ò:`L`,"¸":`Z`,"˛":`X`,Ç:`C`,"◊":`V`,ı:`B`,"˜":`N`,Â:`M`};function getKey(e){return e.altKey?convertKeyTable[e.key]||(e.code.startsWith(`Key`)?e.code[3].toLowerCase():null)||e.key:convertKeyTable[e.key]||e.key}function convertKeyEvent(e){return modifierKeys.indexOf(e.key)===-1?{key:getKey(e),ctrl:e.ctrlKey,meta:e.altKey,super:e.metaKey,shift:e.shiftKey}:null}var lib_exports=__exportAll({computeWidth:()=>computeWidth,eawVersion:()=>version,getEAW:()=>getEAW}),defs=[[0,31,`N`],[32,126,`Na`],[127,160,`N`],[161,161,`A`],[162,163,`Na`],[164,164,`A`],[165,166,`Na`],[167,168,`A`],[169,169,`N`],[170,170,`A`],[171,171,`N`],[172,172,`Na`],[173,174,`A`],[175,175,`Na`],[176,180,`A`],[181,181,`N`],[182,186,`A`],[187,187,`N`],[188,191,`A`],[192,197,`N`],[198,198,`A`],[199,207,`N`],[208,208,`A`],[209,214,`N`],[215,216,`A`],[217,221,`N`],[222,225,`A`],[226,229,`N`],[230,230,`A`],[231,231,`N`],[232,234,`A`],[235,235,`N`],[236,237,`A`],[238,239,`N`],[240,240,`A`],[241,241,`N`],[242,243,`A`],[244,246,`N`],[247,250,`A`],[251,251,`N`],[252,252,`A`],[253,253,`N`],[254,254,`A`],[255,256,`N`],[257,257,`A`],[258,272,`N`],[273,273,`A`],[274,274,`N`],[275,275,`A`],[276,282,`N`],[283,283,`A`],[284,293,`N`],[294,295,`A`],[296,298,`N`],[299,299,`A`],[300,304,`N`],[305,307,`A`],[308,311,`N`],[312,312,`A`],[313,318,`N`],[319,322,`A`],[323,323,`N`],[324,324,`A`],[325,327,`N`],[328,331,`A`],[332,332,`N`],[333,333,`A`],[334,337,`N`],[338,339,`A`],[340,357,`N`],[358,359,`A`],[360,362,`N`],[363,363,`A`],[364,461,`N`],[462,462,`A`],[463,463,`N`],[464,464,`A`],[465,465,`N`],[466,466,`A`],[467,467,`N`],[468,468,`A`],[469,469,`N`],[470,470,`A`],[471,471,`N`],[472,472,`A`],[473,473,`N`],[474,474,`A`],[475,475,`N`],[476,476,`A`],[477,592,`N`],[593,593,`A`],[594,608,`N`],[609,609,`A`],[610,707,`N`],[708,708,`A`],[709,710,`N`],[711,711,`A`],[712,712,`N`],[713,715,`A`],[716,716,`N`],[717,717,`A`],[718,719,`N`],[720,720,`A`],[721,727,`N`],[728,731,`A`],[732,732,`N`],[733,733,`A`],[734,734,`N`],[735,735,`A`],[736,767,`N`],[768,879,`A`],[880,912,`N`],[913,929,`A`],[930,930,`N`],[931,937,`A`],[938,944,`N`],[945,961,`A`],[962,962,`N`],[963,969,`A`],[970,1024,`N`],[1025,1025,`A`],[1026,1039,`N`],[1040,1103,`A`],[1104,1104,`N`],[1105,1105,`A`],[1106,4351,`N`],[4352,4447,`W`],[4448,8207,`N`],[8208,8208,`A`],[8209,8210,`N`],[8211,8214,`A`],[8215,8215,`N`],[8216,8217,`A`],[8218,8219,`N`],[8220,8221,`A`],[8222,8223,`N`],[8224,8226,`A`],[8227,8227,`N`],[8228,8231,`A`],[8232,8239,`N`],[8240,8240,`A`],[8241,8241,`N`],[8242,8243,`A`],[8244,8244,`N`],[8245,8245,`A`],[8246,8250,`N`],[8251,8251,`A`],[8252,8253,`N`],[8254,8254,`A`],[8255,8307,`N`],[8308,8308,`A`],[8309,8318,`N`],[8319,8319,`A`],[8320,8320,`N`],[8321,8324,`A`],[8325,8360,`N`],[8361,8361,`H`],[8362,8363,`N`],[8364,8364,`A`],[8365,8450,`N`],[8451,8451,`A`],[8452,8452,`N`],[8453,8453,`A`],[8454,8456,`N`],[8457,8457,`A`],[8458,8466,`N`],[8467,8467,`A`],[8468,8469,`N`],[8470,8470,`A`],[8471,8480,`N`],[8481,8482,`A`],[8483,8485,`N`],[8486,8486,`A`],[8487,8490,`N`],[8491,8491,`A`],[8492,8530,`N`],[8531,8532,`A`],[8533,8538,`N`],[8539,8542,`A`],[8543,8543,`N`],[8544,8555,`A`],[8556,8559,`N`],[8560,8569,`A`],[8570,8584,`N`],[8585,8585,`A`],[8586,8591,`N`],[8592,8601,`A`],[8602,8631,`N`],[8632,8633,`A`],[8634,8657,`N`],[8658,8658,`A`],[8659,8659,`N`],[8660,8660,`A`],[8661,8678,`N`],[8679,8679,`A`],[8680,8703,`N`],[8704,8704,`A`],[8705,8705,`N`],[8706,8707,`A`],[8708,8710,`N`],[8711,8712,`A`],[8713,8714,`N`],[8715,8715,`A`],[8716,8718,`N`],[8719,8719,`A`],[8720,8720,`N`],[8721,8721,`A`],[8722,8724,`N`],[8725,8725,`A`],[8726,8729,`N`],[8730,8730,`A`],[8731,8732,`N`],[8733,8736,`A`],[8737,8738,`N`],[8739,8739,`A`],[8740,8740,`N`],[8741,8741,`A`],[8742,8742,`N`],[8743,8748,`A`],[8749,8749,`N`],[8750,8750,`A`],[8751,8755,`N`],[8756,8759,`A`],[8760,8763,`N`],[8764,8765,`A`],[8766,8775,`N`],[8776,8776,`A`],[8777,8779,`N`],[8780,8780,`A`],[8781,8785,`N`],[8786,8786,`A`],[8787,8799,`N`],[8800,8801,`A`],[8802,8803,`N`],[8804,8807,`A`],[8808,8809,`N`],[8810,8811,`A`],[8812,8813,`N`],[8814,8815,`A`],[8816,8833,`N`],[8834,8835,`A`],[8836,8837,`N`],[8838,8839,`A`],[8840,8852,`N`],[8853,8853,`A`],[8854,8856,`N`],[8857,8857,`A`],[8858,8868,`N`],[8869,8869,`A`],[8870,8894,`N`],[8895,8895,`A`],[8896,8977,`N`],[8978,8978,`A`],[8979,8985,`N`],[8986,8987,`W`],[8988,9e3,`N`],[9001,9002,`W`],[9003,9192,`N`],[9193,9196,`W`],[9197,9199,`N`],[9200,9200,`W`],[9201,9202,`N`],[9203,9203,`W`],[9204,9311,`N`],[9312,9449,`A`],[9450,9450,`N`],[9451,9547,`A`],[9548,9551,`N`],[9552,9587,`A`],[9588,9599,`N`],[9600,9615,`A`],[9616,9617,`N`],[9618,9621,`A`],[9622,9631,`N`],[9632,9633,`A`],[9634,9634,`N`],[9635,9641,`A`],[9642,9649,`N`],[9650,9651,`A`],[9652,9653,`N`],[9654,9655,`A`],[9656,9659,`N`],[9660,9661,`A`],[9662,9663,`N`],[9664,9665,`A`],[9666,9669,`N`],[9670,9672,`A`],[9673,9674,`N`],[9675,9675,`A`],[9676,9677,`N`],[9678,9681,`A`],[9682,9697,`N`],[9698,9701,`A`],[9702,9710,`N`],[9711,9711,`A`],[9712,9724,`N`],[9725,9726,`W`],[9727,9732,`N`],[9733,9734,`A`],[9735,9736,`N`],[9737,9737,`A`],[9738,9741,`N`],[9742,9743,`A`],[9744,9747,`N`],[9748,9749,`W`],[9750,9755,`N`],[9756,9756,`A`],[9757,9757,`N`],[9758,9758,`A`],[9759,9791,`N`],[9792,9792,`A`],[9793,9793,`N`],[9794,9794,`A`],[9795,9799,`N`],[9800,9811,`W`],[9812,9823,`N`],[9824,9825,`A`],[9826,9826,`N`],[9827,9829,`A`],[9830,9830,`N`],[9831,9834,`A`],[9835,9835,`N`],[9836,9837,`A`],[9838,9838,`N`],[9839,9839,`A`],[9840,9854,`N`],[9855,9855,`W`],[9856,9874,`N`],[9875,9875,`W`],[9876,9885,`N`],[9886,9887,`A`],[9888,9888,`N`],[9889,9889,`W`],[9890,9897,`N`],[9898,9899,`W`],[9900,9916,`N`],[9917,9918,`W`],[9919,9919,`A`],[9920,9923,`N`],[9924,9925,`W`],[9926,9933,`A`],[9934,9934,`W`],[9935,9939,`A`],[9940,9940,`W`],[9941,9953,`A`],[9954,9954,`N`],[9955,9955,`A`],[9956,9959,`N`],[9960,9961,`A`],[9962,9962,`W`],[9963,9969,`A`],[9970,9971,`W`],[9972,9972,`A`],[9973,9973,`W`],[9974,9977,`A`],[9978,9978,`W`],[9979,9980,`A`],[9981,9981,`W`],[9982,9983,`A`],[9984,9988,`N`],[9989,9989,`W`],[9990,9993,`N`],[9994,9995,`W`],[9996,10023,`N`],[10024,10024,`W`],[10025,10044,`N`],[10045,10045,`A`],[10046,10059,`N`],[10060,10060,`W`],[10061,10061,`N`],[10062,10062,`W`],[10063,10066,`N`],[10067,10069,`W`],[10070,10070,`N`],[10071,10071,`W`],[10072,10101,`N`],[10102,10111,`A`],[10112,10132,`N`],[10133,10135,`W`],[10136,10159,`N`],[10160,10160,`W`],[10161,10174,`N`],[10175,10175,`W`],[10176,10213,`N`],[10214,10221,`Na`],[10222,10628,`N`],[10629,10630,`Na`],[10631,11034,`N`],[11035,11036,`W`],[11037,11087,`N`],[11088,11088,`W`],[11089,11092,`N`],[11093,11093,`W`],[11094,11097,`A`],[11098,11903,`N`],[11904,11929,`W`],[11930,11930,`N`],[11931,12019,`W`],[12020,12031,`N`],[12032,12245,`W`],[12246,12271,`N`],[12272,12287,`W`],[12288,12288,`F`],[12289,12350,`W`],[12351,12352,`N`],[12353,12438,`W`],[12439,12440,`N`],[12441,12543,`W`],[12544,12548,`N`],[12549,12591,`W`],[12592,12592,`N`],[12593,12686,`W`],[12687,12687,`N`],[12688,12771,`W`],[12772,12782,`N`],[12783,12830,`W`],[12831,12831,`N`],[12832,12871,`W`],[12872,12879,`A`],[12880,19903,`W`],[19904,19967,`N`],[19968,42124,`W`],[42125,42127,`N`],[42128,42182,`W`],[42183,43359,`N`],[43360,43388,`W`],[43389,44031,`N`],[44032,55203,`W`],[55204,57343,`N`],[57344,63743,`A`],[63744,64255,`W`],[64256,65023,`N`],[65024,65039,`A`],[65040,65049,`W`],[65050,65071,`N`],[65072,65106,`W`],[65107,65107,`N`],[65108,65126,`W`],[65127,65127,`N`],[65128,65131,`W`],[65132,65280,`N`],[65281,65376,`F`],[65377,65470,`H`],[65471,65473,`N`],[65474,65479,`H`],[65480,65481,`N`],[65482,65487,`H`],[65488,65489,`N`],[65490,65495,`H`],[65496,65497,`N`],[65498,65500,`H`],[65501,65503,`N`],[65504,65510,`F`],[65511,65511,`N`],[65512,65518,`H`],[65519,65532,`N`],[65533,65533,`A`],[65534,94175,`N`],[94176,94180,`W`],[94181,94191,`N`],[94192,94193,`W`],[94194,94207,`N`],[94208,100343,`W`],[100344,100351,`N`],[100352,101589,`W`],[101590,101631,`N`],[101632,101640,`W`],[101641,110575,`N`],[110576,110579,`W`],[110580,110580,`N`],[110581,110587,`W`],[110588,110588,`N`],[110589,110590,`W`],[110591,110591,`N`],[110592,110882,`W`],[110883,110897,`N`],[110898,110898,`W`],[110899,110927,`N`],[110928,110930,`W`],[110931,110932,`N`],[110933,110933,`W`],[110934,110947,`N`],[110948,110951,`W`],[110952,110959,`N`],[110960,111355,`W`],[111356,126979,`N`],[126980,126980,`W`],[126981,127182,`N`],[127183,127183,`W`],[127184,127231,`N`],[127232,127242,`A`],[127243,127247,`N`],[127248,127277,`A`],[127278,127279,`N`],[127280,127337,`A`],[127338,127343,`N`],[127344,127373,`A`],[127374,127374,`W`],[127375,127376,`A`],[127377,127386,`W`],[127387,127404,`A`],[127405,127487,`N`],[127488,127490,`W`],[127491,127503,`N`],[127504,127547,`W`],[127548,127551,`N`],[127552,127560,`W`],[127561,127567,`N`],[127568,127569,`W`],[127570,127583,`N`],[127584,127589,`W`],[127590,127743,`N`],[127744,127776,`W`],[127777,127788,`N`],[127789,127797,`W`],[127798,127798,`N`],[127799,127868,`W`],[127869,127869,`N`],[127870,127891,`W`],[127892,127903,`N`],[127904,127946,`W`],[127947,127950,`N`],[127951,127955,`W`],[127956,127967,`N`],[127968,127984,`W`],[127985,127987,`N`],[127988,127988,`W`],[127989,127991,`N`],[127992,128062,`W`],[128063,128063,`N`],[128064,128064,`W`],[128065,128065,`N`],[128066,128252,`W`],[128253,128254,`N`],[128255,128317,`W`],[128318,128330,`N`],[128331,128334,`W`],[128335,128335,`N`],[128336,128359,`W`],[128360,128377,`N`],[128378,128378,`W`],[128379,128404,`N`],[128405,128406,`W`],[128407,128419,`N`],[128420,128420,`W`],[128421,128506,`N`],[128507,128591,`W`],[128592,128639,`N`],[128640,128709,`W`],[128710,128715,`N`],[128716,128716,`W`],[128717,128719,`N`],[128720,128722,`W`],[128723,128724,`N`],[128725,128727,`W`],[128728,128731,`N`],[128732,128735,`W`],[128736,128746,`N`],[128747,128748,`W`],[128749,128755,`N`],[128756,128764,`W`],[128765,128991,`N`],[128992,129003,`W`],[129004,129007,`N`],[129008,129008,`W`],[129009,129291,`N`],[129292,129338,`W`],[129339,129339,`N`],[129340,129349,`W`],[129350,129350,`N`],[129351,129535,`W`],[129536,129647,`N`],[129648,129660,`W`],[129661,129663,`N`],[129664,129672,`W`],[129673,129679,`N`],[129680,129725,`W`],[129726,129726,`N`],[129727,129733,`W`],[129734,129741,`N`],[129742,129755,`W`],[129756,129759,`N`],[129760,129768,`W`],[129769,129775,`N`],[129776,129784,`W`],[129785,131071,`N`],[131072,196605,`W`],[196606,196607,`N`],[196608,262141,`W`],[262142,917759,`N`],[917760,917999,`A`],[918e3,983039,`N`],[983040,1048573,`A`],[1048574,1048575,`N`],[1048576,1114109,`A`],[1114110,1114111,`N`]],version=`15.1.0`;function getEAWOfCodePoint(e){let t=0,n=defs.length-1;for(;t!==n;){let r=t+(n-t>>1),[i,a,o]=defs[r];if(ea)t=r+1;else return o}return defs[t][2]}function getEAW(e,t=0){let n=e.codePointAt(t);if(n!==void 0)return getEAWOfCodePoint(n)}var defaultWidths={N:1,Na:1,W:2,F:2,H:1,A:1};function computeWidth(e,t){let n=0;for(let r of e){let e=getEAW(r);n+=t&&t[e]||defaultWidths[e]}return n}var textOffsetY=5,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function isWideChar(e){switch(getEAW(e)){case`F`:case`W`:return!0;default:return!1}}function isMacOS(){return window.navigator.userAgent.indexOf(`Mac OS X`)!==-1}function computeFontSize(e){let t=document.createElement(`canvas`).getContext(`2d`);t.font=e;let n=t.measureText(`W`);return[Math.floor(n.width),Math.round(n.fontBoundingBoxAscent+textOffsetY+(n.emHeightDescent||0)),Math.round(n.fontBoundingBoxAscent+textOffsetY)]}function drawBlock({ctx:e,x:t,y:n,width:r,height:i,style:a}){e.fillStyle=a,e.fillRect(t,n,r,i)}function drawText({ctx:e,x:t,y:n,text:r,font:i,style:a,option:o}){n+=Math.round(textOffsetY),e.fillStyle=a,e.font=i,e.textBaseline=`top`;for(let i of r)isWideChar(i)?(e.fillText(i,t,n,o.fontWidth*2),t+=o.fontWidth*2):(e.fillText(i,t,n,o.fontWidth),t+=o.fontWidth)}function drawHorizontalLine({ctx:e,x:t,y:n,width:r,style:i,lineWidth:a=1}){e.strokeStyle=i,e.lineWidth=a,e.setLineDash=[],e.beginPath(),e.moveTo(t,n),e.lineTo(t+r,n),e.stroke()}var Option=class{constructor({fontName:e,fontSize:t}){this.setFont(e,t),this.foreground=`#cccccc`,this.background=`#2d2d2d`}setFont(e,t){let n=t+`px `+e,[r,i,a]=computeFontSize(n);this.fontName=e,this.fontSize=t,this.fontWidth=r,this.fontHeight=i,this.fontAscent=a,this.font=n}};function getLemEditorElement(){return document.getElementById(`lem-editor`)}function normalizeWheelDelta(e,t,n,r){switch(n){case 0:return{dx:e/r,dy:t/r};case 2:return{dx:e*20,dy:t*20};default:return{dx:e,dy:t}}}function extractWholeLines(e,t){let n=Math.trunc(e),r=Math.trunc(t);return{scrollX:n,scrollY:r,remainderX:e-n,remainderY:t-r}}function cursorPosition(e,t){let[n,r]=t.getDisplayRectangle(),i=e.clientX-n,a=e.clientY-r;return{pixelX:i,pixelY:a,x:Math.floor(i/t.option.fontWidth),y:Math.floor(a/t.option.fontHeight)}}function makeWheelHandler(e){let t={x:0,y:0},n=!1,r={pixelX:0,pixelY:0,x:0,y:0};return i=>{i.preventDefault(),r=cursorPosition(i,e);let{dx:a,dy:o}=normalizeWheelDelta(i.deltaX,i.deltaY,i.deltaMode,e.option.fontHeight);t={x:t.x+a,y:t.y+o},n||(n=!0,requestAnimationFrame(()=>{n=!1;let{scrollX:i,scrollY:a,remainderX:o,remainderY:s}=extractWholeLines(t.x,t.y);t={x:o,y:s},(i!==0||a!==0)&&e.jsonrpc.notify(`input`,{kind:`wheel`,value:{...r,wheelX:-i,wheelY:-a}})}))}}function addMouseEventListeners({dom:e,editor:t,isDraggable:n,draggableStyle:r}){e.addEventListener(`contextmenu`,e=>{e.preventDefault()});let i=(e,n)=>{e.preventDefault();let[r,i]=t.getDisplayRectangle(),a=e.clientX-r,o=e.clientY-i,s=Math.floor(a/t.option.fontWidth),c=Math.floor(o/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:n,value:{x:s,y:c,pixelX:a,pixelY:o,button:e.button,clicks:e.detail}})};e.addEventListener(`mousedown`,e=>{n&&(document.body.style.cursor=r),t.focusHiddenInput(),i(e,`mousedown`)}),e.addEventListener(`mouseup`,e=>{n&&(document.body.style.cursor=`default`),i(e,`mouseup`)});let a=0;e.addEventListener(`mousemove`,e=>{e.preventDefault();let n=Date.now();if(n-a>50){a=n;let[r,i]=t.getDisplayRectangle(),o=e.clientX-r,s=e.clientY-i,c=Math.floor(o/t.option.fontWidth),l=Math.floor(s/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:`mousemove`,value:{x:c,y:l,pixelX:o,pixelY:s,button:e.buttons===0?null:e.buttons-1}})}}),n&&(e.addEventListener(`mouseover`,()=>{document.body.style.cursor=r}),e.addEventListener(`mouseout`,e=>{e.buttons!==1&&(document.body.style.cursor=`default`)})),e.addEventListener(`wheel`,makeWheelHandler(t))}var zIndexTable={"floating-window":200,modeline:100,"vertical-border":100,"horizontal-border":101};function zindex(e){return zIndexTable[e]||0}var borderOffsetX=5,borderOffsetY=10,BaseSurface=class{constructor({editor:e}){this.editor=e,this.mainDOM=null,this.wrapper=null}delete(){this.wrapper?getLemEditorElement().removeChild(this.wrapper):getLemEditorElement().removeChild(this.mainDOM)}setupDOM({dom:e,isFloating:t,border:n,cssClassName:r}){this.mainDOM=e,t&&n?(this.wrapper=document.createElement(`div`),r&&(this.wrapper.className=r),this.wrapper.style.position=`absolute`,this.wrapper.style.backgroundColor=this.editor.option.background,this.wrapper.style.zIndex=zindex(`floating-window`),this.wrapper.appendChild(e),getLemEditorElement().appendChild(this.wrapper)):(r&&(e.className=r),getLemEditorElement().appendChild(e))}move(e,t){let[n,r]=this.editor.getDisplayRectangle(),i=Math.floor(n+e),a=Math.floor(r+t);this.wrapper?(this.wrapper.style.left=i-borderOffsetX+`px`,this.wrapper.style.top=a-borderOffsetY+`px`,this.mainDOM.style.left=borderOffsetX+`px`,this.mainDOM.style.top=borderOffsetY+`px`):(this.mainDOM.style.left=i+`px`,this.mainDOM.style.top=a+`px`)}_resize(e,t){let n=window.devicePixelRatio||1;this.mainDOM.width=e*n,this.mainDOM.height=t*n,this.mainDOM.style.width=e+`px`,this.mainDOM.style.height=t+`px`,this.wrapper&&(this.wrapper.style.width=e+borderOffsetX*2+`px`,this.wrapper.style.height=t+borderOffsetY*2+`px`)}drawBlock(e,t,n,r,i){}drawText(e,t,n,r,i,a,o){}drawImage(e,t,n,r,i,a,o){}clearImages(e,t){}clearAllImages(){}touch(){}evalIn(code){return eval(code)}},CanvasSurface=class extends BaseSurface{constructor({editor:e,view:t,pixelX:n,pixelY:r,pixelWidth:i,pixelHeight:a,styles:o,isFloating:s,border:c,cssClassName:l}){super({editor:e});let u=this.setupCanvas(o);this.setupDOM({dom:u,isFloating:s,border:c,cssClassName:l}),this.move(n,r),this.resize(i,a),this.drawingQueue=[],addMouseEventListeners({dom:u,editor:e})}setupCanvas(e){let t=document.createElement(`canvas`);if(t.style.position=`absolute`,e)for(let n in e)t.style[n]=e[n];return t}resize(e,t){this._resize(e,t);let n=window.devicePixelRatio||1;this.mainDOM.getContext(`2d`).scale(n,n)}move(e,t){if(super.move(e,t),this.imageEls)for(let[,e]of this.imageEls)this.positionImage(e)}delete(){this.clearAllImages(),super.delete()}drawBlock(e,t,n,r,i){this.drawingQueue.push(function(a){drawBlock({ctx:a,x:e,y:t,width:n,height:r,style:i})})}drawText(e,t,n,r,i,a,o){let s=this.editor.option,c=o||s.fontHeight;this.drawingQueue.push(function(o){if(a=a?`${s.fontSize}px ${a}`:s.font,!i)drawBlock({ctx:o,x:e,y:t,width:r,height:c,style:s.background}),drawText({ctx:o,x:e,y:t,text:n,style:s.foreground,font:a,option:s});else{let{foreground:l,background:u,bold:d,reverse:f,underline:p,cursor:m}=i;if(l||=s.foreground,u||=s.background,f){let e=u;u=l,l=e}m&&(u=s.background),drawBlock({ctx:o,x:e,y:t,width:r,height:c,style:u}),drawText({ctx:o,x:e,y:t,text:n,style:l,font:d?`bold `+a:a,option:s}),p&&drawHorizontalLine({ctx:o,x:e,y:t+s.fontHeight-2,width:r,style:typeof p==`string`?p:l,lineWidth:2})}})}imageBaseLeft(){return parseFloat(this.mainDOM.style.left)||0}imageBaseTop(){return parseFloat(this.mainDOM.style.top)||0}drawImage(e,t,n,r,i,a,o){this.imageEls||=new Map;let s=e+`,`+t,c=this.imageEls.get(s);if(c&&c.url!==o&&(c.el.remove(),this.imageEls.delete(s),c=null),!c){let e=document.createElement(`img`);e.style.position=`absolute`,e.style.pointerEvents=`none`,e.style.zIndex=`1`,e.src=o,this.mainDOM.parentNode.appendChild(e),c={el:e,url:o},this.imageEls.set(s,c)}c.x=e,c.y=t,c.width=n,c.height=r,c.clipWidth=i,c.clipHeight=a,this.positionImage(c)}positionImage(e){e.el.style.left=this.imageBaseLeft()+e.x+`px`,e.el.style.top=this.imageBaseTop()+e.y+`px`,e.el.style.width=e.width+`px`,e.el.style.height=e.height+`px`;let t=e.clipWidth==null?0:Math.max(0,e.width-e.clipWidth),n=e.clipHeight==null?0:Math.max(0,e.height-e.clipHeight);e.el.style.clipPath=t>0||n>0?`inset(0px ${t}px ${n}px 0px)`:``}clearImages(e,t){if(this.imageEls)for(let[n,r]of this.imageEls){let i=r.y+(r.height||0);r.ye&&(r.el.remove(),this.imageEls.delete(n))}}clearAllImages(){if(this.imageEls){for(let[,e]of this.imageEls)e.el.remove();this.imageEls.clear()}}touch(){let e=this.mainDOM.getContext(`2d`);for(let t of this.drawingQueue)t(e);this.drawingQueue=[]}activate(){this.mainDOM.dataset.store=`active`}deactivate(){this.mainDOM.dataset.store=`inactive`}},HTMLSurface=class extends BaseSurface{constructor({editor:e,pixelX:t,pixelY:n,pixelWidth:r,pixelHeight:i,styles:a,option:o,isFloating:s,border:c,html:l}){super({editor:e});let u=document.createElement(`iframe`);this.setupDOM({dom:u,isFloating:s,border:c}),u.style.position=`absolute`,u.style.backgroundColor=o.background,u.setAttribute(`sandbox`,`allow-scripts allow-same-origin`),u.srcdoc=l,u.addEventListener(`load`,()=>{let e=u.contentWindow;e.invokeLem=(e,t)=>parent.postMessage({type:`invoke-lem`,method:e,args:t})}),this.iframe=u,this.move(t,n),this.resize(r,i)}resize(e,t){this._resize(e,t)}update(e){let t=this.iframe.contentWindow.scrollY;this.iframe.srcdoc=e,this.iframe.onload=()=>{this.iframe.onload=null,this.iframe.contentWindow.scrollTo(0,t)}}evalIn(e){return this.iframe.contentWindow.eval(e)}},VerticalBorder=class{constructor({x:e,y:t,height:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__vertical-border`,this.line.style.height=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`vertical-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`col-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=Math.floor(n+e-this.option.fontWidth/2)+`px`,this.line.style.top=r+t+`px`}resize(e){this.line.style.height=e+`px`}},HorizontalBorder=class{constructor({x:e,y:t,width:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__horizontal-border`,this.line.style.width=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`horizontal-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`row-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=n+e+`px`,this.line.style.top=Math.floor(r+t-4)+`px`}resize(e){this.line.style.width=e+`px`}},viewStyles={header:()=>{},tile:()=>{},floating:e=>({boxSizing:`border-box`,borderColor:e.foreground,backgroundColor:e.background})};function getViewStyle(e,t){return viewStyles[e](t)||{}}var View=class{constructor({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,option:h,editor:g}){switch(this.option=h,this.id=e,this.x=t,this.y=n,this.width=r,this.height=i,this.pixelX=a,this.pixelY=o,this.pixelWidth=s,this.pixelHeight=c,this.useModeline=l,this.kind=u,this.type=d,this.border=p,this.borderShape=m,this.editor=g,this.bottomBar=null,this.leftsideBar=null,u){case`tile`:this.mainSurface=this.makeSurface(d,f),this.leftSideBar=new VerticalBorder({x:a,y:o,height:c+(l?h.fontHeight:0),option:h,editor:g}),l||(this.bottomBar=new HorizontalBorder({x:a,y:o+c-h.fontHeight,width:s,option:h,editor:g}));break;case`header`:this.mainSurface=this.makeSurface(d,f);break;case`floating`:this.mainSurface=this.makeSurface(d,f),m===`left-border`&&(this.leftSideBar=new VerticalBorder({x:a,y:o,height:c,option:h,editor:g}));break}this.modelineSurface=l?this.makeModelineSurface():null}delete(){this.mainSurface.delete(),this.modelineSurface&&this.modelineSurface.delete(),this.leftSideBar&&this.leftSideBar.delete(),this.bottomBar&&this.bottomBar.delete()}move(e,t,n,r){this.x=e,this.y=t,this.pixelX=n,this.pixelY=r,this.mainSurface.move(n,r),this.modelineSurface&&this.modelineSurface.move(n,r+this.pixelHeight),this.leftSideBar&&this.leftSideBar.move(n,r),this.bottomBar&&this.bottomBar.move(n,r+this.pixelHeight)}resize(e,t,n,r){this.width=e,this.height=t,this.pixelWidth=n,this.pixelHeight=r,this.mainSurface.resize(n,r),this.modelineSurface&&(this.modelineSurface.move(this.pixelX,this.pixelY+r),this.modelineSurface.resize(n,this.option.fontHeight)),this.leftSideBar&&this.leftSideBar.resize(r+(this.modelineSurface?this.option.fontHeight:0)),this.bottomBar&&this.bottomBar.resize(n)}clear(){this.mainSurface.drawBlock(0,0,this.pixelWidth,this.pixelHeight,this.option.background),this.mainSurface.clearImages(0,this.pixelHeight)}clearEol(e,t,n){n??=this.option.fontHeight,this.mainSurface.drawBlock(e,t,this.pixelWidth-e,n,this.option.background),this.mainSurface.clearImages(t,t+n)}clearEob(e,t){this.mainSurface.drawBlock(e,t,this.pixelWidth,this.pixelHeight-t,this.option.background),this.mainSurface.clearImages(t,this.pixelHeight)}print(e,t,n,r,i,a,o){this.mainSurface.drawText(e,t,n,r,i,a,o)}printImage(e,t,n,r,i,a,o){this.mainSurface.drawImage(e,t,n,r,i,a,o)}printToModeline(e,t,n,r,i,a){this.modelineSurface&&this.modelineSurface.drawText(e,t,n,r,i,null,a)}touch(e){this.mainSurface.touch(),this.modelineSurface&&(this.modelineSurface.touch(),e?this.modelineSurface.activate():this.modelineSurface.deactivate())}makeSurface(e,t){switch(e){case`html`:return this.makeHTMLSurface(t);case`editor`:return this.makeEditorSurface();default:console.error(`unknown type: ${e}`)}}makeHTMLSurface(e){return new HTMLSurface({editor:this.editor,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),option:this.option,isFloating:this.kind===`floating`,border:this.border,html:e})}makeEditorSurface(){let e=this.borderShape===`left-border`?0:this.border,t=this.kind===`floating`;return new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),editor:this.editor,border:e,isFloating:t,view:this,cssClassName:t&&e?`lem-editor__floating-window--bordered`:null})}makeModelineSurface(){let e=new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY+this.pixelHeight,pixelWidth:this.pixelWidth,pixelHeight:this.option.fontHeight,editor:this.editor,view:this,styles:{zIndex:zindex(`modeline`)},cssClassName:`lem-editor__mode-line`});return addMouseEventListeners({dom:e.mainDOM,editor:this.editor,isDraggable:!0,draggableStyle:`row-resize`}),e}changeToHTMLContent(e){this.mainSurface.constructor.name===`HTMLSurface`?this.mainSurface.update(e):(this.mainSurface.delete(),this.mainSurface=this.makeHTMLSurface(e))}changeToEditorContent(){this.mainSurface.delete(),this.mainSurface=this.makeEditorSurface()}evalIn(e){return this.mainSurface.evalIn(e)}};function isPasteKeyEvent(e){return isMacOS()?e.metaKey&&e.key===`v`:e.ctrlKey&&e.shiftKey&&e.key===`V`}var Input=class{constructor(e){let t=e.option;this.editor=e,this.composition=!1,this.ignoreKeydownAfterCompositionend=!1,this.span=document.createElement(`span`),this.span.style.color=t.foreground,this.span.style.backgroundColor=t.background,this.span.style.position=`absolute`,this.span.style.zIndex=1e6,this.span.style.top=`0`,this.span.style.left=`0`,this.span.style.font=t.font,this.input=document.createElement(`input`),this.input.style.backgroundColor=`transparent`,this.input.style.color=`transparent`,this.input.style.width=`0`,this.input.style.padding=`0`,this.input.style.margin=`0`,this.input.style.border=`none`,this.input.style.position=`absolute`,this.input.style.zIndex=`-10`,this.input.style.top=`0`,this.input.style.left=`0`,this.input.style.font=t.font,this.input.addEventListener(`blur`,e=>{this.input.focus()}),this.input.addEventListener(`input`,e=>{this.composition===!1&&(this.input.value=``,this.span.innerHTML=``,this.input.style.width=`0`,isMacOS()||this.editor.emitInputString(e.data))}),this.input.addEventListener(`paste`,async e=>{e.preventDefault();let t=e.clipboardData||window.Clipboard.data,n=t?.getData(`text`)??t?.getData(`text/plain`);if(n&&n.length>0){this.editor.emitInputString(n);return}try{if(navigator.clipboard?.readText){let e=await navigator.clipboard.readText();if(e&&e.length>0){this.editor.emitInputString(e);return}}}catch(e){console.warn(`clipboard.readText() failed:`,e)}alert(`Paste failed (permission/environment restriction`)}),this.input.addEventListener(`keydown`,e=>{if(!isPasteKeyEvent(e)&&!(e.isComposing||this.composition)&&e.key!==`Process`){if(this.ignoreKeydownAfterCompositionend&&(isSafari||isMacOS())){e.preventDefault(),this.ignoreKeydownAfterCompositionend=!1;return}if(!(!isMacOS()&&!e.ctrlKey&&!e.altKey&&e.key.length===1)&&(e.preventDefault(),e.isComposing!==!0&&e.code!==``))return setTimeout(()=>{this.composition||(this.editor.emitInput(e),this.input.value=``)},0),!1}}),this.input.addEventListener(`compositionstart`,e=>{this.composition=!0,this.span.innerHTML=this.input.value,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionupdate`,e=>{this.span.innerHTML=e.data,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionend`,e=>{this.composition=!1,this.editor.emitInputString(this.input.value),this.input.value=``,this.span.innerHTML=this.input.value,this.input.style.width=`0`,this.ignoreKeydownAfterCompositionend=!0}),document.body.appendChild(this.input),document.body.appendChild(this.span),this.input.focus()}finalize(){document.body.removeChild(this.input),document.body.removeChild(this.span)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.span.style.top=r+t+`px`,this.span.style.left=n+e+`px`,this.input.style.top=this.span.offsetTop+`px`,this.input.style.left=this.span.offsetLeft+`px`}updateForeground(e){this.span.style.color=e}updateBackground(e){this.span.style.backgroundColor=e}},MessageTable=class{constructor(){this.map=new Map}register(e,t){for(let n in t){let r=t[n];this.map.set(n,r),e.on(n,r)}}get(e){return this.map.get(e)}};function getDisplayRectangleDefault(){return[0,0,window.innerWidth,window.innerHeight]}var Editor=class{constructor({getDisplayRectangle:e=getDisplayRectangleDefault,fontName:t,fontSize:n,url:r,onExit:i,onClosed:a}){this.getDisplayRectangle=e,this.option=new Option({fontName:t,fontSize:n}),this.onExit=i,this.input=new Input(this),this.cursors=new Map,this.cursorOverlay=document.createElement(`div`),this.cursorOverlay.className=`lem-cursor`,this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.cursorOverlay.style.backgroundColor=`#ffffff`,this.cursorType=`box`,this.viewMap=new Map,this.jsonrpc=new JSONRPC(r,{onClosed:()=>{a()}}),this.messageTable=new MessageTable,this.messageTable.register(this.jsonrpc,{"update-foreground":this.updateForeground.bind(this),"update-background":this.updateBackground.bind(this),"make-view":this.makeView.bind(this),"delete-view":this.deleteView.bind(this),"resize-view":this.resize.bind(this),"move-view":this.move.bind(this),"redraw-view-after":this.redrawViewAfter.bind(this),clear:this.clear.bind(this),"clear-eol":this.clearEol.bind(this),"clear-eob":this.clearEob.bind(this),put:this.put.bind(this),"put-image":this.putImage.bind(this),"modeline-put":this.modelinePut.bind(this),"update-display":this.updateDisplay.bind(this),"move-cursor":this.moveCursor.bind(this),"change-view":this.changeView.bind(this),"resize-display":this.resizeDisplay.bind(this),bulk:this.bulk.bind(this),exit:this.exitEditor.bind(this),"get-clipboard-text":this.getClipboardText.bind(this),"set-clipboard-text":this.setClipboardText.bind(this),"js-eval":this.jsEval.bind(this),"set-font":this.setFont.bind(this),"get-font":this.getFont.bind(this),"get-display-size":this.getDisplaySize.bind(this),"load-css":this.loadCSS.bind(this),"update-cursor-shape":this.updateCursorShape.bind(this)}),this.login(),this.boundedHandleResize=this.handleResize.bind(this),this.focusHiddenInput=this.focusHiddenInput.bind(this)}init(){window.addEventListener(`resize`,this.boundedHandleResize),document.getElementsByTagName(`html`)[0].style[`background-color`]=`#333`,getLemEditorElement().appendChild(this.cursorOverlay)}finalize(){window.removeEventListener(`resize`,this.boundedHandleResize),this.input.finalize(),this.cursorOverlay.parentNode&&this.cursorOverlay.parentNode.removeChild(this.cursorOverlay)}closeConnection(){this.jsonrpc.close()}emitInput(e){let t=convertKeyEvent(e);if(t){if(t.key===`]`&&t.ctrl&&!t.meta&&!t.super&&!t.shift){this.jsonrpc.notify(`input`,{kind:`abort`});return}t.key!==`Unidentified`&&this.jsonrpc.notify(`input`,{kind:`key`,value:t})}}emitInputString(e){e?this.jsonrpc.notify(`input`,{kind:`input-string`,value:e}):console.error(`unexpected argument`,e)}redrawParams(){return{size:this.getDisplaySize(),fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent}}handleResize(e){this.jsonrpc.notify(`redraw`,this.redrawParams())}focusHiddenInput(){let e=this.input?.input;if(e){try{window.focus()}catch{}requestAnimationFrame(()=>{setTimeout(()=>{e.focus({preventScroll:!0})},0)})}}sendNotification(e,t){this.jsonrpc.notify(e,t)}request(e,t,n){this.jsonrpc.request(e,t,n)}getDisplaySize(){let[e,t,n,r]=this.getDisplayRectangle();return{width:Math.floor(n/this.option.fontWidth),height:Math.floor(r/this.option.fontHeight)}}callMessage(e,t){this.messageTable.get(e)(t)}findViewById(e){return this.viewMap.get(e)}login(){this.jsonrpc.request(`login`,{size:this.getDisplaySize(),foreground:this.option.foreground,background:this.option.background,fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent},e=>{if(this.updateForeground(e.foreground),this.updateBackground(e.background),e.views)for(let t of e.views)this.makeView(t);this.jsonrpc.notify(`redraw`,this.redrawParams())})}updateForeground(e){e!=null&&(this.option.foreground=e,this.input.updateForeground(e))}updateBackground(e){if(e==null)return;this.option.background=e,this.input.updateBackground(e);let t=getLemEditorElement();t.style.backgroundColor=e}makeView({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,use_modeline:l,kind:u,type:d,content:f,border:p,border_shape:m}){let h=new View({option:this.option,id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,editor:this});this.viewMap.set(e,h)}deleteView({viewInfo:{id:e}}){this.findViewById(e).delete(),this.viewMap.delete(e)}resize({viewInfo:{id:e},width:t,height:n,pixelWidth:r,pixelHeight:i}){let a=this.findViewById(e);a?a.resize(t,n,r,i):console.warn(`resize: view not found for id ${e}`)}move({viewInfo:{id:e},x:t,y:n,pixelX:r,pixelY:i}){let a=this.findViewById(e);a?a.move(t,n,r,i):console.warn(`move: view not found for id ${e}`)}redrawViewAfter({viewInfo:{id:e},isActive:t}){this.findViewById(e).touch(t)}clear({viewInfo:{id:e}}){this.findViewById(e).clear()}clearEol({viewInfo:{id:e},x:t,y:n,height:r}){this.findViewById(e).clearEol(t,n,r)}clearEob({viewInfo:{id:e},x:t,y:n}){this.findViewById(e).clearEob(t,n)}put({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,font:o,height:s}){this.findViewById(e).print(t,n,r,i,a,o,s)}putImage({viewInfo:{id:e},x:t,y:n,pixelWidth:r,pixelHeight:i,clipWidth:a,clipHeight:o,url:s}){this.findViewById(e).printImage(t,n,r,i,a,o,s)}modelinePut({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,height:o}){this.findViewById(e).printToModeline(t,n,r,i,a,o)}updateDisplay(){}moveCursor({viewInfo:{id:e},x:t,y:n,color:r,cursorText:i,cursorForeground:a}){let o=this.findViewById(e),[s,c]=this.getDisplayRectangle(),l=o.pixelX+t,u=o.pixelY+n;this.input.move(l,u);let d=r||this.option.foreground,f=a||this.option.background,p=this.cursorOverlay;switch(this.cursorType){case`bar`:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=`2px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;case`underline`:p.style.left=s+l+`px`,p.style.top=c+u+this.option.fontHeight-2+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=`2px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;default:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.style.font=this.option.font,p.style.paddingTop=textOffsetY+`px`,p.textContent=i||``,p.style.color=f;break}p.style.animation=`none`,p.offsetHeight,p.style.animation=``}updateCursorShape({cursorType:e}){this.cursorType=e||`box`}changeView({viewInfo:{id:e},type:t,content:n}){let r=this.findViewById(e);switch(t){case`html`:r.changeToHTMLContent(n);break;case`editor`:r.changeToEditorContent();break}}resizeDisplay({width:e,height:t}){let n=getLemEditorElement();n.style.width=Math.floor(e*this.option.fontWidth)+`px`,n.style.height=Math.floor(t*this.option.fontHeight)+`px`}bulk(e){for(let{method:t,argument:n}of e)this.callMessage(t,n)}exitEditor(){this.onExit&&this.onExit()}getClipboardText(){navigator.clipboard?.readText().then(e=>{this.jsonrpc.notify(`got-clipboard-text`,{text:e})})}setClipboardText({text:e}){navigator.clipboard&&navigator.clipboard.writeText(e)}jsEval({viewInfo:{id:e},code:t}){let n=this.findViewById(e).evalIn(t);return n&&n.toString()}setFont({fontName:e,fontSize:t}){this.option.setFont(e||this.option.fontName,t||this.option.fontSize),this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.jsonrpc.notify(`redraw`,this.redrawParams())}getFont(){return{name:this.option.fontName,size:this.option.fontSize}}loadCSS({content:e}){let t=document.createElement(`style`);t.textContent=e,document.head.appendChild(t)}notifyToServer(e,t){this.jsonrpc.notify(`invoke`,{method:e,args:t})}},canvas=document.querySelector(`#editor`);async function main(){await Promise.all([document.fonts.load(`19px file-icons`),document.fonts.load(`19px AllTheIcons`),document.fonts.load(`19px fontawesome`),document.fonts.load(`19px material-design-icons`),document.fonts.load(`19px octicons`)]),await document.fonts.ready;let e=new Editor({canvas,fontName:`Monospace`,fontSize:18,url:`${window.location.protocol===`https:`?`wss`:`ws`}://${window.location.hostname}:${window.location.port}`,onExit:null,onClosed:null});window.addEventListener(`message`,t=>{t.data.type===`invoke-lem`&&e.notifyToServer(t.data.method,t.data.args)}),e.init()}main(); \ No newline at end of file diff --git a/frontends/server/frontend/editor.js b/frontends/server/frontend/editor.js index baa0e2af4..3ad4569fe 100644 --- a/frontends/server/frontend/editor.js +++ b/frontends/server/frontend/editor.js @@ -346,7 +346,7 @@ class BaseSurface { // drawing coordinates are relative to the surface's own top-left corner. drawBlock(x, y, width, height, color) { } drawText(x, y, text, textWidth, attribute, font, height) { } - drawImage(x, y, width, height, url) { } + drawImage(x, y, width, height, clipWidth, clipHeight, url) { } clearImages(yStart, yEnd) { } clearAllImages() { } @@ -490,9 +490,9 @@ class CanvasSurface extends BaseSurface { imageBaseLeft() { return parseFloat(this.mainDOM.style.left) || 0; } imageBaseTop() { return parseFloat(this.mainDOM.style.top) || 0; } - drawImage(x, y, width, height, url) { + drawImage(x, y, width, height, clipWidth, clipHeight, url) { if (!this.imageEls) - // mapping "x,y" to { el, url, x, y, width, height } + // mapping "x,y" to { el, url, x, y, width, height, clipWidth, clipHeight } this.imageEls = new Map(); const key = x + ',' + y; let entry = this.imageEls.get(key); @@ -516,6 +516,8 @@ class CanvasSurface extends BaseSurface { entry.y = y; entry.width = width; entry.height = height; + entry.clipWidth = clipWidth; + entry.clipHeight = clipHeight; this.positionImage(entry); } @@ -524,6 +526,15 @@ class CanvasSurface extends BaseSurface { entry.el.style.top = (this.imageBaseTop() + entry.y) + 'px'; entry.el.style.width = entry.width + 'px'; entry.el.style.height = entry.height + 'px'; + // show only the part the server said is visible. the element keeps its full size and + // clip-path hides the rest, since shrinking it would squash the picture. + const clipRight = entry.clipWidth == null + ? 0 : Math.max(0, entry.width - entry.clipWidth); + const clipBottom = entry.clipHeight == null + ? 0 : Math.max(0, entry.height - entry.clipHeight); + entry.el.style.clipPath = (clipRight > 0 || clipBottom > 0) + ? `inset(0px ${clipRight}px ${clipBottom}px 0px)` + : ''; } // remove image elements whose vertical span intersects [yStart, yEnd). @@ -869,8 +880,8 @@ class View { ); } - printImage(x, y, pixelWidth, pixelHeight, url) { - this.mainSurface.drawImage(x, y, pixelWidth, pixelHeight, url); + printImage(x, y, pixelWidth, pixelHeight, clipWidth, clipHeight, url) { + this.mainSurface.drawImage(x, y, pixelWidth, pixelHeight, clipWidth, clipHeight, url); } printToModeline(x, y, text, textWidth, attribute, height) { @@ -1455,9 +1466,9 @@ export class Editor { view.print(x, y, text, textWidth, attribute, font, height); } - putImage({ viewInfo: { id }, x, y, pixelWidth, pixelHeight, url }) { + putImage({ viewInfo: { id }, x, y, pixelWidth, pixelHeight, clipWidth, clipHeight, url }) { const view = this.findViewById(id); - view.printImage(x, y, pixelWidth, pixelHeight, url); + view.printImage(x, y, pixelWidth, pixelHeight, clipWidth, clipHeight, url); } modelinePut({ viewInfo: { id }, x, y, text, textWidth, attribute, height }) { diff --git a/frontends/server/main.lisp b/frontends/server/main.lisp index 1a79a6c83..17b39a2e1 100644 --- a/frontends/server/main.lisp +++ b/frontends/server/main.lisp @@ -747,8 +747,15 @@ a string already carrying a data:/https: URL is passed through unchanged." (let ((url (image-object-url object))) (when url (with-error-handler () - (let ((pw (display:image-draw-width jsonrpc object)) - (ph (display:image-draw-height jsonrpc object))) + (let* ((pw (display:image-draw-width jsonrpc object)) + (ph (display:image-draw-height jsonrpc object)) + ;; how much may appear: the crop the layout applied, and the room left in the view. + ;; an image is a DOM element over the view, not pixels in it, so nothing clips it + ;; for us. + (clip-width (min pw + (max 0 (- (view-px-width view) x)) + (or (display:image-object-visible-width object) pw))) + (clip-height (min ph (max 0 (- (view-px-height view) y))))) (notify* jsonrpc "put-image" (hash "viewInfo" (view-id-hash view) @@ -756,6 +763,9 @@ a string already carrying a data:/https: URL is passed through unchanged." "y" y "pixelWidth" pw "pixelHeight" ph + ;; the visible part, from the image's top-left + "clipWidth" clip-width + "clipHeight" clip-height "url" url))))))) (defun draw-row (jsonrpc view row) diff --git a/src/display/physical-line.lisp b/src/display/physical-line.lisp index 252d0bd9d..ddbc9ee5f 100644 --- a/src/display/physical-line.lisp +++ b/src/display/physical-line.lisp @@ -60,7 +60,24 @@ ((image :initarg :image :reader image-object-image) (width :initarg :width :reader image-object-width) (height :initarg :height :reader image-object-height) - (attribute :initarg :attribute :reader image-object-attribute))) + (attribute :initarg :attribute :reader image-object-attribute) + ;; how much of the width may be shown, or NIL for all of it. see `crop-image-object'. + (visible-width :initarg :visible-width + :initform nil + :reader image-object-visible-width))) + +(defun image-object-ascent (object height) + "How much of OBJECT's image, drawn HEIGHT tall, sits above the text baseline. +Taken from the object's `:ascent' attribute: a percentage of HEIGHT, 50 by default. `:center' +instead puts the middle of the image on the middle of a line of text." + ;; attribute-value* rather than attribute-value: an object's attribute may be a name, as + ;; `attribute-image' above it allows. + (let ((ascent (or (attribute-value* (image-object-attribute object) :ascent) + 50))) + (if (eq ascent :center) + (multiple-value-bind (text-ascent text-height) (text-row-metrics) + (round (+ (/ height 2) (- text-ascent (/ text-height 2))))) + (round (* height (/ (max 0 (min 100 ascent)) 100)))))) (defun image-draw-width (implementation object) "Pixel width OBJECT's image is drawn at. @@ -90,7 +107,11 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." 0) (defmethod lem-if:object-width (implementation (drawing-object image-object)) - (image-draw-width implementation drawing-object)) + ;; a cropped image occupies only what it was cropped to, see `crop-image-object'. + (let ((width (image-draw-width implementation drawing-object))) + (alexandria:if-let ((visible (image-object-visible-width drawing-object))) + (min width visible) + width))) (defmethod lem-if:object-height (implementation (drawing-object drawing-object)) (lem-if:cell-height implementation)) @@ -106,6 +127,20 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." (declare (ignore cell-width cell-height)) (or cell-ascent (lem-if:object-height implementation drawing-object)))) +(defmethod lem-if:object-ascent (implementation (drawing-object image-object)) + (image-object-ascent drawing-object (lem-if:object-height implementation drawing-object))) + +(defun crop-image-object (object width) + "A copy of OBJECT allowed to occupy only WIDTH, in the units `object-width' counts in." + (make-instance 'image-object + :image (image-object-image object) + :width (image-object-width object) + :height (image-object-height object) + :attribute (image-object-attribute object) + :visible-width (alexandria:if-let ((visible (image-object-visible-width object))) + (min width visible) + width))) + (defmethod cursor-object-p (drawing-object) nil) @@ -149,7 +184,10 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." (defmethod drawing-object-equal ((drawing-object-1 image-object) (drawing-object-2 image-object)) (and (eq (image-object-image drawing-object-1) (image-object-image drawing-object-2)) (equal (image-object-width drawing-object-1) (image-object-width drawing-object-2)) - (equal (image-object-height drawing-object-1) (image-object-height drawing-object-2)))) + (equal (image-object-height drawing-object-1) (image-object-height drawing-object-2)) + ;; a differently cropped image draws differently, so the cached row must not be reused + (equal (image-object-visible-width drawing-object-1) + (image-object-visible-width drawing-object-2)))) (defgeneric drawing-object-mergable-p (drawing-object-1 drawing-object-2)) @@ -357,7 +395,16 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." :and physical-line-objects := '() :for object := (pop objects) :while object - :do (cond ((and (typep object 'text-object) + :do (cond ((and (typep object 'image-object) + (< (- view-width total-width) (object-width object))) + ;; an image cannot be broken in half the way a text run is, so it moves whole + ;; to the next row. one that does not fit even a row of its own is cropped. + (if (null physical-line-objects) + (push (crop-image-object object (- view-width total-width)) + physical-line-objects) + (push object objects)) + (return (values (nreverse physical-line-objects) objects))) + ((and (typep object 'text-object) (<= view-width (+ total-width (object-width object)))) (cond ((< 1 (length (text-object-string object))) (setf objects (nconc (explode-object object) objects))) @@ -807,6 +854,10 @@ creating zero temporary letter-objects." (text-object-attribute object) (text-object-type object)) result)))) + ;; an image crossing the right edge is cut down to what fits. the left edge is not, since + ;; that needs an offset into the image and an image-object carries only a visible width. + ((and (typep object 'image-object) (< x end-x) (< end-x obj-end)) + (push (crop-image-object object (- end-x x)) result)) ;; Non-text objects straddling boundary - include (t (push object result))) (incf x w))) diff --git a/src/internal-packages.lisp b/src/internal-packages.lisp index 95d4e7960..82675337e 100644 --- a/src/internal-packages.lisp +++ b/src/internal-packages.lisp @@ -18,6 +18,8 @@ :image-object-height :image-object-image :image-object-width + :image-object-visible-width + :image-object-ascent :image-draw-width :image-draw-height :object-ascent From 74fb09ea1ba21f15ddfbc6fc9c4c0c558419c07a Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Sat, 1 Aug 2026 16:41:53 +0300 Subject: [PATCH 09/18] let virtual text contain newlines also fixes a pre-existing bound in the wrapping path that compared y, in the frontend's units, against window-height, a row count. --- src/display/logical-line.lisp | 21 +++-- src/display/physical-line.lisp | 160 +++++++++++++++++++++++---------- src/internal-packages.lisp | 2 +- 3 files changed, 129 insertions(+), 54 deletions(-) diff --git a/src/display/logical-line.lisp b/src/display/logical-line.lisp index b2a043e0c..dd74e29af 100644 --- a/src/display/logical-line.lisp +++ b/src/display/logical-line.lisp @@ -440,6 +440,10 @@ several folds that each hide arbitrary character ranges across multiple buffer l attribute offset) +;; a newline inside virtual text (an overlay's :before-string / :after-string): ends the screen row +;; without touching the buffer line. +(defstruct line-break-item) + (defmethod item-string ((item string-with-attribute-item)) (string-with-attribute-item-string item)) @@ -519,11 +523,18 @@ VIRTUAL-ITEMS arrive in draw order (from `create-logical-line')." (flet ((add-virtuals-at (pos) (loop :while (and pending (= (virtual-item-charpos (first pending)) pos)) :do (let ((vi (pop pending))) - (setf items (add-or-merge-item - (make-string-with-attribute-item - :string (virtual-item-string vi) - :attribute (virtual-item-attribute vi)) - items)))))) + ;; a newline ends the screen row rather than being drawn, so the segments + ;; around it become items with a break between them. + (loop :for segment :in (uiop:split-string (virtual-item-string vi) + :separator '(#\newline)) + :for firstp := t :then nil + :do (unless firstp + (setf items (cons (make-line-break-item) items))) + (setf items (add-or-merge-item + (make-string-with-attribute-item + :string segment + :attribute (virtual-item-attribute vi)) + items))))))) ;; walk segments between break positions, injecting virtual items at each boundary (loop :for (pos . rest) :on positions :while rest diff --git a/src/display/physical-line.lisp b/src/display/physical-line.lisp index ddbc9ee5f..488cb60ba 100644 --- a/src/display/physical-line.lisp +++ b/src/display/physical-line.lisp @@ -19,6 +19,10 @@ (defclass void-object (drawing-object) ()) +;; from a `line-break-item', consumed while splitting a line into rows, so it never reaches a +;; frontend. +(defclass line-break-object (void-object) ()) + (defclass text-object (drawing-object) ((surface :initarg :surface :initform nil :accessor text-object-surface) (string :initarg :string :reader text-object-string) @@ -339,6 +343,8 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." :true-cursor-p (eol-cursor-item-true-cursor-p item)))) ((typep item 'extend-to-eol-item) (list (make-instance 'extend-to-eol-object :color (extend-to-eol-item-color item)))) + ((typep item 'line-break-item) + (list (make-instance 'line-break-object))) ((typep item 'line-end-item) (let ((string (line-end-item-text item)) (attribute (line-end-item-attribute item))) @@ -378,6 +384,11 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." (char-type character))) (defun separate-objects-by-width (objects view-width buffer) + "Take one screen row's worth of OBJECTS, at most VIEW-WIDTH wide. +Returns (values ROW REST WHY): the row's objects, those left for the rows after it, and why the row +ended. :WRAPPED for running out of width, :LINE-BREAK for a newline inside virtual text, :END for +the end of the line. Only after :WRAPPED does the next row show more of the buffer's text, which is +what turning a row back into a buffer position needs to know." (flet ((explode-object (text-object) (check-type text-object text-object) (let* ((string (text-object-string text-object)) @@ -395,7 +406,11 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." :and physical-line-objects := '() :for object := (pop objects) :while object - :do (cond ((and (typep object 'image-object) + :do (cond ((typep object 'line-break-object) + ;; a newline in virtual text, not a row that ran out of width, so no wrap + ;; marker and not :wrapped. + (return (values (nreverse physical-line-objects) objects :line-break))) + ((and (typep object 'image-object) (< (- view-width total-width) (object-width object))) ;; an image cannot be broken in half the way a text run is, so it moves whole ;; to the next row. one that does not fit even a row of its own is cropped. @@ -403,7 +418,7 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." (push (crop-image-object object (- view-width total-width)) physical-line-objects) (push object objects)) - (return (values (nreverse physical-line-objects) objects))) + (return (values (nreverse physical-line-objects) objects :wrapped))) ((and (typep object 'text-object) (<= view-width (+ total-width (object-width object)))) (cond ((< 1 (length (text-object-string object))) @@ -413,11 +428,26 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." (push (make-letter-object wrap-line-character wrap-line-attribute) physical-line-objects) - (return (values (nreverse physical-line-objects) objects))))) + (return (values (nreverse physical-line-objects) + objects + :wrapped))))) (t (incf total-width (object-width object)) (push object physical-line-objects))) - :finally (return (nreverse physical-line-objects)))))) + :finally (return (values (nreverse physical-line-objects) nil :end)))))) + +(defun split-objects-at-line-breaks (objects) + "Split OBJECTS into one list per screen row, consuming each `line-break-object'. +Returns a list of lists, never empty: a line with no breaks in it gives one row." + (if (notany (lambda (object) (typep object 'line-break-object)) objects) + (list objects) + (let (rows row) + (dolist (object objects) + (if (typep object 'line-break-object) + (progn (push (nreverse row) rows) + (setf row nil)) + (push object row))) + (nreverse (cons (nreverse row) rows))))) (defun render-row (view row) (lem-if:render-row (implementation) view row)) @@ -738,31 +768,43 @@ over the top-level spine and tolerant of improper (dotted) lists." left-side-width)) (defun check-line-fingerprint (window y fingerprint) - "Check if the fingerprint for line at Y matches. Returns cached height or NIL." + "Check if the fingerprint for line at Y matches. Returns the cached list of row heights, or NIL. +One entry per row, since a line can draw several without wrapping." (let ((cache (line-fingerprint-cache window))) (multiple-value-bind (entry found) (gethash y cache) (when (and found (eql (car entry) fingerprint)) (cdr entry))))) (defun evict-line-fingerprint-shadow (cache y height) - "Remove entries in CACHE for the rows a HEIGHT-tall line at Y covers." - (loop :for row :from (1+ y) :below (+ y height) - :do (remhash row cache))) - -(defun update-line-fingerprint (window y fingerprint height) - "Store the fingerprint and height for line at Y, and drop the rows it covers." + "Remove entries in CACHE for the rows a HEIGHT-tall line at Y covers. +Loops over the cache's keys, not over every Y in the range: on a pixel frontend that range is one +iteration per pixel, against a cache holding one entry per line drawn." + (let ((end (+ y height)) + (stale)) + (loop :for row :being :the :hash-keys :of cache + :when (and (< y row) (< row end)) + :do (push row stale)) + (dolist (row stale) + (remhash row cache)))) + +(defun update-line-fingerprint (window y fingerprint heights) + "Store the fingerprint and HEIGHTS for line at Y, and drop the rows it covers. +HEIGHTS is one entry per screen row the line drew, as the redraw functions collect them." (let ((cache (line-fingerprint-cache window))) - (setf (gethash y cache) (cons fingerprint height)) - (evict-line-fingerprint-shadow cache y height))) + (setf (gethash y cache) (cons fingerprint heights)) + (evict-line-fingerprint-shadow cache y (reduce #'+ heights :initial-value 0)))) + +(defun left-side-character-count (left-side-objects) + (loop :for obj :in left-side-objects + :when (typep obj 'text-object) + :sum (length (text-object-string obj)))) (defun redraw-logical-line-when-line-wrapping (window y logical-line left-side-objects left-side-width) - (let* ((left-side-characters (loop :for obj :in left-side-objects - :when (typep obj 'text-object) - :sum (length (text-object-string obj))))) + (let* ((left-side-characters (left-side-character-count left-side-objects))) (multiple-value-bind (first-line-objects rest-line-objects) (separate-objects-by-width (create-drawing-objects logical-line) (- (window-view-width window) left-side-width) @@ -773,22 +815,25 @@ over the top-level spine and tolerant of improper (dotted) lists." *active-modes* left-side-width left-side-characters))))) - (let ((total-height 0) + (let ((heights '()) (objects first-line-objects)) (loop - (unless objects (return)) + ;; an empty row is still a row when more of the line follows, which is what a break at + ;; the very start of the virtual text asks for. + (unless (or objects rest-line-objects) (return)) (let* ((all-objects (append left-side-objects objects)) (height (render-row-with-caching window y all-objects))) (incf y height) (setq left-side-objects wrapped-left-side-objects) - (incf total-height height) - (unless (< y (window-height window)) + (push height heights) + ;; y is in the frontend's units, so the bound must be too, not the row count. + (unless (< y (window-view-height window)) (return))) (setf (values objects rest-line-objects) (separate-objects-by-width rest-line-objects (- (window-view-width window) left-side-width) (window-buffer window)))) - total-height))))) + (nreverse heights)))))) (defun find-cursor-object (objects) (loop :for object :in objects @@ -873,30 +918,47 @@ creating zero temporary letter-objects." scroll-before left-side-width))) ;; Early exit if line content unchanged - (alexandria:when-let ((cached-height (check-line-fingerprint window y fingerprint))) - (return-from redraw-logical-line-when-horizontal-scroll cached-height)) - (let ((objects (create-drawing-objects logical-line)) - (height 0)) - (multiple-value-bind (cursor-object cursor-x) - (find-cursor-object objects) - (when cursor-object - (let ((width (- (window-view-width window) left-side-width))) - (cond ((< cursor-x (horizontal-scroll-start window)) - (setf (horizontal-scroll-start window) cursor-x)) - ((< (+ (horizontal-scroll-start window) - width) - (+ cursor-x (object-width cursor-object))) - (setf (horizontal-scroll-start window) - (+ (- cursor-x width) - (object-width cursor-object))))))) - (setf objects - (clip-objects-to-display-range - objects - (horizontal-scroll-start window) - (+ (horizontal-scroll-start window) - (window-view-width window)))) - (setf height - (render-row-with-caching window y (append left-side-objects objects)))) + (alexandria:when-let ((cached-heights (check-line-fingerprint window y fingerprint))) + (return-from redraw-logical-line-when-horizontal-scroll cached-heights)) + (let* ((rows (split-objects-at-line-breaks (create-drawing-objects logical-line))) + (left-side-characters (left-side-character-count left-side-objects)) + (heights '()) + (total-height 0)) + ;; the cursor is on one of the rows, scrolling follows it there. + (dolist (row-objects rows) + (multiple-value-bind (cursor-object cursor-x) + (find-cursor-object row-objects) + (when cursor-object + (let ((width (- (window-view-width window) left-side-width))) + (cond ((< cursor-x (horizontal-scroll-start window)) + (setf (horizontal-scroll-start window) cursor-x)) + ((< (+ (horizontal-scroll-start window) + width) + (+ cursor-x (object-width cursor-object))) + (setf (horizontal-scroll-start window) + (+ (- cursor-x width) + (object-width cursor-object))))))))) + (let ((wrapped-left-side-objects + (when (rest rows) + (copy-list (compute-wrap-left-area-content *active-modes* + left-side-width + left-side-characters))))) + (loop :for row-objects :in rows + ;; only the first row carries the real left area, the rest get the wrap padding. + :for side := left-side-objects :then wrapped-left-side-objects + :do (let* ((clipped (clip-objects-to-display-range + row-objects + (horizontal-scroll-start window) + (+ (horizontal-scroll-start window) + (window-view-width window)))) + (height (render-row-with-caching window (+ y total-height) + (append side clipped)))) + (incf total-height height) + (push height heights)) + ;; y is in the frontend's units, as is the bound + (when (<= (window-view-height window) (+ y total-height)) + (return)))) + (setf heights (nreverse heights)) ;; Reuse fingerprint if scroll position didn't change; avoids redundant sxhash (update-line-fingerprint window y @@ -905,8 +967,8 @@ creating zero temporary letter-objects." (compute-line-fingerprint logical-line (horizontal-scroll-start window) left-side-width)) - height) - height))) + heights) + heights))) (defun redraw-lines (window) (let* ((*line-wrap* (variable-value 'line-wrap @@ -928,7 +990,9 @@ creating zero temporary letter-objects." (setf left-side-width (loop :for object :in left-side-objects :sum (object-width object))) - (incf y (funcall redraw-fn window y logical-line left-side-objects left-side-width)) + (dolist (row-height + (funcall redraw-fn window y logical-line left-side-objects left-side-width)) + (incf y row-height)) (unless (< y height) (return-from outer))))) (when (< y height) diff --git a/src/internal-packages.lisp b/src/internal-packages.lisp index 82675337e..9d6c5d09a 100644 --- a/src/internal-packages.lisp +++ b/src/internal-packages.lisp @@ -843,9 +843,9 @@ :get-mouse-position :cell-width :cell-height + :cell-pixel-size :clear-to-end-of-window :js-eval - :cell-pixel-size :render-row :render-modeline-row :object-width From fb2448f428c1edb9b163b59b753e692745359be2 Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Sat, 1 Aug 2026 19:58:14 +0300 Subject: [PATCH 10/18] hit test the mouse against the rows actually drawn --- src/display/logical-line.lisp | 13 +++-- src/display/physical-line.lisp | 94 +++++++++++++++++++++++++--------- src/mouse.lisp | 38 +++++++++++--- 3 files changed, 113 insertions(+), 32 deletions(-) diff --git a/src/display/logical-line.lisp b/src/display/logical-line.lisp index dd74e29af..70e7553eb 100644 --- a/src/display/logical-line.lisp +++ b/src/display/logical-line.lisp @@ -629,12 +629,19 @@ VIRTUAL-ITEMS arrive in draw order (from `create-logical-line')." (*active-modes* active-modes)) (loop :for logical-line := (create-logical-line point overlays active-modes) :do (when logical-line - (funcall function logical-line)) + (funcall function logical-line point)) (loop (unless (line-offset point 1) (return-from call-do-logical-line)) (unless (line-continuation-p point) (return))))))) -(defmacro do-logical-line ((logical-line window) &body body) - `(call-do-logical-line ,window (lambda (,logical-line) ,@body))) +(defmacro do-logical-line ((logical-line window &optional point) &body body) + "Run BODY for each logical line of WINDOW, in draw order. +POINT, when named, is bound to the start of the line. It is one point reused for every line and +moved on to the next once BODY returns, so BODY must `copy-point' it to hold on to it." + (let ((point-var (or point (gensym "POINT")))) + `(call-do-logical-line ,window + (lambda (,logical-line ,point-var) + (declare (ignorable ,point-var)) + ,@body)))) diff --git a/src/display/physical-line.lisp b/src/display/physical-line.lisp index 488cb60ba..bc02215e2 100644 --- a/src/display/physical-line.lisp +++ b/src/display/physical-line.lisp @@ -767,9 +767,41 @@ over the top-level spine and tolerant of improper (dotted) lists." scroll-start left-side-width)) +(defstruct screen-row + "One drawn row of a window, recorded as it was drawn." + height + ;; which buffer line this row's logical line starts on. + line-number + ;; this row's index within its line. a break in virtual text starts a row without advancing it. + wrap-index) + +(defun window-screen-rows (window) + "Every screen row of WINDOW, top to bottom, as recorded while it was drawn." + (window-parameter window 'screen-rows)) + +(defun (setf window-screen-rows) (rows window) + (setf (window-parameter window 'screen-rows) rows)) + +(defun window-screen-row-index-at-y (window y) + "Index of the screen row Y falls in, counted from the top of WINDOW's view, or NIL when Y is past +the last row drawn or the window has not been drawn yet. Y is in the frontend's units. +Walks the rows because they are not all one height, so there is nothing to divide by." + (loop :with top := 0 + :for row :in (window-screen-rows window) + :for index :from 0 + :do (when (< y (+ top (screen-row-height row))) + (return index)) + (incf top (screen-row-height row)))) + +(defun window-screen-row-at-index (window index) + "WINDOW's screen row at INDEX, counted from the top of its view, or NIL if no row was drawn +there." + (nth index (window-screen-rows window))) + (defun check-line-fingerprint (window y fingerprint) - "Check if the fingerprint for line at Y matches. Returns the cached list of row heights, or NIL. -One entry per row, since a line can draw several without wrapping." + "Check if the fingerprint for line at Y matches. Returns the cached list of rows, or NIL. +One entry per row, so a line taken from the cache still contributes its rows to +`window-screen-rows'." (let ((cache (line-fingerprint-cache window))) (multiple-value-bind (entry found) (gethash y cache) (when (and found (eql (car entry) fingerprint)) @@ -787,12 +819,13 @@ iteration per pixel, against a cache holding one entry per line drawn." (dolist (row stale) (remhash row cache)))) -(defun update-line-fingerprint (window y fingerprint heights) - "Store the fingerprint and HEIGHTS for line at Y, and drop the rows it covers. -HEIGHTS is one entry per screen row the line drew, as the redraw functions collect them." +(defun update-line-fingerprint (window y fingerprint rows) + "Store the fingerprint and ROWS for line at Y, and drop the rows it covers. +ROWS is one (HEIGHT . WRAP-INDEX) per screen row the line drew, as the redraw functions collect +them." (let ((cache (line-fingerprint-cache window))) - (setf (gethash y cache) (cons fingerprint heights)) - (evict-line-fingerprint-shadow cache y (reduce #'+ heights :initial-value 0)))) + (setf (gethash y cache) (cons fingerprint rows)) + (evict-line-fingerprint-shadow cache y (reduce #'+ rows :key #'car :initial-value 0)))) (defun left-side-character-count (left-side-objects) (loop :for obj :in left-side-objects @@ -805,7 +838,7 @@ HEIGHTS is one entry per screen row the line drew, as the redraw functions colle left-side-objects left-side-width) (let* ((left-side-characters (left-side-character-count left-side-objects))) - (multiple-value-bind (first-line-objects rest-line-objects) + (multiple-value-bind (first-line-objects rest-line-objects why) (separate-objects-by-width (create-drawing-objects logical-line) (- (window-view-width window) left-side-width) (window-buffer window)) @@ -815,7 +848,8 @@ HEIGHTS is one entry per screen row the line drew, as the redraw functions colle *active-modes* left-side-width left-side-characters))))) - (let ((heights '()) + (let ((rows) + (wrap-index 0) (objects first-line-objects)) (loop ;; an empty row is still a row when more of the line follows, which is what a break at @@ -825,15 +859,18 @@ HEIGHTS is one entry per screen row the line drew, as the redraw functions colle (height (render-row-with-caching window y all-objects))) (incf y height) (setq left-side-objects wrapped-left-side-objects) - (push height heights) + (push (cons height wrap-index) rows) + ;; only running out of width advances the position, a virtual-text break does not. + (when (eq why :wrapped) + (incf wrap-index)) ;; y is in the frontend's units, so the bound must be too, not the row count. (unless (< y (window-view-height window)) (return))) - (setf (values objects rest-line-objects) + (setf (values objects rest-line-objects why) (separate-objects-by-width rest-line-objects (- (window-view-width window) left-side-width) (window-buffer window)))) - (nreverse heights)))))) + (nreverse rows)))))) (defun find-cursor-object (objects) (loop :for object :in objects @@ -918,11 +955,11 @@ creating zero temporary letter-objects." scroll-before left-side-width))) ;; Early exit if line content unchanged - (alexandria:when-let ((cached-heights (check-line-fingerprint window y fingerprint))) - (return-from redraw-logical-line-when-horizontal-scroll cached-heights)) + (alexandria:when-let ((cached-rows (check-line-fingerprint window y fingerprint))) + (return-from redraw-logical-line-when-horizontal-scroll cached-rows)) (let* ((rows (split-objects-at-line-breaks (create-drawing-objects logical-line))) (left-side-characters (left-side-character-count left-side-objects)) - (heights '()) + (row-heights) (total-height 0)) ;; the cursor is on one of the rows, scrolling follows it there. (dolist (row-objects rows) @@ -954,11 +991,12 @@ creating zero temporary letter-objects." (height (render-row-with-caching window (+ y total-height) (append side clipped)))) (incf total-height height) - (push height heights)) + ;; wrapping is off here, so every row begins where the line does, index 0 + (push (cons height 0) row-heights)) ;; y is in the frontend's units, as is the bound (when (<= (window-view-height window) (+ y total-height)) (return)))) - (setf heights (nreverse heights)) + (setf row-heights (nreverse row-heights)) ;; Reuse fingerprint if scroll position didn't change; avoids redundant sxhash (update-line-fingerprint window y @@ -967,8 +1005,8 @@ creating zero temporary letter-objects." (compute-line-fingerprint logical-line (horizontal-scroll-start window) left-side-width)) - heights) - heights))) + row-heights) + row-heights))) (defun redraw-lines (window) (let* ((*line-wrap* (variable-value 'line-wrap @@ -978,9 +1016,11 @@ creating zero temporary letter-objects." #'redraw-logical-line-when-horizontal-scroll))) (let ((y 0) (height (window-view-height window)) + ;; every row drawn, in reverse. see `window-screen-rows' + (rows) left-side-width) (block outer - (do-logical-line (logical-line window) + (do-logical-line (logical-line window line-point) (let* ((left-side-objects (alexandria:when-let (content (logical-line-left-content logical-line)) (mapcan #'create-drawing-object @@ -990,11 +1030,19 @@ creating zero temporary letter-objects." (setf left-side-width (loop :for object :in left-side-objects :sum (object-width object))) - (dolist (row-height - (funcall redraw-fn window y logical-line left-side-objects left-side-width)) - (incf y row-height)) + (let ((line-rows + (funcall redraw-fn window y logical-line left-side-objects left-side-width)) + ;; read once, shared by the line's rows + (line-number (line-number-at-point line-point))) + (loop :for (row-height . wrap-index) :in line-rows + :do (push (make-screen-row :height row-height + :line-number line-number + :wrap-index wrap-index) + rows) + (incf y row-height))) (unless (< y height) (return-from outer))))) + (setf (window-screen-rows window) (nreverse rows)) (when (< y height) (clear-line-fingerprint-cache-from window y) (invalidate-drawing-cache-from window y) diff --git a/src/mouse.lisp b/src/mouse.lisp index 7faa8548d..429bb5e0b 100644 --- a/src/mouse.lisp +++ b/src/mouse.lisp @@ -69,18 +69,44 @@ (* (window-y window) (lem-if:cell-height (implementation))))))) +(defun mouse-event-screen-row (mouse-event window fallback-row) + "The screen row of WINDOW that MOUSE-EVENT points at, counted from the top of its view. +Walks the heights recorded when the window was drawn, since rows are not all one height. +FALLBACK-ROW, what dividing by a row height gives, is used when there is no pixel position to walk +with or the window is undrawn." + (if (and (mouse-event-pixel-x mouse-event) + (mouse-event-pixel-y mouse-event)) + (multiple-value-bind (relative-x relative-y) + (get-relative-mouse-coordinates-pixels mouse-event window) + (declare (ignore relative-x)) + (or (window-screen-row-index-at-y window relative-y) + fallback-row)) + fallback-row)) + +(defun move-point-to-screen-row (point window row) + "Move POINT to the start of screen ROW of WINDOW, counting rows from the top of its view. +Uses the line recorded when the row was drawn, since counting virtual lines down from the view top +would miscount every row a newline inside virtual text added. Falls back to that count for a row +that was not drawn, or whose line the buffer no longer has." + (flet ((count-from-view-top () + (move-point point (window-view-point window)) + (move-to-next-virtual-line point row window))) + (alexandria:if-let ((screen-row (window-screen-row-at-index window row))) + (if (move-to-line point (screen-row-line-number screen-row)) + (move-to-next-virtual-line point (screen-row-wrap-index screen-row) window) + (count-from-view-top)) + (count-from-view-top)))) + (defun get-point-from-window-with-coordinates (window x y &optional (allow-overflow-column t)) (with-point ((point (buffer-point (window-buffer window)))) - (move-point point (window-view-point window)) - (move-to-next-virtual-line point y window) + (move-point-to-screen-row point window y) (let ((moved (move-to-virtual-line-column point x window))) (when (or moved allow-overflow-column) point)))) (defun move-current-point-to-x-y-position (window x y) (switch-to-window window) - (move-point (current-point) (window-view-point window)) - (move-to-next-virtual-line (current-point) y) + (move-point-to-screen-row (current-point) window y) (move-to-virtual-line-column (current-point) x)) (defvar *last-mouse-event*) @@ -194,7 +220,7 @@ mouse-event :window window :x x - :y y))))))) + :y (mouse-event-screen-row mouse-event window y)))))))) (defmethod handle-mouse-event ((mouse-event mouse-button-up)) (setf *last-dragged-separator* nil) @@ -260,7 +286,7 @@ mouse-event :window window :x x - :y y)))) + :y (mouse-event-screen-row mouse-event window y))))) ((typep *last-dragged-separator* 'window-vertical-separator) (let ((x (mouse-event-x mouse-event)) (button (mouse-event-button mouse-event))) From 0ce2ac269eac78eedd98b098942e629158268892 Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Sun, 2 Aug 2026 14:15:46 +0300 Subject: [PATCH 11/18] fill a row with draw-block instead of a textless put row fills and the modeline background were sent as an empty put with a width and height, since put was the only notification that could paint a color. put now draws one line of text; draw-block fills a rect. --- .../server/frontend/dist/assets/index.js | 2 +- frontends/server/frontend/editor.js | 49 ++++++++++---- frontends/server/main.lisp | 65 ++++++++++--------- 3 files changed, 72 insertions(+), 44 deletions(-) diff --git a/frontends/server/frontend/dist/assets/index.js b/frontends/server/frontend/dist/assets/index.js index 79fd24e7d..572821549 100644 --- a/frontends/server/frontend/dist/assets/index.js +++ b/frontends/server/frontend/dist/assets/index.js @@ -1 +1 @@ -var __defProp=Object.defineProperty,__commonJSMin=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),__exportAll=(e,t)=>{let n={};for(var r in e)__defProp(n,r,{get:e[r],enumerable:!0});return t||__defProp(n,Symbol.toStringTag,{value:`Module`}),n};(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var require_models=__commonJSMin((e=>{var t=e&&e.__extends||(function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};return function(t,n){if(typeof n!=`function`&&n!==null)throw TypeError(`Class extends value `+String(n)+` is not a constructor or null`);e(t,n);function r(){this.constructor=t}t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}})();Object.defineProperty(e,"__esModule",{value:!0}),e.createJSONRPCNotification=e.createJSONRPCRequest=e.createJSONRPCSuccessResponse=e.createJSONRPCErrorResponse=e.JSONRPCErrorCode=e.JSONRPCErrorException=e.isJSONRPCResponses=e.isJSONRPCResponse=e.isJSONRPCRequests=e.isJSONRPCRequest=e.isJSONRPCID=e.JSONRPC=void 0,e.JSONRPC=`2.0`,e.isJSONRPCID=function(e){return typeof e==`string`||typeof e==`number`||e===null},e.isJSONRPCRequest=function(t){return t.jsonrpc===e.JSONRPC&&t.method!==void 0&&t.result===void 0&&t.error===void 0},e.isJSONRPCRequests=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCRequest)},e.isJSONRPCResponse=function(t){return t.jsonrpc===e.JSONRPC&&t.id!==void 0&&(t.result!==void 0||t.error!==void 0)},e.isJSONRPCResponses=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCResponse)};var n=function(e,t,n){var r={code:e,message:t};return n!=null&&(r.data=n),r};e.JSONRPCErrorException=function(e){t(r,e);function r(t,n,i){var a=e.call(this,t)||this;return Object.setPrototypeOf(a,r.prototype),a.code=n,a.data=i,a}return r.prototype.toObject=function(){return n(this.code,this.message,this.data)},r}(Error),(function(e){e[e.ParseError=-32700]=`ParseError`,e[e.InvalidRequest=-32600]=`InvalidRequest`,e[e.MethodNotFound=-32601]=`MethodNotFound`,e[e.InvalidParams=-32602]=`InvalidParams`,e[e.InternalError=-32603]=`InternalError`})(e.JSONRPCErrorCode||={}),e.createJSONRPCErrorResponse=function(t,r,i,a){return{jsonrpc:e.JSONRPC,id:t,error:n(r,i,a)}},e.createJSONRPCSuccessResponse=function(t,n){return{jsonrpc:e.JSONRPC,id:t,result:n??null}},e.createJSONRPCRequest=function(t,n,r){return{jsonrpc:e.JSONRPC,id:t,method:n,params:r}},e.createJSONRPCNotification=function(t,n){return{jsonrpc:e.JSONRPC,method:t,params:n}}})),require_internal=__commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.DefaultErrorCode=void 0,e.DefaultErrorCode=0})),require_client=__commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{Object.defineProperty(e,"__esModule",{value:!0})})),require_server=__commonJSMin((e=>{var t=e&&e.__assign||function(){return t=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__createBinding||(Object.create?(function(e,t,n,r){r===void 0&&(r=n);var i=Object.getOwnPropertyDescriptor(t,n);(!i||(`get`in i?!t.__esModule:i.writable||i.configurable))&&(i={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,i)}):(function(e,t,n,r){r===void 0&&(r=n),e[r]=t[n]})),n=e&&e.__exportStar||function(e,n){for(var r in e)r!=="default"&&!Object.prototype.hasOwnProperty.call(n,r)&&t(n,e,r)};Object.defineProperty(e,"__esModule",{value:!0}),n(require_client(),e),n(require_interfaces(),e),n(require_models(),e),n(require_server(),e),n(require_server_and_client(),e)})),import_dist=require_dist(),JSONRPC=class{constructor(e,{onConnected:t,onClosed:n}){this.url=e,this.onConnected=t,this.onClosed=n,this.messageQueue=[],this.serverAndClient=null,this.connect(),this.connectionEstablished=!1,this.timerId=null,this.closed=!1}close(){this.timerId&&clearTimeout(this.timerId),this.webSocket.close(),this.closed=!0}on(e,t){this.serverAndClient.addMethod(e,t)}async requestInternal(e,t,n){let r=await this.serverAndClient.request(e,t);n&&n(r)}requestMessageQueue(){this.messageQueue.forEach(e=>{let[t,n,r]=e;this.requestInternal(t,n,r)}),this.messageQueue=[]}request(e,t,n){this.webSocket.readyState===WebSocket.OPEN?this.requestInternal(e,t,n):this.messageQueue.push([e,t,n])}notify(e,t){switch(this.webSocket.readyState){case WebSocket.OPEN:this.serverAndClient.notify(e,t);break;case WebSocket.CLOSED:break}}connect(e){this.closed||(console.log(`connect`,this.url),this.webSocket=new WebSocket(this.url),this.serverAndClient||=new import_dist.JSONRPCServerAndClient(new import_dist.JSONRPCServer,new import_dist.JSONRPCClient(e=>{try{return this.webSocket.send(JSON.stringify(e)),Promise.resolve()}catch(e){return Promise.reject(e)}})),this.webSocket.onmessage=e=>{this.serverAndClient.receiveAndSend(JSON.parse(e.data.toString()))},this.webSocket.onopen=()=>{console.log(`WebSocket connection established`),this.connectionEstablished=!0,this.onConnected&&this.onConnected(),this.requestMessageQueue()},this.webSocket.onclose=e=>{console.error(`WebScoket closed`,e),this.serverAndClient.rejectAllPendingRequests(`Connection is closed (${e.reason}).`),this.connectionEstablished&&this.onClosed(),this.timerId=setTimeout(()=>{this.connect()},3e3)},this.webSocket.onerror=e=>{console.error(`WebSocket error:`,e),this.webSocket.close()})}},keyevent_exports=__exportAll({convertKeyEvent:()=>convertKeyEvent}),modifierKeys=[`Shift`,`Control`,`Alt`,`Meta`,`CapsLock`],convertKeyTable={Enter:`Return`,ArrowRight:`Right`,ArrowLeft:`Left`,ArrowUp:`Up`,ArrowDown:`Down`,"¡":`1`,"™":`2`,"£":`3`,"¢":`4`,"∞":`5`,"§":`6`,"¶":`7`,"•":`8`,ª:`9`,º:`0`,"–":`-`,"≠":`=`,"“":`[`,"‘":`]`,"«":`\\`,"…":`;`,æ:`'`,"≤":`,`,"≥":`.`,"÷":`/`,"⁄":`!`,"€":`@`,"‹":`#`,"›":`$`,fi:`%`,fl:`^`,"‡":`&`,"°":`*`,"·":`(`,"‚":`)`,"—":`_`,"±":`+`,"”":`{`,"’":`}`,"»":`|`,Ú:`:`,Æ:`"`,"¯":`<`,"˘":`>`,"¿":`?`,œ:`q`,"∑":`w`,"´":`e`,"®":`r`,"†":`t`,"¥":`y`,"¨":`u`,ˆ:`i`,ø:`o`,π:`p`,å:`a`,ß:`s`,"∂":`d`,ƒ:`f`,"©":`g`,"˙":`h`,"∆":`j`,"˚":`k`,"¬":`l`,Ω:`z`,"≈":`x`,ç:`c`,"√":`v`,"∫":`b`,"˜":`n`,µ:`m`,Œ:`Q`,"„":`W`,"´":`E`,"‰":`R`,ˇ:`T`,Á:`Y`,"¨":`U`,ˆ:`I`,Ø:`O`,"∏":`P`,Å:`A`,Í:`S`,Î:`D`,Ï:`F`,"˝":`G`,Ó:`H`,Ô:`J`,"":`K`,Ò:`L`,"¸":`Z`,"˛":`X`,Ç:`C`,"◊":`V`,ı:`B`,"˜":`N`,Â:`M`};function getKey(e){return e.altKey?convertKeyTable[e.key]||(e.code.startsWith(`Key`)?e.code[3].toLowerCase():null)||e.key:convertKeyTable[e.key]||e.key}function convertKeyEvent(e){return modifierKeys.indexOf(e.key)===-1?{key:getKey(e),ctrl:e.ctrlKey,meta:e.altKey,super:e.metaKey,shift:e.shiftKey}:null}var lib_exports=__exportAll({computeWidth:()=>computeWidth,eawVersion:()=>version,getEAW:()=>getEAW}),defs=[[0,31,`N`],[32,126,`Na`],[127,160,`N`],[161,161,`A`],[162,163,`Na`],[164,164,`A`],[165,166,`Na`],[167,168,`A`],[169,169,`N`],[170,170,`A`],[171,171,`N`],[172,172,`Na`],[173,174,`A`],[175,175,`Na`],[176,180,`A`],[181,181,`N`],[182,186,`A`],[187,187,`N`],[188,191,`A`],[192,197,`N`],[198,198,`A`],[199,207,`N`],[208,208,`A`],[209,214,`N`],[215,216,`A`],[217,221,`N`],[222,225,`A`],[226,229,`N`],[230,230,`A`],[231,231,`N`],[232,234,`A`],[235,235,`N`],[236,237,`A`],[238,239,`N`],[240,240,`A`],[241,241,`N`],[242,243,`A`],[244,246,`N`],[247,250,`A`],[251,251,`N`],[252,252,`A`],[253,253,`N`],[254,254,`A`],[255,256,`N`],[257,257,`A`],[258,272,`N`],[273,273,`A`],[274,274,`N`],[275,275,`A`],[276,282,`N`],[283,283,`A`],[284,293,`N`],[294,295,`A`],[296,298,`N`],[299,299,`A`],[300,304,`N`],[305,307,`A`],[308,311,`N`],[312,312,`A`],[313,318,`N`],[319,322,`A`],[323,323,`N`],[324,324,`A`],[325,327,`N`],[328,331,`A`],[332,332,`N`],[333,333,`A`],[334,337,`N`],[338,339,`A`],[340,357,`N`],[358,359,`A`],[360,362,`N`],[363,363,`A`],[364,461,`N`],[462,462,`A`],[463,463,`N`],[464,464,`A`],[465,465,`N`],[466,466,`A`],[467,467,`N`],[468,468,`A`],[469,469,`N`],[470,470,`A`],[471,471,`N`],[472,472,`A`],[473,473,`N`],[474,474,`A`],[475,475,`N`],[476,476,`A`],[477,592,`N`],[593,593,`A`],[594,608,`N`],[609,609,`A`],[610,707,`N`],[708,708,`A`],[709,710,`N`],[711,711,`A`],[712,712,`N`],[713,715,`A`],[716,716,`N`],[717,717,`A`],[718,719,`N`],[720,720,`A`],[721,727,`N`],[728,731,`A`],[732,732,`N`],[733,733,`A`],[734,734,`N`],[735,735,`A`],[736,767,`N`],[768,879,`A`],[880,912,`N`],[913,929,`A`],[930,930,`N`],[931,937,`A`],[938,944,`N`],[945,961,`A`],[962,962,`N`],[963,969,`A`],[970,1024,`N`],[1025,1025,`A`],[1026,1039,`N`],[1040,1103,`A`],[1104,1104,`N`],[1105,1105,`A`],[1106,4351,`N`],[4352,4447,`W`],[4448,8207,`N`],[8208,8208,`A`],[8209,8210,`N`],[8211,8214,`A`],[8215,8215,`N`],[8216,8217,`A`],[8218,8219,`N`],[8220,8221,`A`],[8222,8223,`N`],[8224,8226,`A`],[8227,8227,`N`],[8228,8231,`A`],[8232,8239,`N`],[8240,8240,`A`],[8241,8241,`N`],[8242,8243,`A`],[8244,8244,`N`],[8245,8245,`A`],[8246,8250,`N`],[8251,8251,`A`],[8252,8253,`N`],[8254,8254,`A`],[8255,8307,`N`],[8308,8308,`A`],[8309,8318,`N`],[8319,8319,`A`],[8320,8320,`N`],[8321,8324,`A`],[8325,8360,`N`],[8361,8361,`H`],[8362,8363,`N`],[8364,8364,`A`],[8365,8450,`N`],[8451,8451,`A`],[8452,8452,`N`],[8453,8453,`A`],[8454,8456,`N`],[8457,8457,`A`],[8458,8466,`N`],[8467,8467,`A`],[8468,8469,`N`],[8470,8470,`A`],[8471,8480,`N`],[8481,8482,`A`],[8483,8485,`N`],[8486,8486,`A`],[8487,8490,`N`],[8491,8491,`A`],[8492,8530,`N`],[8531,8532,`A`],[8533,8538,`N`],[8539,8542,`A`],[8543,8543,`N`],[8544,8555,`A`],[8556,8559,`N`],[8560,8569,`A`],[8570,8584,`N`],[8585,8585,`A`],[8586,8591,`N`],[8592,8601,`A`],[8602,8631,`N`],[8632,8633,`A`],[8634,8657,`N`],[8658,8658,`A`],[8659,8659,`N`],[8660,8660,`A`],[8661,8678,`N`],[8679,8679,`A`],[8680,8703,`N`],[8704,8704,`A`],[8705,8705,`N`],[8706,8707,`A`],[8708,8710,`N`],[8711,8712,`A`],[8713,8714,`N`],[8715,8715,`A`],[8716,8718,`N`],[8719,8719,`A`],[8720,8720,`N`],[8721,8721,`A`],[8722,8724,`N`],[8725,8725,`A`],[8726,8729,`N`],[8730,8730,`A`],[8731,8732,`N`],[8733,8736,`A`],[8737,8738,`N`],[8739,8739,`A`],[8740,8740,`N`],[8741,8741,`A`],[8742,8742,`N`],[8743,8748,`A`],[8749,8749,`N`],[8750,8750,`A`],[8751,8755,`N`],[8756,8759,`A`],[8760,8763,`N`],[8764,8765,`A`],[8766,8775,`N`],[8776,8776,`A`],[8777,8779,`N`],[8780,8780,`A`],[8781,8785,`N`],[8786,8786,`A`],[8787,8799,`N`],[8800,8801,`A`],[8802,8803,`N`],[8804,8807,`A`],[8808,8809,`N`],[8810,8811,`A`],[8812,8813,`N`],[8814,8815,`A`],[8816,8833,`N`],[8834,8835,`A`],[8836,8837,`N`],[8838,8839,`A`],[8840,8852,`N`],[8853,8853,`A`],[8854,8856,`N`],[8857,8857,`A`],[8858,8868,`N`],[8869,8869,`A`],[8870,8894,`N`],[8895,8895,`A`],[8896,8977,`N`],[8978,8978,`A`],[8979,8985,`N`],[8986,8987,`W`],[8988,9e3,`N`],[9001,9002,`W`],[9003,9192,`N`],[9193,9196,`W`],[9197,9199,`N`],[9200,9200,`W`],[9201,9202,`N`],[9203,9203,`W`],[9204,9311,`N`],[9312,9449,`A`],[9450,9450,`N`],[9451,9547,`A`],[9548,9551,`N`],[9552,9587,`A`],[9588,9599,`N`],[9600,9615,`A`],[9616,9617,`N`],[9618,9621,`A`],[9622,9631,`N`],[9632,9633,`A`],[9634,9634,`N`],[9635,9641,`A`],[9642,9649,`N`],[9650,9651,`A`],[9652,9653,`N`],[9654,9655,`A`],[9656,9659,`N`],[9660,9661,`A`],[9662,9663,`N`],[9664,9665,`A`],[9666,9669,`N`],[9670,9672,`A`],[9673,9674,`N`],[9675,9675,`A`],[9676,9677,`N`],[9678,9681,`A`],[9682,9697,`N`],[9698,9701,`A`],[9702,9710,`N`],[9711,9711,`A`],[9712,9724,`N`],[9725,9726,`W`],[9727,9732,`N`],[9733,9734,`A`],[9735,9736,`N`],[9737,9737,`A`],[9738,9741,`N`],[9742,9743,`A`],[9744,9747,`N`],[9748,9749,`W`],[9750,9755,`N`],[9756,9756,`A`],[9757,9757,`N`],[9758,9758,`A`],[9759,9791,`N`],[9792,9792,`A`],[9793,9793,`N`],[9794,9794,`A`],[9795,9799,`N`],[9800,9811,`W`],[9812,9823,`N`],[9824,9825,`A`],[9826,9826,`N`],[9827,9829,`A`],[9830,9830,`N`],[9831,9834,`A`],[9835,9835,`N`],[9836,9837,`A`],[9838,9838,`N`],[9839,9839,`A`],[9840,9854,`N`],[9855,9855,`W`],[9856,9874,`N`],[9875,9875,`W`],[9876,9885,`N`],[9886,9887,`A`],[9888,9888,`N`],[9889,9889,`W`],[9890,9897,`N`],[9898,9899,`W`],[9900,9916,`N`],[9917,9918,`W`],[9919,9919,`A`],[9920,9923,`N`],[9924,9925,`W`],[9926,9933,`A`],[9934,9934,`W`],[9935,9939,`A`],[9940,9940,`W`],[9941,9953,`A`],[9954,9954,`N`],[9955,9955,`A`],[9956,9959,`N`],[9960,9961,`A`],[9962,9962,`W`],[9963,9969,`A`],[9970,9971,`W`],[9972,9972,`A`],[9973,9973,`W`],[9974,9977,`A`],[9978,9978,`W`],[9979,9980,`A`],[9981,9981,`W`],[9982,9983,`A`],[9984,9988,`N`],[9989,9989,`W`],[9990,9993,`N`],[9994,9995,`W`],[9996,10023,`N`],[10024,10024,`W`],[10025,10044,`N`],[10045,10045,`A`],[10046,10059,`N`],[10060,10060,`W`],[10061,10061,`N`],[10062,10062,`W`],[10063,10066,`N`],[10067,10069,`W`],[10070,10070,`N`],[10071,10071,`W`],[10072,10101,`N`],[10102,10111,`A`],[10112,10132,`N`],[10133,10135,`W`],[10136,10159,`N`],[10160,10160,`W`],[10161,10174,`N`],[10175,10175,`W`],[10176,10213,`N`],[10214,10221,`Na`],[10222,10628,`N`],[10629,10630,`Na`],[10631,11034,`N`],[11035,11036,`W`],[11037,11087,`N`],[11088,11088,`W`],[11089,11092,`N`],[11093,11093,`W`],[11094,11097,`A`],[11098,11903,`N`],[11904,11929,`W`],[11930,11930,`N`],[11931,12019,`W`],[12020,12031,`N`],[12032,12245,`W`],[12246,12271,`N`],[12272,12287,`W`],[12288,12288,`F`],[12289,12350,`W`],[12351,12352,`N`],[12353,12438,`W`],[12439,12440,`N`],[12441,12543,`W`],[12544,12548,`N`],[12549,12591,`W`],[12592,12592,`N`],[12593,12686,`W`],[12687,12687,`N`],[12688,12771,`W`],[12772,12782,`N`],[12783,12830,`W`],[12831,12831,`N`],[12832,12871,`W`],[12872,12879,`A`],[12880,19903,`W`],[19904,19967,`N`],[19968,42124,`W`],[42125,42127,`N`],[42128,42182,`W`],[42183,43359,`N`],[43360,43388,`W`],[43389,44031,`N`],[44032,55203,`W`],[55204,57343,`N`],[57344,63743,`A`],[63744,64255,`W`],[64256,65023,`N`],[65024,65039,`A`],[65040,65049,`W`],[65050,65071,`N`],[65072,65106,`W`],[65107,65107,`N`],[65108,65126,`W`],[65127,65127,`N`],[65128,65131,`W`],[65132,65280,`N`],[65281,65376,`F`],[65377,65470,`H`],[65471,65473,`N`],[65474,65479,`H`],[65480,65481,`N`],[65482,65487,`H`],[65488,65489,`N`],[65490,65495,`H`],[65496,65497,`N`],[65498,65500,`H`],[65501,65503,`N`],[65504,65510,`F`],[65511,65511,`N`],[65512,65518,`H`],[65519,65532,`N`],[65533,65533,`A`],[65534,94175,`N`],[94176,94180,`W`],[94181,94191,`N`],[94192,94193,`W`],[94194,94207,`N`],[94208,100343,`W`],[100344,100351,`N`],[100352,101589,`W`],[101590,101631,`N`],[101632,101640,`W`],[101641,110575,`N`],[110576,110579,`W`],[110580,110580,`N`],[110581,110587,`W`],[110588,110588,`N`],[110589,110590,`W`],[110591,110591,`N`],[110592,110882,`W`],[110883,110897,`N`],[110898,110898,`W`],[110899,110927,`N`],[110928,110930,`W`],[110931,110932,`N`],[110933,110933,`W`],[110934,110947,`N`],[110948,110951,`W`],[110952,110959,`N`],[110960,111355,`W`],[111356,126979,`N`],[126980,126980,`W`],[126981,127182,`N`],[127183,127183,`W`],[127184,127231,`N`],[127232,127242,`A`],[127243,127247,`N`],[127248,127277,`A`],[127278,127279,`N`],[127280,127337,`A`],[127338,127343,`N`],[127344,127373,`A`],[127374,127374,`W`],[127375,127376,`A`],[127377,127386,`W`],[127387,127404,`A`],[127405,127487,`N`],[127488,127490,`W`],[127491,127503,`N`],[127504,127547,`W`],[127548,127551,`N`],[127552,127560,`W`],[127561,127567,`N`],[127568,127569,`W`],[127570,127583,`N`],[127584,127589,`W`],[127590,127743,`N`],[127744,127776,`W`],[127777,127788,`N`],[127789,127797,`W`],[127798,127798,`N`],[127799,127868,`W`],[127869,127869,`N`],[127870,127891,`W`],[127892,127903,`N`],[127904,127946,`W`],[127947,127950,`N`],[127951,127955,`W`],[127956,127967,`N`],[127968,127984,`W`],[127985,127987,`N`],[127988,127988,`W`],[127989,127991,`N`],[127992,128062,`W`],[128063,128063,`N`],[128064,128064,`W`],[128065,128065,`N`],[128066,128252,`W`],[128253,128254,`N`],[128255,128317,`W`],[128318,128330,`N`],[128331,128334,`W`],[128335,128335,`N`],[128336,128359,`W`],[128360,128377,`N`],[128378,128378,`W`],[128379,128404,`N`],[128405,128406,`W`],[128407,128419,`N`],[128420,128420,`W`],[128421,128506,`N`],[128507,128591,`W`],[128592,128639,`N`],[128640,128709,`W`],[128710,128715,`N`],[128716,128716,`W`],[128717,128719,`N`],[128720,128722,`W`],[128723,128724,`N`],[128725,128727,`W`],[128728,128731,`N`],[128732,128735,`W`],[128736,128746,`N`],[128747,128748,`W`],[128749,128755,`N`],[128756,128764,`W`],[128765,128991,`N`],[128992,129003,`W`],[129004,129007,`N`],[129008,129008,`W`],[129009,129291,`N`],[129292,129338,`W`],[129339,129339,`N`],[129340,129349,`W`],[129350,129350,`N`],[129351,129535,`W`],[129536,129647,`N`],[129648,129660,`W`],[129661,129663,`N`],[129664,129672,`W`],[129673,129679,`N`],[129680,129725,`W`],[129726,129726,`N`],[129727,129733,`W`],[129734,129741,`N`],[129742,129755,`W`],[129756,129759,`N`],[129760,129768,`W`],[129769,129775,`N`],[129776,129784,`W`],[129785,131071,`N`],[131072,196605,`W`],[196606,196607,`N`],[196608,262141,`W`],[262142,917759,`N`],[917760,917999,`A`],[918e3,983039,`N`],[983040,1048573,`A`],[1048574,1048575,`N`],[1048576,1114109,`A`],[1114110,1114111,`N`]],version=`15.1.0`;function getEAWOfCodePoint(e){let t=0,n=defs.length-1;for(;t!==n;){let r=t+(n-t>>1),[i,a,o]=defs[r];if(ea)t=r+1;else return o}return defs[t][2]}function getEAW(e,t=0){let n=e.codePointAt(t);if(n!==void 0)return getEAWOfCodePoint(n)}var defaultWidths={N:1,Na:1,W:2,F:2,H:1,A:1};function computeWidth(e,t){let n=0;for(let r of e){let e=getEAW(r);n+=t&&t[e]||defaultWidths[e]}return n}var textOffsetY=5,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function isWideChar(e){switch(getEAW(e)){case`F`:case`W`:return!0;default:return!1}}function isMacOS(){return window.navigator.userAgent.indexOf(`Mac OS X`)!==-1}function computeFontSize(e){let t=document.createElement(`canvas`).getContext(`2d`);t.font=e;let n=t.measureText(`W`);return[Math.floor(n.width),Math.round(n.fontBoundingBoxAscent+textOffsetY+(n.emHeightDescent||0)),Math.round(n.fontBoundingBoxAscent+textOffsetY)]}function drawBlock({ctx:e,x:t,y:n,width:r,height:i,style:a}){e.fillStyle=a,e.fillRect(t,n,r,i)}function drawText({ctx:e,x:t,y:n,text:r,font:i,style:a,option:o}){n+=Math.round(textOffsetY),e.fillStyle=a,e.font=i,e.textBaseline=`top`;for(let i of r)isWideChar(i)?(e.fillText(i,t,n,o.fontWidth*2),t+=o.fontWidth*2):(e.fillText(i,t,n,o.fontWidth),t+=o.fontWidth)}function drawHorizontalLine({ctx:e,x:t,y:n,width:r,style:i,lineWidth:a=1}){e.strokeStyle=i,e.lineWidth=a,e.setLineDash=[],e.beginPath(),e.moveTo(t,n),e.lineTo(t+r,n),e.stroke()}var Option=class{constructor({fontName:e,fontSize:t}){this.setFont(e,t),this.foreground=`#cccccc`,this.background=`#2d2d2d`}setFont(e,t){let n=t+`px `+e,[r,i,a]=computeFontSize(n);this.fontName=e,this.fontSize=t,this.fontWidth=r,this.fontHeight=i,this.fontAscent=a,this.font=n}};function getLemEditorElement(){return document.getElementById(`lem-editor`)}function normalizeWheelDelta(e,t,n,r){switch(n){case 0:return{dx:e/r,dy:t/r};case 2:return{dx:e*20,dy:t*20};default:return{dx:e,dy:t}}}function extractWholeLines(e,t){let n=Math.trunc(e),r=Math.trunc(t);return{scrollX:n,scrollY:r,remainderX:e-n,remainderY:t-r}}function cursorPosition(e,t){let[n,r]=t.getDisplayRectangle(),i=e.clientX-n,a=e.clientY-r;return{pixelX:i,pixelY:a,x:Math.floor(i/t.option.fontWidth),y:Math.floor(a/t.option.fontHeight)}}function makeWheelHandler(e){let t={x:0,y:0},n=!1,r={pixelX:0,pixelY:0,x:0,y:0};return i=>{i.preventDefault(),r=cursorPosition(i,e);let{dx:a,dy:o}=normalizeWheelDelta(i.deltaX,i.deltaY,i.deltaMode,e.option.fontHeight);t={x:t.x+a,y:t.y+o},n||(n=!0,requestAnimationFrame(()=>{n=!1;let{scrollX:i,scrollY:a,remainderX:o,remainderY:s}=extractWholeLines(t.x,t.y);t={x:o,y:s},(i!==0||a!==0)&&e.jsonrpc.notify(`input`,{kind:`wheel`,value:{...r,wheelX:-i,wheelY:-a}})}))}}function addMouseEventListeners({dom:e,editor:t,isDraggable:n,draggableStyle:r}){e.addEventListener(`contextmenu`,e=>{e.preventDefault()});let i=(e,n)=>{e.preventDefault();let[r,i]=t.getDisplayRectangle(),a=e.clientX-r,o=e.clientY-i,s=Math.floor(a/t.option.fontWidth),c=Math.floor(o/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:n,value:{x:s,y:c,pixelX:a,pixelY:o,button:e.button,clicks:e.detail}})};e.addEventListener(`mousedown`,e=>{n&&(document.body.style.cursor=r),t.focusHiddenInput(),i(e,`mousedown`)}),e.addEventListener(`mouseup`,e=>{n&&(document.body.style.cursor=`default`),i(e,`mouseup`)});let a=0;e.addEventListener(`mousemove`,e=>{e.preventDefault();let n=Date.now();if(n-a>50){a=n;let[r,i]=t.getDisplayRectangle(),o=e.clientX-r,s=e.clientY-i,c=Math.floor(o/t.option.fontWidth),l=Math.floor(s/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:`mousemove`,value:{x:c,y:l,pixelX:o,pixelY:s,button:e.buttons===0?null:e.buttons-1}})}}),n&&(e.addEventListener(`mouseover`,()=>{document.body.style.cursor=r}),e.addEventListener(`mouseout`,e=>{e.buttons!==1&&(document.body.style.cursor=`default`)})),e.addEventListener(`wheel`,makeWheelHandler(t))}var zIndexTable={"floating-window":200,modeline:100,"vertical-border":100,"horizontal-border":101};function zindex(e){return zIndexTable[e]||0}var borderOffsetX=5,borderOffsetY=10,BaseSurface=class{constructor({editor:e}){this.editor=e,this.mainDOM=null,this.wrapper=null}delete(){this.wrapper?getLemEditorElement().removeChild(this.wrapper):getLemEditorElement().removeChild(this.mainDOM)}setupDOM({dom:e,isFloating:t,border:n,cssClassName:r}){this.mainDOM=e,t&&n?(this.wrapper=document.createElement(`div`),r&&(this.wrapper.className=r),this.wrapper.style.position=`absolute`,this.wrapper.style.backgroundColor=this.editor.option.background,this.wrapper.style.zIndex=zindex(`floating-window`),this.wrapper.appendChild(e),getLemEditorElement().appendChild(this.wrapper)):(r&&(e.className=r),getLemEditorElement().appendChild(e))}move(e,t){let[n,r]=this.editor.getDisplayRectangle(),i=Math.floor(n+e),a=Math.floor(r+t);this.wrapper?(this.wrapper.style.left=i-borderOffsetX+`px`,this.wrapper.style.top=a-borderOffsetY+`px`,this.mainDOM.style.left=borderOffsetX+`px`,this.mainDOM.style.top=borderOffsetY+`px`):(this.mainDOM.style.left=i+`px`,this.mainDOM.style.top=a+`px`)}_resize(e,t){let n=window.devicePixelRatio||1;this.mainDOM.width=e*n,this.mainDOM.height=t*n,this.mainDOM.style.width=e+`px`,this.mainDOM.style.height=t+`px`,this.wrapper&&(this.wrapper.style.width=e+borderOffsetX*2+`px`,this.wrapper.style.height=t+borderOffsetY*2+`px`)}drawBlock(e,t,n,r,i){}drawText(e,t,n,r,i,a,o){}drawImage(e,t,n,r,i,a,o){}clearImages(e,t){}clearAllImages(){}touch(){}evalIn(code){return eval(code)}},CanvasSurface=class extends BaseSurface{constructor({editor:e,view:t,pixelX:n,pixelY:r,pixelWidth:i,pixelHeight:a,styles:o,isFloating:s,border:c,cssClassName:l}){super({editor:e});let u=this.setupCanvas(o);this.setupDOM({dom:u,isFloating:s,border:c,cssClassName:l}),this.move(n,r),this.resize(i,a),this.drawingQueue=[],addMouseEventListeners({dom:u,editor:e})}setupCanvas(e){let t=document.createElement(`canvas`);if(t.style.position=`absolute`,e)for(let n in e)t.style[n]=e[n];return t}resize(e,t){this._resize(e,t);let n=window.devicePixelRatio||1;this.mainDOM.getContext(`2d`).scale(n,n)}move(e,t){if(super.move(e,t),this.imageEls)for(let[,e]of this.imageEls)this.positionImage(e)}delete(){this.clearAllImages(),super.delete()}drawBlock(e,t,n,r,i){this.drawingQueue.push(function(a){drawBlock({ctx:a,x:e,y:t,width:n,height:r,style:i})})}drawText(e,t,n,r,i,a,o){let s=this.editor.option,c=o||s.fontHeight;this.drawingQueue.push(function(o){if(a=a?`${s.fontSize}px ${a}`:s.font,!i)drawBlock({ctx:o,x:e,y:t,width:r,height:c,style:s.background}),drawText({ctx:o,x:e,y:t,text:n,style:s.foreground,font:a,option:s});else{let{foreground:l,background:u,bold:d,reverse:f,underline:p,cursor:m}=i;if(l||=s.foreground,u||=s.background,f){let e=u;u=l,l=e}m&&(u=s.background),drawBlock({ctx:o,x:e,y:t,width:r,height:c,style:u}),drawText({ctx:o,x:e,y:t,text:n,style:l,font:d?`bold `+a:a,option:s}),p&&drawHorizontalLine({ctx:o,x:e,y:t+s.fontHeight-2,width:r,style:typeof p==`string`?p:l,lineWidth:2})}})}imageBaseLeft(){return parseFloat(this.mainDOM.style.left)||0}imageBaseTop(){return parseFloat(this.mainDOM.style.top)||0}drawImage(e,t,n,r,i,a,o){this.imageEls||=new Map;let s=e+`,`+t,c=this.imageEls.get(s);if(c&&c.url!==o&&(c.el.remove(),this.imageEls.delete(s),c=null),!c){let e=document.createElement(`img`);e.style.position=`absolute`,e.style.pointerEvents=`none`,e.style.zIndex=`1`,e.src=o,this.mainDOM.parentNode.appendChild(e),c={el:e,url:o},this.imageEls.set(s,c)}c.x=e,c.y=t,c.width=n,c.height=r,c.clipWidth=i,c.clipHeight=a,this.positionImage(c)}positionImage(e){e.el.style.left=this.imageBaseLeft()+e.x+`px`,e.el.style.top=this.imageBaseTop()+e.y+`px`,e.el.style.width=e.width+`px`,e.el.style.height=e.height+`px`;let t=e.clipWidth==null?0:Math.max(0,e.width-e.clipWidth),n=e.clipHeight==null?0:Math.max(0,e.height-e.clipHeight);e.el.style.clipPath=t>0||n>0?`inset(0px ${t}px ${n}px 0px)`:``}clearImages(e,t){if(this.imageEls)for(let[n,r]of this.imageEls){let i=r.y+(r.height||0);r.ye&&(r.el.remove(),this.imageEls.delete(n))}}clearAllImages(){if(this.imageEls){for(let[,e]of this.imageEls)e.el.remove();this.imageEls.clear()}}touch(){let e=this.mainDOM.getContext(`2d`);for(let t of this.drawingQueue)t(e);this.drawingQueue=[]}activate(){this.mainDOM.dataset.store=`active`}deactivate(){this.mainDOM.dataset.store=`inactive`}},HTMLSurface=class extends BaseSurface{constructor({editor:e,pixelX:t,pixelY:n,pixelWidth:r,pixelHeight:i,styles:a,option:o,isFloating:s,border:c,html:l}){super({editor:e});let u=document.createElement(`iframe`);this.setupDOM({dom:u,isFloating:s,border:c}),u.style.position=`absolute`,u.style.backgroundColor=o.background,u.setAttribute(`sandbox`,`allow-scripts allow-same-origin`),u.srcdoc=l,u.addEventListener(`load`,()=>{let e=u.contentWindow;e.invokeLem=(e,t)=>parent.postMessage({type:`invoke-lem`,method:e,args:t})}),this.iframe=u,this.move(t,n),this.resize(r,i)}resize(e,t){this._resize(e,t)}update(e){let t=this.iframe.contentWindow.scrollY;this.iframe.srcdoc=e,this.iframe.onload=()=>{this.iframe.onload=null,this.iframe.contentWindow.scrollTo(0,t)}}evalIn(e){return this.iframe.contentWindow.eval(e)}},VerticalBorder=class{constructor({x:e,y:t,height:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__vertical-border`,this.line.style.height=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`vertical-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`col-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=Math.floor(n+e-this.option.fontWidth/2)+`px`,this.line.style.top=r+t+`px`}resize(e){this.line.style.height=e+`px`}},HorizontalBorder=class{constructor({x:e,y:t,width:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__horizontal-border`,this.line.style.width=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`horizontal-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`row-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=n+e+`px`,this.line.style.top=Math.floor(r+t-4)+`px`}resize(e){this.line.style.width=e+`px`}},viewStyles={header:()=>{},tile:()=>{},floating:e=>({boxSizing:`border-box`,borderColor:e.foreground,backgroundColor:e.background})};function getViewStyle(e,t){return viewStyles[e](t)||{}}var View=class{constructor({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,option:h,editor:g}){switch(this.option=h,this.id=e,this.x=t,this.y=n,this.width=r,this.height=i,this.pixelX=a,this.pixelY=o,this.pixelWidth=s,this.pixelHeight=c,this.useModeline=l,this.kind=u,this.type=d,this.border=p,this.borderShape=m,this.editor=g,this.bottomBar=null,this.leftsideBar=null,u){case`tile`:this.mainSurface=this.makeSurface(d,f),this.leftSideBar=new VerticalBorder({x:a,y:o,height:c+(l?h.fontHeight:0),option:h,editor:g}),l||(this.bottomBar=new HorizontalBorder({x:a,y:o+c-h.fontHeight,width:s,option:h,editor:g}));break;case`header`:this.mainSurface=this.makeSurface(d,f);break;case`floating`:this.mainSurface=this.makeSurface(d,f),m===`left-border`&&(this.leftSideBar=new VerticalBorder({x:a,y:o,height:c,option:h,editor:g}));break}this.modelineSurface=l?this.makeModelineSurface():null}delete(){this.mainSurface.delete(),this.modelineSurface&&this.modelineSurface.delete(),this.leftSideBar&&this.leftSideBar.delete(),this.bottomBar&&this.bottomBar.delete()}move(e,t,n,r){this.x=e,this.y=t,this.pixelX=n,this.pixelY=r,this.mainSurface.move(n,r),this.modelineSurface&&this.modelineSurface.move(n,r+this.pixelHeight),this.leftSideBar&&this.leftSideBar.move(n,r),this.bottomBar&&this.bottomBar.move(n,r+this.pixelHeight)}resize(e,t,n,r){this.width=e,this.height=t,this.pixelWidth=n,this.pixelHeight=r,this.mainSurface.resize(n,r),this.modelineSurface&&(this.modelineSurface.move(this.pixelX,this.pixelY+r),this.modelineSurface.resize(n,this.option.fontHeight)),this.leftSideBar&&this.leftSideBar.resize(r+(this.modelineSurface?this.option.fontHeight:0)),this.bottomBar&&this.bottomBar.resize(n)}clear(){this.mainSurface.drawBlock(0,0,this.pixelWidth,this.pixelHeight,this.option.background),this.mainSurface.clearImages(0,this.pixelHeight)}clearEol(e,t,n){n??=this.option.fontHeight,this.mainSurface.drawBlock(e,t,this.pixelWidth-e,n,this.option.background),this.mainSurface.clearImages(t,t+n)}clearEob(e,t){this.mainSurface.drawBlock(e,t,this.pixelWidth,this.pixelHeight-t,this.option.background),this.mainSurface.clearImages(t,this.pixelHeight)}print(e,t,n,r,i,a,o){this.mainSurface.drawText(e,t,n,r,i,a,o)}printImage(e,t,n,r,i,a,o){this.mainSurface.drawImage(e,t,n,r,i,a,o)}printToModeline(e,t,n,r,i,a){this.modelineSurface&&this.modelineSurface.drawText(e,t,n,r,i,null,a)}touch(e){this.mainSurface.touch(),this.modelineSurface&&(this.modelineSurface.touch(),e?this.modelineSurface.activate():this.modelineSurface.deactivate())}makeSurface(e,t){switch(e){case`html`:return this.makeHTMLSurface(t);case`editor`:return this.makeEditorSurface();default:console.error(`unknown type: ${e}`)}}makeHTMLSurface(e){return new HTMLSurface({editor:this.editor,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),option:this.option,isFloating:this.kind===`floating`,border:this.border,html:e})}makeEditorSurface(){let e=this.borderShape===`left-border`?0:this.border,t=this.kind===`floating`;return new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),editor:this.editor,border:e,isFloating:t,view:this,cssClassName:t&&e?`lem-editor__floating-window--bordered`:null})}makeModelineSurface(){let e=new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY+this.pixelHeight,pixelWidth:this.pixelWidth,pixelHeight:this.option.fontHeight,editor:this.editor,view:this,styles:{zIndex:zindex(`modeline`)},cssClassName:`lem-editor__mode-line`});return addMouseEventListeners({dom:e.mainDOM,editor:this.editor,isDraggable:!0,draggableStyle:`row-resize`}),e}changeToHTMLContent(e){this.mainSurface.constructor.name===`HTMLSurface`?this.mainSurface.update(e):(this.mainSurface.delete(),this.mainSurface=this.makeHTMLSurface(e))}changeToEditorContent(){this.mainSurface.delete(),this.mainSurface=this.makeEditorSurface()}evalIn(e){return this.mainSurface.evalIn(e)}};function isPasteKeyEvent(e){return isMacOS()?e.metaKey&&e.key===`v`:e.ctrlKey&&e.shiftKey&&e.key===`V`}var Input=class{constructor(e){let t=e.option;this.editor=e,this.composition=!1,this.ignoreKeydownAfterCompositionend=!1,this.span=document.createElement(`span`),this.span.style.color=t.foreground,this.span.style.backgroundColor=t.background,this.span.style.position=`absolute`,this.span.style.zIndex=1e6,this.span.style.top=`0`,this.span.style.left=`0`,this.span.style.font=t.font,this.input=document.createElement(`input`),this.input.style.backgroundColor=`transparent`,this.input.style.color=`transparent`,this.input.style.width=`0`,this.input.style.padding=`0`,this.input.style.margin=`0`,this.input.style.border=`none`,this.input.style.position=`absolute`,this.input.style.zIndex=`-10`,this.input.style.top=`0`,this.input.style.left=`0`,this.input.style.font=t.font,this.input.addEventListener(`blur`,e=>{this.input.focus()}),this.input.addEventListener(`input`,e=>{this.composition===!1&&(this.input.value=``,this.span.innerHTML=``,this.input.style.width=`0`,isMacOS()||this.editor.emitInputString(e.data))}),this.input.addEventListener(`paste`,async e=>{e.preventDefault();let t=e.clipboardData||window.Clipboard.data,n=t?.getData(`text`)??t?.getData(`text/plain`);if(n&&n.length>0){this.editor.emitInputString(n);return}try{if(navigator.clipboard?.readText){let e=await navigator.clipboard.readText();if(e&&e.length>0){this.editor.emitInputString(e);return}}}catch(e){console.warn(`clipboard.readText() failed:`,e)}alert(`Paste failed (permission/environment restriction`)}),this.input.addEventListener(`keydown`,e=>{if(!isPasteKeyEvent(e)&&!(e.isComposing||this.composition)&&e.key!==`Process`){if(this.ignoreKeydownAfterCompositionend&&(isSafari||isMacOS())){e.preventDefault(),this.ignoreKeydownAfterCompositionend=!1;return}if(!(!isMacOS()&&!e.ctrlKey&&!e.altKey&&e.key.length===1)&&(e.preventDefault(),e.isComposing!==!0&&e.code!==``))return setTimeout(()=>{this.composition||(this.editor.emitInput(e),this.input.value=``)},0),!1}}),this.input.addEventListener(`compositionstart`,e=>{this.composition=!0,this.span.innerHTML=this.input.value,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionupdate`,e=>{this.span.innerHTML=e.data,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionend`,e=>{this.composition=!1,this.editor.emitInputString(this.input.value),this.input.value=``,this.span.innerHTML=this.input.value,this.input.style.width=`0`,this.ignoreKeydownAfterCompositionend=!0}),document.body.appendChild(this.input),document.body.appendChild(this.span),this.input.focus()}finalize(){document.body.removeChild(this.input),document.body.removeChild(this.span)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.span.style.top=r+t+`px`,this.span.style.left=n+e+`px`,this.input.style.top=this.span.offsetTop+`px`,this.input.style.left=this.span.offsetLeft+`px`}updateForeground(e){this.span.style.color=e}updateBackground(e){this.span.style.backgroundColor=e}},MessageTable=class{constructor(){this.map=new Map}register(e,t){for(let n in t){let r=t[n];this.map.set(n,r),e.on(n,r)}}get(e){return this.map.get(e)}};function getDisplayRectangleDefault(){return[0,0,window.innerWidth,window.innerHeight]}var Editor=class{constructor({getDisplayRectangle:e=getDisplayRectangleDefault,fontName:t,fontSize:n,url:r,onExit:i,onClosed:a}){this.getDisplayRectangle=e,this.option=new Option({fontName:t,fontSize:n}),this.onExit=i,this.input=new Input(this),this.cursors=new Map,this.cursorOverlay=document.createElement(`div`),this.cursorOverlay.className=`lem-cursor`,this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.cursorOverlay.style.backgroundColor=`#ffffff`,this.cursorType=`box`,this.viewMap=new Map,this.jsonrpc=new JSONRPC(r,{onClosed:()=>{a()}}),this.messageTable=new MessageTable,this.messageTable.register(this.jsonrpc,{"update-foreground":this.updateForeground.bind(this),"update-background":this.updateBackground.bind(this),"make-view":this.makeView.bind(this),"delete-view":this.deleteView.bind(this),"resize-view":this.resize.bind(this),"move-view":this.move.bind(this),"redraw-view-after":this.redrawViewAfter.bind(this),clear:this.clear.bind(this),"clear-eol":this.clearEol.bind(this),"clear-eob":this.clearEob.bind(this),put:this.put.bind(this),"put-image":this.putImage.bind(this),"modeline-put":this.modelinePut.bind(this),"update-display":this.updateDisplay.bind(this),"move-cursor":this.moveCursor.bind(this),"change-view":this.changeView.bind(this),"resize-display":this.resizeDisplay.bind(this),bulk:this.bulk.bind(this),exit:this.exitEditor.bind(this),"get-clipboard-text":this.getClipboardText.bind(this),"set-clipboard-text":this.setClipboardText.bind(this),"js-eval":this.jsEval.bind(this),"set-font":this.setFont.bind(this),"get-font":this.getFont.bind(this),"get-display-size":this.getDisplaySize.bind(this),"load-css":this.loadCSS.bind(this),"update-cursor-shape":this.updateCursorShape.bind(this)}),this.login(),this.boundedHandleResize=this.handleResize.bind(this),this.focusHiddenInput=this.focusHiddenInput.bind(this)}init(){window.addEventListener(`resize`,this.boundedHandleResize),document.getElementsByTagName(`html`)[0].style[`background-color`]=`#333`,getLemEditorElement().appendChild(this.cursorOverlay)}finalize(){window.removeEventListener(`resize`,this.boundedHandleResize),this.input.finalize(),this.cursorOverlay.parentNode&&this.cursorOverlay.parentNode.removeChild(this.cursorOverlay)}closeConnection(){this.jsonrpc.close()}emitInput(e){let t=convertKeyEvent(e);if(t){if(t.key===`]`&&t.ctrl&&!t.meta&&!t.super&&!t.shift){this.jsonrpc.notify(`input`,{kind:`abort`});return}t.key!==`Unidentified`&&this.jsonrpc.notify(`input`,{kind:`key`,value:t})}}emitInputString(e){e?this.jsonrpc.notify(`input`,{kind:`input-string`,value:e}):console.error(`unexpected argument`,e)}redrawParams(){return{size:this.getDisplaySize(),fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent}}handleResize(e){this.jsonrpc.notify(`redraw`,this.redrawParams())}focusHiddenInput(){let e=this.input?.input;if(e){try{window.focus()}catch{}requestAnimationFrame(()=>{setTimeout(()=>{e.focus({preventScroll:!0})},0)})}}sendNotification(e,t){this.jsonrpc.notify(e,t)}request(e,t,n){this.jsonrpc.request(e,t,n)}getDisplaySize(){let[e,t,n,r]=this.getDisplayRectangle();return{width:Math.floor(n/this.option.fontWidth),height:Math.floor(r/this.option.fontHeight)}}callMessage(e,t){this.messageTable.get(e)(t)}findViewById(e){return this.viewMap.get(e)}login(){this.jsonrpc.request(`login`,{size:this.getDisplaySize(),foreground:this.option.foreground,background:this.option.background,fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent},e=>{if(this.updateForeground(e.foreground),this.updateBackground(e.background),e.views)for(let t of e.views)this.makeView(t);this.jsonrpc.notify(`redraw`,this.redrawParams())})}updateForeground(e){e!=null&&(this.option.foreground=e,this.input.updateForeground(e))}updateBackground(e){if(e==null)return;this.option.background=e,this.input.updateBackground(e);let t=getLemEditorElement();t.style.backgroundColor=e}makeView({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,use_modeline:l,kind:u,type:d,content:f,border:p,border_shape:m}){let h=new View({option:this.option,id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,editor:this});this.viewMap.set(e,h)}deleteView({viewInfo:{id:e}}){this.findViewById(e).delete(),this.viewMap.delete(e)}resize({viewInfo:{id:e},width:t,height:n,pixelWidth:r,pixelHeight:i}){let a=this.findViewById(e);a?a.resize(t,n,r,i):console.warn(`resize: view not found for id ${e}`)}move({viewInfo:{id:e},x:t,y:n,pixelX:r,pixelY:i}){let a=this.findViewById(e);a?a.move(t,n,r,i):console.warn(`move: view not found for id ${e}`)}redrawViewAfter({viewInfo:{id:e},isActive:t}){this.findViewById(e).touch(t)}clear({viewInfo:{id:e}}){this.findViewById(e).clear()}clearEol({viewInfo:{id:e},x:t,y:n,height:r}){this.findViewById(e).clearEol(t,n,r)}clearEob({viewInfo:{id:e},x:t,y:n}){this.findViewById(e).clearEob(t,n)}put({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,font:o,height:s}){this.findViewById(e).print(t,n,r,i,a,o,s)}putImage({viewInfo:{id:e},x:t,y:n,pixelWidth:r,pixelHeight:i,clipWidth:a,clipHeight:o,url:s}){this.findViewById(e).printImage(t,n,r,i,a,o,s)}modelinePut({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,height:o}){this.findViewById(e).printToModeline(t,n,r,i,a,o)}updateDisplay(){}moveCursor({viewInfo:{id:e},x:t,y:n,color:r,cursorText:i,cursorForeground:a}){let o=this.findViewById(e),[s,c]=this.getDisplayRectangle(),l=o.pixelX+t,u=o.pixelY+n;this.input.move(l,u);let d=r||this.option.foreground,f=a||this.option.background,p=this.cursorOverlay;switch(this.cursorType){case`bar`:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=`2px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;case`underline`:p.style.left=s+l+`px`,p.style.top=c+u+this.option.fontHeight-2+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=`2px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;default:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.style.font=this.option.font,p.style.paddingTop=textOffsetY+`px`,p.textContent=i||``,p.style.color=f;break}p.style.animation=`none`,p.offsetHeight,p.style.animation=``}updateCursorShape({cursorType:e}){this.cursorType=e||`box`}changeView({viewInfo:{id:e},type:t,content:n}){let r=this.findViewById(e);switch(t){case`html`:r.changeToHTMLContent(n);break;case`editor`:r.changeToEditorContent();break}}resizeDisplay({width:e,height:t}){let n=getLemEditorElement();n.style.width=Math.floor(e*this.option.fontWidth)+`px`,n.style.height=Math.floor(t*this.option.fontHeight)+`px`}bulk(e){for(let{method:t,argument:n}of e)this.callMessage(t,n)}exitEditor(){this.onExit&&this.onExit()}getClipboardText(){navigator.clipboard?.readText().then(e=>{this.jsonrpc.notify(`got-clipboard-text`,{text:e})})}setClipboardText({text:e}){navigator.clipboard&&navigator.clipboard.writeText(e)}jsEval({viewInfo:{id:e},code:t}){let n=this.findViewById(e).evalIn(t);return n&&n.toString()}setFont({fontName:e,fontSize:t}){this.option.setFont(e||this.option.fontName,t||this.option.fontSize),this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.jsonrpc.notify(`redraw`,this.redrawParams())}getFont(){return{name:this.option.fontName,size:this.option.fontSize}}loadCSS({content:e}){let t=document.createElement(`style`);t.textContent=e,document.head.appendChild(t)}notifyToServer(e,t){this.jsonrpc.notify(`invoke`,{method:e,args:t})}},canvas=document.querySelector(`#editor`);async function main(){await Promise.all([document.fonts.load(`19px file-icons`),document.fonts.load(`19px AllTheIcons`),document.fonts.load(`19px fontawesome`),document.fonts.load(`19px material-design-icons`),document.fonts.load(`19px octicons`)]),await document.fonts.ready;let e=new Editor({canvas,fontName:`Monospace`,fontSize:18,url:`${window.location.protocol===`https:`?`wss`:`ws`}://${window.location.hostname}:${window.location.port}`,onExit:null,onClosed:null});window.addEventListener(`message`,t=>{t.data.type===`invoke-lem`&&e.notifyToServer(t.data.method,t.data.args)}),e.init()}main(); \ No newline at end of file +var __defProp=Object.defineProperty,__commonJSMin=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),__exportAll=(e,t)=>{let n={};for(var r in e)__defProp(n,r,{get:e[r],enumerable:!0});return t||__defProp(n,Symbol.toStringTag,{value:`Module`}),n};(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var require_models=__commonJSMin((e=>{var t=e&&e.__extends||(function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};return function(t,n){if(typeof n!=`function`&&n!==null)throw TypeError(`Class extends value `+String(n)+` is not a constructor or null`);e(t,n);function r(){this.constructor=t}t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}})();Object.defineProperty(e,"__esModule",{value:!0}),e.createJSONRPCNotification=e.createJSONRPCRequest=e.createJSONRPCSuccessResponse=e.createJSONRPCErrorResponse=e.JSONRPCErrorCode=e.JSONRPCErrorException=e.isJSONRPCResponses=e.isJSONRPCResponse=e.isJSONRPCRequests=e.isJSONRPCRequest=e.isJSONRPCID=e.JSONRPC=void 0,e.JSONRPC=`2.0`,e.isJSONRPCID=function(e){return typeof e==`string`||typeof e==`number`||e===null},e.isJSONRPCRequest=function(t){return t.jsonrpc===e.JSONRPC&&t.method!==void 0&&t.result===void 0&&t.error===void 0},e.isJSONRPCRequests=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCRequest)},e.isJSONRPCResponse=function(t){return t.jsonrpc===e.JSONRPC&&t.id!==void 0&&(t.result!==void 0||t.error!==void 0)},e.isJSONRPCResponses=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCResponse)};var n=function(e,t,n){var r={code:e,message:t};return n!=null&&(r.data=n),r};e.JSONRPCErrorException=function(e){t(r,e);function r(t,n,i){var a=e.call(this,t)||this;return Object.setPrototypeOf(a,r.prototype),a.code=n,a.data=i,a}return r.prototype.toObject=function(){return n(this.code,this.message,this.data)},r}(Error),(function(e){e[e.ParseError=-32700]=`ParseError`,e[e.InvalidRequest=-32600]=`InvalidRequest`,e[e.MethodNotFound=-32601]=`MethodNotFound`,e[e.InvalidParams=-32602]=`InvalidParams`,e[e.InternalError=-32603]=`InternalError`})(e.JSONRPCErrorCode||={}),e.createJSONRPCErrorResponse=function(t,r,i,a){return{jsonrpc:e.JSONRPC,id:t,error:n(r,i,a)}},e.createJSONRPCSuccessResponse=function(t,n){return{jsonrpc:e.JSONRPC,id:t,result:n??null}},e.createJSONRPCRequest=function(t,n,r){return{jsonrpc:e.JSONRPC,id:t,method:n,params:r}},e.createJSONRPCNotification=function(t,n){return{jsonrpc:e.JSONRPC,method:t,params:n}}})),require_internal=__commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.DefaultErrorCode=void 0,e.DefaultErrorCode=0})),require_client=__commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{Object.defineProperty(e,"__esModule",{value:!0})})),require_server=__commonJSMin((e=>{var t=e&&e.__assign||function(){return t=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__createBinding||(Object.create?(function(e,t,n,r){r===void 0&&(r=n);var i=Object.getOwnPropertyDescriptor(t,n);(!i||(`get`in i?!t.__esModule:i.writable||i.configurable))&&(i={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,i)}):(function(e,t,n,r){r===void 0&&(r=n),e[r]=t[n]})),n=e&&e.__exportStar||function(e,n){for(var r in e)r!=="default"&&!Object.prototype.hasOwnProperty.call(n,r)&&t(n,e,r)};Object.defineProperty(e,"__esModule",{value:!0}),n(require_client(),e),n(require_interfaces(),e),n(require_models(),e),n(require_server(),e),n(require_server_and_client(),e)})),import_dist=require_dist(),JSONRPC=class{constructor(e,{onConnected:t,onClosed:n}){this.url=e,this.onConnected=t,this.onClosed=n,this.messageQueue=[],this.serverAndClient=null,this.connect(),this.connectionEstablished=!1,this.timerId=null,this.closed=!1}close(){this.timerId&&clearTimeout(this.timerId),this.webSocket.close(),this.closed=!0}on(e,t){this.serverAndClient.addMethod(e,t)}async requestInternal(e,t,n){let r=await this.serverAndClient.request(e,t);n&&n(r)}requestMessageQueue(){this.messageQueue.forEach(e=>{let[t,n,r]=e;this.requestInternal(t,n,r)}),this.messageQueue=[]}request(e,t,n){this.webSocket.readyState===WebSocket.OPEN?this.requestInternal(e,t,n):this.messageQueue.push([e,t,n])}notify(e,t){switch(this.webSocket.readyState){case WebSocket.OPEN:this.serverAndClient.notify(e,t);break;case WebSocket.CLOSED:break}}connect(e){this.closed||(console.log(`connect`,this.url),this.webSocket=new WebSocket(this.url),this.serverAndClient||=new import_dist.JSONRPCServerAndClient(new import_dist.JSONRPCServer,new import_dist.JSONRPCClient(e=>{try{return this.webSocket.send(JSON.stringify(e)),Promise.resolve()}catch(e){return Promise.reject(e)}})),this.webSocket.onmessage=e=>{this.serverAndClient.receiveAndSend(JSON.parse(e.data.toString()))},this.webSocket.onopen=()=>{console.log(`WebSocket connection established`),this.connectionEstablished=!0,this.onConnected&&this.onConnected(),this.requestMessageQueue()},this.webSocket.onclose=e=>{console.error(`WebScoket closed`,e),this.serverAndClient.rejectAllPendingRequests(`Connection is closed (${e.reason}).`),this.connectionEstablished&&this.onClosed(),this.timerId=setTimeout(()=>{this.connect()},3e3)},this.webSocket.onerror=e=>{console.error(`WebSocket error:`,e),this.webSocket.close()})}},keyevent_exports=__exportAll({convertKeyEvent:()=>convertKeyEvent}),modifierKeys=[`Shift`,`Control`,`Alt`,`Meta`,`CapsLock`],convertKeyTable={Enter:`Return`,ArrowRight:`Right`,ArrowLeft:`Left`,ArrowUp:`Up`,ArrowDown:`Down`,"¡":`1`,"™":`2`,"£":`3`,"¢":`4`,"∞":`5`,"§":`6`,"¶":`7`,"•":`8`,ª:`9`,º:`0`,"–":`-`,"≠":`=`,"“":`[`,"‘":`]`,"«":`\\`,"…":`;`,æ:`'`,"≤":`,`,"≥":`.`,"÷":`/`,"⁄":`!`,"€":`@`,"‹":`#`,"›":`$`,fi:`%`,fl:`^`,"‡":`&`,"°":`*`,"·":`(`,"‚":`)`,"—":`_`,"±":`+`,"”":`{`,"’":`}`,"»":`|`,Ú:`:`,Æ:`"`,"¯":`<`,"˘":`>`,"¿":`?`,œ:`q`,"∑":`w`,"´":`e`,"®":`r`,"†":`t`,"¥":`y`,"¨":`u`,ˆ:`i`,ø:`o`,π:`p`,å:`a`,ß:`s`,"∂":`d`,ƒ:`f`,"©":`g`,"˙":`h`,"∆":`j`,"˚":`k`,"¬":`l`,Ω:`z`,"≈":`x`,ç:`c`,"√":`v`,"∫":`b`,"˜":`n`,µ:`m`,Œ:`Q`,"„":`W`,"´":`E`,"‰":`R`,ˇ:`T`,Á:`Y`,"¨":`U`,ˆ:`I`,Ø:`O`,"∏":`P`,Å:`A`,Í:`S`,Î:`D`,Ï:`F`,"˝":`G`,Ó:`H`,Ô:`J`,"":`K`,Ò:`L`,"¸":`Z`,"˛":`X`,Ç:`C`,"◊":`V`,ı:`B`,"˜":`N`,Â:`M`};function getKey(e){return e.altKey?convertKeyTable[e.key]||(e.code.startsWith(`Key`)?e.code[3].toLowerCase():null)||e.key:convertKeyTable[e.key]||e.key}function convertKeyEvent(e){return modifierKeys.indexOf(e.key)===-1?{key:getKey(e),ctrl:e.ctrlKey,meta:e.altKey,super:e.metaKey,shift:e.shiftKey}:null}var lib_exports=__exportAll({computeWidth:()=>computeWidth,eawVersion:()=>version,getEAW:()=>getEAW}),defs=[[0,31,`N`],[32,126,`Na`],[127,160,`N`],[161,161,`A`],[162,163,`Na`],[164,164,`A`],[165,166,`Na`],[167,168,`A`],[169,169,`N`],[170,170,`A`],[171,171,`N`],[172,172,`Na`],[173,174,`A`],[175,175,`Na`],[176,180,`A`],[181,181,`N`],[182,186,`A`],[187,187,`N`],[188,191,`A`],[192,197,`N`],[198,198,`A`],[199,207,`N`],[208,208,`A`],[209,214,`N`],[215,216,`A`],[217,221,`N`],[222,225,`A`],[226,229,`N`],[230,230,`A`],[231,231,`N`],[232,234,`A`],[235,235,`N`],[236,237,`A`],[238,239,`N`],[240,240,`A`],[241,241,`N`],[242,243,`A`],[244,246,`N`],[247,250,`A`],[251,251,`N`],[252,252,`A`],[253,253,`N`],[254,254,`A`],[255,256,`N`],[257,257,`A`],[258,272,`N`],[273,273,`A`],[274,274,`N`],[275,275,`A`],[276,282,`N`],[283,283,`A`],[284,293,`N`],[294,295,`A`],[296,298,`N`],[299,299,`A`],[300,304,`N`],[305,307,`A`],[308,311,`N`],[312,312,`A`],[313,318,`N`],[319,322,`A`],[323,323,`N`],[324,324,`A`],[325,327,`N`],[328,331,`A`],[332,332,`N`],[333,333,`A`],[334,337,`N`],[338,339,`A`],[340,357,`N`],[358,359,`A`],[360,362,`N`],[363,363,`A`],[364,461,`N`],[462,462,`A`],[463,463,`N`],[464,464,`A`],[465,465,`N`],[466,466,`A`],[467,467,`N`],[468,468,`A`],[469,469,`N`],[470,470,`A`],[471,471,`N`],[472,472,`A`],[473,473,`N`],[474,474,`A`],[475,475,`N`],[476,476,`A`],[477,592,`N`],[593,593,`A`],[594,608,`N`],[609,609,`A`],[610,707,`N`],[708,708,`A`],[709,710,`N`],[711,711,`A`],[712,712,`N`],[713,715,`A`],[716,716,`N`],[717,717,`A`],[718,719,`N`],[720,720,`A`],[721,727,`N`],[728,731,`A`],[732,732,`N`],[733,733,`A`],[734,734,`N`],[735,735,`A`],[736,767,`N`],[768,879,`A`],[880,912,`N`],[913,929,`A`],[930,930,`N`],[931,937,`A`],[938,944,`N`],[945,961,`A`],[962,962,`N`],[963,969,`A`],[970,1024,`N`],[1025,1025,`A`],[1026,1039,`N`],[1040,1103,`A`],[1104,1104,`N`],[1105,1105,`A`],[1106,4351,`N`],[4352,4447,`W`],[4448,8207,`N`],[8208,8208,`A`],[8209,8210,`N`],[8211,8214,`A`],[8215,8215,`N`],[8216,8217,`A`],[8218,8219,`N`],[8220,8221,`A`],[8222,8223,`N`],[8224,8226,`A`],[8227,8227,`N`],[8228,8231,`A`],[8232,8239,`N`],[8240,8240,`A`],[8241,8241,`N`],[8242,8243,`A`],[8244,8244,`N`],[8245,8245,`A`],[8246,8250,`N`],[8251,8251,`A`],[8252,8253,`N`],[8254,8254,`A`],[8255,8307,`N`],[8308,8308,`A`],[8309,8318,`N`],[8319,8319,`A`],[8320,8320,`N`],[8321,8324,`A`],[8325,8360,`N`],[8361,8361,`H`],[8362,8363,`N`],[8364,8364,`A`],[8365,8450,`N`],[8451,8451,`A`],[8452,8452,`N`],[8453,8453,`A`],[8454,8456,`N`],[8457,8457,`A`],[8458,8466,`N`],[8467,8467,`A`],[8468,8469,`N`],[8470,8470,`A`],[8471,8480,`N`],[8481,8482,`A`],[8483,8485,`N`],[8486,8486,`A`],[8487,8490,`N`],[8491,8491,`A`],[8492,8530,`N`],[8531,8532,`A`],[8533,8538,`N`],[8539,8542,`A`],[8543,8543,`N`],[8544,8555,`A`],[8556,8559,`N`],[8560,8569,`A`],[8570,8584,`N`],[8585,8585,`A`],[8586,8591,`N`],[8592,8601,`A`],[8602,8631,`N`],[8632,8633,`A`],[8634,8657,`N`],[8658,8658,`A`],[8659,8659,`N`],[8660,8660,`A`],[8661,8678,`N`],[8679,8679,`A`],[8680,8703,`N`],[8704,8704,`A`],[8705,8705,`N`],[8706,8707,`A`],[8708,8710,`N`],[8711,8712,`A`],[8713,8714,`N`],[8715,8715,`A`],[8716,8718,`N`],[8719,8719,`A`],[8720,8720,`N`],[8721,8721,`A`],[8722,8724,`N`],[8725,8725,`A`],[8726,8729,`N`],[8730,8730,`A`],[8731,8732,`N`],[8733,8736,`A`],[8737,8738,`N`],[8739,8739,`A`],[8740,8740,`N`],[8741,8741,`A`],[8742,8742,`N`],[8743,8748,`A`],[8749,8749,`N`],[8750,8750,`A`],[8751,8755,`N`],[8756,8759,`A`],[8760,8763,`N`],[8764,8765,`A`],[8766,8775,`N`],[8776,8776,`A`],[8777,8779,`N`],[8780,8780,`A`],[8781,8785,`N`],[8786,8786,`A`],[8787,8799,`N`],[8800,8801,`A`],[8802,8803,`N`],[8804,8807,`A`],[8808,8809,`N`],[8810,8811,`A`],[8812,8813,`N`],[8814,8815,`A`],[8816,8833,`N`],[8834,8835,`A`],[8836,8837,`N`],[8838,8839,`A`],[8840,8852,`N`],[8853,8853,`A`],[8854,8856,`N`],[8857,8857,`A`],[8858,8868,`N`],[8869,8869,`A`],[8870,8894,`N`],[8895,8895,`A`],[8896,8977,`N`],[8978,8978,`A`],[8979,8985,`N`],[8986,8987,`W`],[8988,9e3,`N`],[9001,9002,`W`],[9003,9192,`N`],[9193,9196,`W`],[9197,9199,`N`],[9200,9200,`W`],[9201,9202,`N`],[9203,9203,`W`],[9204,9311,`N`],[9312,9449,`A`],[9450,9450,`N`],[9451,9547,`A`],[9548,9551,`N`],[9552,9587,`A`],[9588,9599,`N`],[9600,9615,`A`],[9616,9617,`N`],[9618,9621,`A`],[9622,9631,`N`],[9632,9633,`A`],[9634,9634,`N`],[9635,9641,`A`],[9642,9649,`N`],[9650,9651,`A`],[9652,9653,`N`],[9654,9655,`A`],[9656,9659,`N`],[9660,9661,`A`],[9662,9663,`N`],[9664,9665,`A`],[9666,9669,`N`],[9670,9672,`A`],[9673,9674,`N`],[9675,9675,`A`],[9676,9677,`N`],[9678,9681,`A`],[9682,9697,`N`],[9698,9701,`A`],[9702,9710,`N`],[9711,9711,`A`],[9712,9724,`N`],[9725,9726,`W`],[9727,9732,`N`],[9733,9734,`A`],[9735,9736,`N`],[9737,9737,`A`],[9738,9741,`N`],[9742,9743,`A`],[9744,9747,`N`],[9748,9749,`W`],[9750,9755,`N`],[9756,9756,`A`],[9757,9757,`N`],[9758,9758,`A`],[9759,9791,`N`],[9792,9792,`A`],[9793,9793,`N`],[9794,9794,`A`],[9795,9799,`N`],[9800,9811,`W`],[9812,9823,`N`],[9824,9825,`A`],[9826,9826,`N`],[9827,9829,`A`],[9830,9830,`N`],[9831,9834,`A`],[9835,9835,`N`],[9836,9837,`A`],[9838,9838,`N`],[9839,9839,`A`],[9840,9854,`N`],[9855,9855,`W`],[9856,9874,`N`],[9875,9875,`W`],[9876,9885,`N`],[9886,9887,`A`],[9888,9888,`N`],[9889,9889,`W`],[9890,9897,`N`],[9898,9899,`W`],[9900,9916,`N`],[9917,9918,`W`],[9919,9919,`A`],[9920,9923,`N`],[9924,9925,`W`],[9926,9933,`A`],[9934,9934,`W`],[9935,9939,`A`],[9940,9940,`W`],[9941,9953,`A`],[9954,9954,`N`],[9955,9955,`A`],[9956,9959,`N`],[9960,9961,`A`],[9962,9962,`W`],[9963,9969,`A`],[9970,9971,`W`],[9972,9972,`A`],[9973,9973,`W`],[9974,9977,`A`],[9978,9978,`W`],[9979,9980,`A`],[9981,9981,`W`],[9982,9983,`A`],[9984,9988,`N`],[9989,9989,`W`],[9990,9993,`N`],[9994,9995,`W`],[9996,10023,`N`],[10024,10024,`W`],[10025,10044,`N`],[10045,10045,`A`],[10046,10059,`N`],[10060,10060,`W`],[10061,10061,`N`],[10062,10062,`W`],[10063,10066,`N`],[10067,10069,`W`],[10070,10070,`N`],[10071,10071,`W`],[10072,10101,`N`],[10102,10111,`A`],[10112,10132,`N`],[10133,10135,`W`],[10136,10159,`N`],[10160,10160,`W`],[10161,10174,`N`],[10175,10175,`W`],[10176,10213,`N`],[10214,10221,`Na`],[10222,10628,`N`],[10629,10630,`Na`],[10631,11034,`N`],[11035,11036,`W`],[11037,11087,`N`],[11088,11088,`W`],[11089,11092,`N`],[11093,11093,`W`],[11094,11097,`A`],[11098,11903,`N`],[11904,11929,`W`],[11930,11930,`N`],[11931,12019,`W`],[12020,12031,`N`],[12032,12245,`W`],[12246,12271,`N`],[12272,12287,`W`],[12288,12288,`F`],[12289,12350,`W`],[12351,12352,`N`],[12353,12438,`W`],[12439,12440,`N`],[12441,12543,`W`],[12544,12548,`N`],[12549,12591,`W`],[12592,12592,`N`],[12593,12686,`W`],[12687,12687,`N`],[12688,12771,`W`],[12772,12782,`N`],[12783,12830,`W`],[12831,12831,`N`],[12832,12871,`W`],[12872,12879,`A`],[12880,19903,`W`],[19904,19967,`N`],[19968,42124,`W`],[42125,42127,`N`],[42128,42182,`W`],[42183,43359,`N`],[43360,43388,`W`],[43389,44031,`N`],[44032,55203,`W`],[55204,57343,`N`],[57344,63743,`A`],[63744,64255,`W`],[64256,65023,`N`],[65024,65039,`A`],[65040,65049,`W`],[65050,65071,`N`],[65072,65106,`W`],[65107,65107,`N`],[65108,65126,`W`],[65127,65127,`N`],[65128,65131,`W`],[65132,65280,`N`],[65281,65376,`F`],[65377,65470,`H`],[65471,65473,`N`],[65474,65479,`H`],[65480,65481,`N`],[65482,65487,`H`],[65488,65489,`N`],[65490,65495,`H`],[65496,65497,`N`],[65498,65500,`H`],[65501,65503,`N`],[65504,65510,`F`],[65511,65511,`N`],[65512,65518,`H`],[65519,65532,`N`],[65533,65533,`A`],[65534,94175,`N`],[94176,94180,`W`],[94181,94191,`N`],[94192,94193,`W`],[94194,94207,`N`],[94208,100343,`W`],[100344,100351,`N`],[100352,101589,`W`],[101590,101631,`N`],[101632,101640,`W`],[101641,110575,`N`],[110576,110579,`W`],[110580,110580,`N`],[110581,110587,`W`],[110588,110588,`N`],[110589,110590,`W`],[110591,110591,`N`],[110592,110882,`W`],[110883,110897,`N`],[110898,110898,`W`],[110899,110927,`N`],[110928,110930,`W`],[110931,110932,`N`],[110933,110933,`W`],[110934,110947,`N`],[110948,110951,`W`],[110952,110959,`N`],[110960,111355,`W`],[111356,126979,`N`],[126980,126980,`W`],[126981,127182,`N`],[127183,127183,`W`],[127184,127231,`N`],[127232,127242,`A`],[127243,127247,`N`],[127248,127277,`A`],[127278,127279,`N`],[127280,127337,`A`],[127338,127343,`N`],[127344,127373,`A`],[127374,127374,`W`],[127375,127376,`A`],[127377,127386,`W`],[127387,127404,`A`],[127405,127487,`N`],[127488,127490,`W`],[127491,127503,`N`],[127504,127547,`W`],[127548,127551,`N`],[127552,127560,`W`],[127561,127567,`N`],[127568,127569,`W`],[127570,127583,`N`],[127584,127589,`W`],[127590,127743,`N`],[127744,127776,`W`],[127777,127788,`N`],[127789,127797,`W`],[127798,127798,`N`],[127799,127868,`W`],[127869,127869,`N`],[127870,127891,`W`],[127892,127903,`N`],[127904,127946,`W`],[127947,127950,`N`],[127951,127955,`W`],[127956,127967,`N`],[127968,127984,`W`],[127985,127987,`N`],[127988,127988,`W`],[127989,127991,`N`],[127992,128062,`W`],[128063,128063,`N`],[128064,128064,`W`],[128065,128065,`N`],[128066,128252,`W`],[128253,128254,`N`],[128255,128317,`W`],[128318,128330,`N`],[128331,128334,`W`],[128335,128335,`N`],[128336,128359,`W`],[128360,128377,`N`],[128378,128378,`W`],[128379,128404,`N`],[128405,128406,`W`],[128407,128419,`N`],[128420,128420,`W`],[128421,128506,`N`],[128507,128591,`W`],[128592,128639,`N`],[128640,128709,`W`],[128710,128715,`N`],[128716,128716,`W`],[128717,128719,`N`],[128720,128722,`W`],[128723,128724,`N`],[128725,128727,`W`],[128728,128731,`N`],[128732,128735,`W`],[128736,128746,`N`],[128747,128748,`W`],[128749,128755,`N`],[128756,128764,`W`],[128765,128991,`N`],[128992,129003,`W`],[129004,129007,`N`],[129008,129008,`W`],[129009,129291,`N`],[129292,129338,`W`],[129339,129339,`N`],[129340,129349,`W`],[129350,129350,`N`],[129351,129535,`W`],[129536,129647,`N`],[129648,129660,`W`],[129661,129663,`N`],[129664,129672,`W`],[129673,129679,`N`],[129680,129725,`W`],[129726,129726,`N`],[129727,129733,`W`],[129734,129741,`N`],[129742,129755,`W`],[129756,129759,`N`],[129760,129768,`W`],[129769,129775,`N`],[129776,129784,`W`],[129785,131071,`N`],[131072,196605,`W`],[196606,196607,`N`],[196608,262141,`W`],[262142,917759,`N`],[917760,917999,`A`],[918e3,983039,`N`],[983040,1048573,`A`],[1048574,1048575,`N`],[1048576,1114109,`A`],[1114110,1114111,`N`]],version=`15.1.0`;function getEAWOfCodePoint(e){let t=0,n=defs.length-1;for(;t!==n;){let r=t+(n-t>>1),[i,a,o]=defs[r];if(ea)t=r+1;else return o}return defs[t][2]}function getEAW(e,t=0){let n=e.codePointAt(t);if(n!==void 0)return getEAWOfCodePoint(n)}var defaultWidths={N:1,Na:1,W:2,F:2,H:1,A:1};function computeWidth(e,t){let n=0;for(let r of e){let e=getEAW(r);n+=t&&t[e]||defaultWidths[e]}return n}var textOffsetY=5,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function isWideChar(e){switch(getEAW(e)){case`F`:case`W`:return!0;default:return!1}}function isMacOS(){return window.navigator.userAgent.indexOf(`Mac OS X`)!==-1}function computeFontSize(e){let t=document.createElement(`canvas`).getContext(`2d`);t.font=e;let n=t.measureText(`W`);return[Math.floor(n.width),Math.round(n.fontBoundingBoxAscent+textOffsetY+(n.emHeightDescent||0)),Math.round(n.fontBoundingBoxAscent+textOffsetY)]}function drawBlock({ctx:e,x:t,y:n,width:r,height:i,style:a}){e.fillStyle=a,e.fillRect(t,n,r,i)}function drawText({ctx:e,x:t,y:n,text:r,font:i,style:a,option:o}){n+=Math.round(textOffsetY),e.fillStyle=a,e.font=i,e.textBaseline=`top`;for(let i of r)isWideChar(i)?(e.fillText(i,t,n,o.fontWidth*2),t+=o.fontWidth*2):(e.fillText(i,t,n,o.fontWidth),t+=o.fontWidth)}function drawHorizontalLine({ctx:e,x:t,y:n,width:r,style:i,lineWidth:a=1}){e.strokeStyle=i,e.lineWidth=a,e.setLineDash=[],e.beginPath(),e.moveTo(t,n),e.lineTo(t+r,n),e.stroke()}var Option=class{constructor({fontName:e,fontSize:t}){this.setFont(e,t),this.foreground=`#cccccc`,this.background=`#2d2d2d`}setFont(e,t){let n=t+`px `+e,[r,i,a]=computeFontSize(n);this.fontName=e,this.fontSize=t,this.fontWidth=r,this.fontHeight=i,this.fontAscent=a,this.font=n}};function getLemEditorElement(){return document.getElementById(`lem-editor`)}function normalizeWheelDelta(e,t,n,r){switch(n){case 0:return{dx:e/r,dy:t/r};case 2:return{dx:e*20,dy:t*20};default:return{dx:e,dy:t}}}function extractWholeLines(e,t){let n=Math.trunc(e),r=Math.trunc(t);return{scrollX:n,scrollY:r,remainderX:e-n,remainderY:t-r}}function cursorPosition(e,t){let[n,r]=t.getDisplayRectangle(),i=e.clientX-n,a=e.clientY-r;return{pixelX:i,pixelY:a,x:Math.floor(i/t.option.fontWidth),y:Math.floor(a/t.option.fontHeight)}}function makeWheelHandler(e){let t={x:0,y:0},n=!1,r={pixelX:0,pixelY:0,x:0,y:0};return i=>{i.preventDefault(),r=cursorPosition(i,e);let{dx:a,dy:o}=normalizeWheelDelta(i.deltaX,i.deltaY,i.deltaMode,e.option.fontHeight);t={x:t.x+a,y:t.y+o},n||(n=!0,requestAnimationFrame(()=>{n=!1;let{scrollX:i,scrollY:a,remainderX:o,remainderY:s}=extractWholeLines(t.x,t.y);t={x:o,y:s},(i!==0||a!==0)&&e.jsonrpc.notify(`input`,{kind:`wheel`,value:{...r,wheelX:-i,wheelY:-a}})}))}}function addMouseEventListeners({dom:e,editor:t,isDraggable:n,draggableStyle:r}){e.addEventListener(`contextmenu`,e=>{e.preventDefault()});let i=(e,n)=>{e.preventDefault();let[r,i]=t.getDisplayRectangle(),a=e.clientX-r,o=e.clientY-i,s=Math.floor(a/t.option.fontWidth),c=Math.floor(o/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:n,value:{x:s,y:c,pixelX:a,pixelY:o,button:e.button,clicks:e.detail}})};e.addEventListener(`mousedown`,e=>{n&&(document.body.style.cursor=r),t.focusHiddenInput(),i(e,`mousedown`)}),e.addEventListener(`mouseup`,e=>{n&&(document.body.style.cursor=`default`),i(e,`mouseup`)});let a=0;e.addEventListener(`mousemove`,e=>{e.preventDefault();let n=Date.now();if(n-a>50){a=n;let[r,i]=t.getDisplayRectangle(),o=e.clientX-r,s=e.clientY-i,c=Math.floor(o/t.option.fontWidth),l=Math.floor(s/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:`mousemove`,value:{x:c,y:l,pixelX:o,pixelY:s,button:e.buttons===0?null:e.buttons-1}})}}),n&&(e.addEventListener(`mouseover`,()=>{document.body.style.cursor=r}),e.addEventListener(`mouseout`,e=>{e.buttons!==1&&(document.body.style.cursor=`default`)})),e.addEventListener(`wheel`,makeWheelHandler(t))}var zIndexTable={"floating-window":200,modeline:100,"vertical-border":100,"horizontal-border":101};function zindex(e){return zIndexTable[e]||0}var borderOffsetX=5,borderOffsetY=10,BaseSurface=class{constructor({editor:e}){this.editor=e,this.mainDOM=null,this.wrapper=null}delete(){this.wrapper?getLemEditorElement().removeChild(this.wrapper):getLemEditorElement().removeChild(this.mainDOM)}setupDOM({dom:e,isFloating:t,border:n,cssClassName:r}){this.mainDOM=e,t&&n?(this.wrapper=document.createElement(`div`),r&&(this.wrapper.className=r),this.wrapper.style.position=`absolute`,this.wrapper.style.backgroundColor=this.editor.option.background,this.wrapper.style.zIndex=zindex(`floating-window`),this.wrapper.appendChild(e),getLemEditorElement().appendChild(this.wrapper)):(r&&(e.className=r),getLemEditorElement().appendChild(e))}move(e,t){let[n,r]=this.editor.getDisplayRectangle(),i=Math.floor(n+e),a=Math.floor(r+t);this.wrapper?(this.wrapper.style.left=i-borderOffsetX+`px`,this.wrapper.style.top=a-borderOffsetY+`px`,this.mainDOM.style.left=borderOffsetX+`px`,this.mainDOM.style.top=borderOffsetY+`px`):(this.mainDOM.style.left=i+`px`,this.mainDOM.style.top=a+`px`)}_resize(e,t){let n=window.devicePixelRatio||1;this.mainDOM.width=e*n,this.mainDOM.height=t*n,this.mainDOM.style.width=e+`px`,this.mainDOM.style.height=t+`px`,this.wrapper&&(this.wrapper.style.width=e+borderOffsetX*2+`px`,this.wrapper.style.height=t+borderOffsetY*2+`px`)}drawBlock(e,t,n,r,i){}drawText(e,t,n,r,i,a){}drawImage(e,t,n,r,i,a,o){}clearImages(e,t){}clearAllImages(){}touch(){}evalIn(code){return eval(code)}},CanvasSurface=class extends BaseSurface{constructor({editor:e,view:t,pixelX:n,pixelY:r,pixelWidth:i,pixelHeight:a,styles:o,isFloating:s,border:c,cssClassName:l}){super({editor:e});let u=this.setupCanvas(o);this.setupDOM({dom:u,isFloating:s,border:c,cssClassName:l}),this.move(n,r),this.resize(i,a),this.drawingQueue=[],addMouseEventListeners({dom:u,editor:e})}setupCanvas(e){let t=document.createElement(`canvas`);if(t.style.position=`absolute`,e)for(let n in e)t.style[n]=e[n];return t}resize(e,t){this._resize(e,t);let n=window.devicePixelRatio||1;this.mainDOM.getContext(`2d`).scale(n,n)}move(e,t){if(super.move(e,t),this.imageEls)for(let[,e]of this.imageEls)this.positionImage(e)}delete(){this.clearAllImages(),super.delete()}drawBlock(e,t,n,r,i){this.drawingQueue.push(function(a){drawBlock({ctx:a,x:e,y:t,width:n,height:r,style:i})})}drawText(e,t,n,r,i,a){let o=this.editor.option,s=o.fontHeight;this.drawingQueue.push(function(c){if(a=a?`${o.fontSize}px ${a}`:o.font,!i)drawBlock({ctx:c,x:e,y:t,width:r,height:s,style:o.background}),drawText({ctx:c,x:e,y:t,text:n,style:o.foreground,font:a,option:o});else{let{foreground:l,background:u,bold:d,reverse:f,underline:p,cursor:m}=i;if(l||=o.foreground,u||=o.background,f){let e=u;u=l,l=e}m&&(u=o.background),drawBlock({ctx:c,x:e,y:t,width:r,height:s,style:u}),drawText({ctx:c,x:e,y:t,text:n,style:l,font:d?`bold `+a:a,option:o}),p&&drawHorizontalLine({ctx:c,x:e,y:t+o.fontHeight-2,width:r,style:typeof p==`string`?p:l,lineWidth:2})}})}imageBaseLeft(){return parseFloat(this.mainDOM.style.left)||0}imageBaseTop(){return parseFloat(this.mainDOM.style.top)||0}drawImage(e,t,n,r,i,a,o){this.imageEls||=new Map;let s=e+`,`+t,c=this.imageEls.get(s);if(c&&c.url!==o&&(c.el.remove(),this.imageEls.delete(s),c=null),!c){let e=document.createElement(`img`);e.style.position=`absolute`,e.style.pointerEvents=`none`,e.style.zIndex=`1`,e.src=o,this.mainDOM.parentNode.appendChild(e),c={el:e,url:o},this.imageEls.set(s,c)}c.x=e,c.y=t,c.width=n,c.height=r,c.clipWidth=i,c.clipHeight=a,this.positionImage(c)}positionImage(e){e.el.style.left=this.imageBaseLeft()+e.x+`px`,e.el.style.top=this.imageBaseTop()+e.y+`px`,e.el.style.width=e.width+`px`,e.el.style.height=e.height+`px`;let t=e.clipWidth==null?0:Math.max(0,e.width-e.clipWidth),n=e.clipHeight==null?0:Math.max(0,e.height-e.clipHeight);e.el.style.clipPath=t>0||n>0?`inset(0px ${t}px ${n}px 0px)`:``}clearImages(e,t){if(this.imageEls)for(let[n,r]of this.imageEls){let i=r.y+(r.height||0);r.ye&&(r.el.remove(),this.imageEls.delete(n))}}clearAllImages(){if(this.imageEls){for(let[,e]of this.imageEls)e.el.remove();this.imageEls.clear()}}touch(){let e=this.mainDOM.getContext(`2d`);for(let t of this.drawingQueue)t(e);this.drawingQueue=[]}activate(){this.mainDOM.dataset.store=`active`}deactivate(){this.mainDOM.dataset.store=`inactive`}},HTMLSurface=class extends BaseSurface{constructor({editor:e,pixelX:t,pixelY:n,pixelWidth:r,pixelHeight:i,styles:a,option:o,isFloating:s,border:c,html:l}){super({editor:e});let u=document.createElement(`iframe`);this.setupDOM({dom:u,isFloating:s,border:c}),u.style.position=`absolute`,u.style.backgroundColor=o.background,u.setAttribute(`sandbox`,`allow-scripts allow-same-origin`),u.srcdoc=l,u.addEventListener(`load`,()=>{let e=u.contentWindow;e.invokeLem=(e,t)=>parent.postMessage({type:`invoke-lem`,method:e,args:t})}),this.iframe=u,this.move(t,n),this.resize(r,i)}resize(e,t){this._resize(e,t)}update(e){let t=this.iframe.contentWindow.scrollY;this.iframe.srcdoc=e,this.iframe.onload=()=>{this.iframe.onload=null,this.iframe.contentWindow.scrollTo(0,t)}}evalIn(e){return this.iframe.contentWindow.eval(e)}},VerticalBorder=class{constructor({x:e,y:t,height:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__vertical-border`,this.line.style.height=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`vertical-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`col-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=Math.floor(n+e-this.option.fontWidth/2)+`px`,this.line.style.top=r+t+`px`}resize(e){this.line.style.height=e+`px`}},HorizontalBorder=class{constructor({x:e,y:t,width:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__horizontal-border`,this.line.style.width=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`horizontal-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`row-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=n+e+`px`,this.line.style.top=Math.floor(r+t-4)+`px`}resize(e){this.line.style.width=e+`px`}},viewStyles={header:()=>{},tile:()=>{},floating:e=>({boxSizing:`border-box`,borderColor:e.foreground,backgroundColor:e.background})};function getViewStyle(e,t){return viewStyles[e](t)||{}}var View=class{constructor({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,option:h,editor:g}){switch(this.option=h,this.id=e,this.x=t,this.y=n,this.width=r,this.height=i,this.pixelX=a,this.pixelY=o,this.pixelWidth=s,this.pixelHeight=c,this.useModeline=l,this.kind=u,this.type=d,this.border=p,this.borderShape=m,this.editor=g,this.bottomBar=null,this.leftsideBar=null,u){case`tile`:this.mainSurface=this.makeSurface(d,f),this.leftSideBar=new VerticalBorder({x:a,y:o,height:c+(l?h.fontHeight:0),option:h,editor:g}),l||(this.bottomBar=new HorizontalBorder({x:a,y:o+c-h.fontHeight,width:s,option:h,editor:g}));break;case`header`:this.mainSurface=this.makeSurface(d,f);break;case`floating`:this.mainSurface=this.makeSurface(d,f),m===`left-border`&&(this.leftSideBar=new VerticalBorder({x:a,y:o,height:c,option:h,editor:g}));break}this.modelineSurface=l?this.makeModelineSurface():null}delete(){this.mainSurface.delete(),this.modelineSurface&&this.modelineSurface.delete(),this.leftSideBar&&this.leftSideBar.delete(),this.bottomBar&&this.bottomBar.delete()}move(e,t,n,r){this.x=e,this.y=t,this.pixelX=n,this.pixelY=r,this.mainSurface.move(n,r),this.modelineSurface&&this.modelineSurface.move(n,r+this.pixelHeight),this.leftSideBar&&this.leftSideBar.move(n,r),this.bottomBar&&this.bottomBar.move(n,r+this.pixelHeight)}resize(e,t,n,r){this.width=e,this.height=t,this.pixelWidth=n,this.pixelHeight=r,this.mainSurface.resize(n,r),this.modelineSurface&&(this.modelineSurface.move(this.pixelX,this.pixelY+r),this.modelineSurface.resize(n,this.option.fontHeight)),this.leftSideBar&&this.leftSideBar.resize(r+(this.modelineSurface?this.option.fontHeight:0)),this.bottomBar&&this.bottomBar.resize(n)}clear(){this.mainSurface.drawBlock(0,0,this.pixelWidth,this.pixelHeight,this.option.background),this.mainSurface.clearImages(0,this.pixelHeight)}clearEol(e,t,n){n??=this.option.fontHeight,this.mainSurface.drawBlock(e,t,this.pixelWidth-e,n,this.option.background),this.mainSurface.clearImages(t,t+n)}clearEob(e,t){this.mainSurface.drawBlock(e,t,this.pixelWidth,this.pixelHeight-t,this.option.background),this.mainSurface.clearImages(t,this.pixelHeight)}print(e,t,n,r,i,a){this.mainSurface.drawText(e,t,n,r,i,a)}drawBlock(e,t,n,r,i){this.mainSurface.drawBlock(e,t,n,r,i||this.option.background)}drawBlockOnModeline(e,t,n,r,i){this.modelineSurface&&this.modelineSurface.drawBlock(e,t,n,r,i||this.option.background)}printImage(e,t,n,r,i,a,o){this.mainSurface.drawImage(e,t,n,r,i,a,o)}printToModeline(e,t,n,r,i){this.modelineSurface&&this.modelineSurface.drawText(e,t,n,r,i,null)}touch(e){this.mainSurface.touch(),this.modelineSurface&&(this.modelineSurface.touch(),e?this.modelineSurface.activate():this.modelineSurface.deactivate())}makeSurface(e,t){switch(e){case`html`:return this.makeHTMLSurface(t);case`editor`:return this.makeEditorSurface();default:console.error(`unknown type: ${e}`)}}makeHTMLSurface(e){return new HTMLSurface({editor:this.editor,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),option:this.option,isFloating:this.kind===`floating`,border:this.border,html:e})}makeEditorSurface(){let e=this.borderShape===`left-border`?0:this.border,t=this.kind===`floating`;return new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),editor:this.editor,border:e,isFloating:t,view:this,cssClassName:t&&e?`lem-editor__floating-window--bordered`:null})}makeModelineSurface(){let e=new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY+this.pixelHeight,pixelWidth:this.pixelWidth,pixelHeight:this.option.fontHeight,editor:this.editor,view:this,styles:{zIndex:zindex(`modeline`)},cssClassName:`lem-editor__mode-line`});return addMouseEventListeners({dom:e.mainDOM,editor:this.editor,isDraggable:!0,draggableStyle:`row-resize`}),e}changeToHTMLContent(e){this.mainSurface.constructor.name===`HTMLSurface`?this.mainSurface.update(e):(this.mainSurface.delete(),this.mainSurface=this.makeHTMLSurface(e))}changeToEditorContent(){this.mainSurface.delete(),this.mainSurface=this.makeEditorSurface()}evalIn(e){return this.mainSurface.evalIn(e)}};function isPasteKeyEvent(e){return isMacOS()?e.metaKey&&e.key===`v`:e.ctrlKey&&e.shiftKey&&e.key===`V`}var Input=class{constructor(e){let t=e.option;this.editor=e,this.composition=!1,this.ignoreKeydownAfterCompositionend=!1,this.span=document.createElement(`span`),this.span.style.color=t.foreground,this.span.style.backgroundColor=t.background,this.span.style.position=`absolute`,this.span.style.zIndex=1e6,this.span.style.top=`0`,this.span.style.left=`0`,this.span.style.font=t.font,this.input=document.createElement(`input`),this.input.style.backgroundColor=`transparent`,this.input.style.color=`transparent`,this.input.style.width=`0`,this.input.style.padding=`0`,this.input.style.margin=`0`,this.input.style.border=`none`,this.input.style.position=`absolute`,this.input.style.zIndex=`-10`,this.input.style.top=`0`,this.input.style.left=`0`,this.input.style.font=t.font,this.input.addEventListener(`blur`,e=>{this.input.focus()}),this.input.addEventListener(`input`,e=>{this.composition===!1&&(this.input.value=``,this.span.innerHTML=``,this.input.style.width=`0`,isMacOS()||this.editor.emitInputString(e.data))}),this.input.addEventListener(`paste`,async e=>{e.preventDefault();let t=e.clipboardData||window.Clipboard.data,n=t?.getData(`text`)??t?.getData(`text/plain`);if(n&&n.length>0){this.editor.emitInputString(n);return}try{if(navigator.clipboard?.readText){let e=await navigator.clipboard.readText();if(e&&e.length>0){this.editor.emitInputString(e);return}}}catch(e){console.warn(`clipboard.readText() failed:`,e)}alert(`Paste failed (permission/environment restriction`)}),this.input.addEventListener(`keydown`,e=>{if(!isPasteKeyEvent(e)&&!(e.isComposing||this.composition)&&e.key!==`Process`){if(this.ignoreKeydownAfterCompositionend&&(isSafari||isMacOS())){e.preventDefault(),this.ignoreKeydownAfterCompositionend=!1;return}if(!(!isMacOS()&&!e.ctrlKey&&!e.altKey&&e.key.length===1)&&(e.preventDefault(),e.isComposing!==!0&&e.code!==``))return setTimeout(()=>{this.composition||(this.editor.emitInput(e),this.input.value=``)},0),!1}}),this.input.addEventListener(`compositionstart`,e=>{this.composition=!0,this.span.innerHTML=this.input.value,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionupdate`,e=>{this.span.innerHTML=e.data,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionend`,e=>{this.composition=!1,this.editor.emitInputString(this.input.value),this.input.value=``,this.span.innerHTML=this.input.value,this.input.style.width=`0`,this.ignoreKeydownAfterCompositionend=!0}),document.body.appendChild(this.input),document.body.appendChild(this.span),this.input.focus()}finalize(){document.body.removeChild(this.input),document.body.removeChild(this.span)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.span.style.top=r+t+`px`,this.span.style.left=n+e+`px`,this.input.style.top=this.span.offsetTop+`px`,this.input.style.left=this.span.offsetLeft+`px`}updateForeground(e){this.span.style.color=e}updateBackground(e){this.span.style.backgroundColor=e}},MessageTable=class{constructor(){this.map=new Map}register(e,t){for(let n in t){let r=t[n];this.map.set(n,r),e.on(n,r)}}get(e){return this.map.get(e)}};function getDisplayRectangleDefault(){return[0,0,window.innerWidth,window.innerHeight]}var Editor=class{constructor({getDisplayRectangle:e=getDisplayRectangleDefault,fontName:t,fontSize:n,url:r,onExit:i,onClosed:a}){this.getDisplayRectangle=e,this.option=new Option({fontName:t,fontSize:n}),this.onExit=i,this.input=new Input(this),this.cursors=new Map,this.cursorOverlay=document.createElement(`div`),this.cursorOverlay.className=`lem-cursor`,this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.cursorOverlay.style.backgroundColor=`#ffffff`,this.cursorType=`box`,this.viewMap=new Map,this.jsonrpc=new JSONRPC(r,{onClosed:()=>{a()}}),this.messageTable=new MessageTable,this.messageTable.register(this.jsonrpc,{"update-foreground":this.updateForeground.bind(this),"update-background":this.updateBackground.bind(this),"make-view":this.makeView.bind(this),"delete-view":this.deleteView.bind(this),"resize-view":this.resize.bind(this),"move-view":this.move.bind(this),"redraw-view-after":this.redrawViewAfter.bind(this),clear:this.clear.bind(this),"clear-eol":this.clearEol.bind(this),"clear-eob":this.clearEob.bind(this),put:this.put.bind(this),"put-image":this.putImage.bind(this),"modeline-put":this.modelinePut.bind(this),"draw-block":this.drawBlock.bind(this),"modeline-draw-block":this.modelineDrawBlock.bind(this),"update-display":this.updateDisplay.bind(this),"move-cursor":this.moveCursor.bind(this),"change-view":this.changeView.bind(this),"resize-display":this.resizeDisplay.bind(this),bulk:this.bulk.bind(this),exit:this.exitEditor.bind(this),"get-clipboard-text":this.getClipboardText.bind(this),"set-clipboard-text":this.setClipboardText.bind(this),"js-eval":this.jsEval.bind(this),"set-font":this.setFont.bind(this),"get-font":this.getFont.bind(this),"get-display-size":this.getDisplaySize.bind(this),"load-css":this.loadCSS.bind(this),"update-cursor-shape":this.updateCursorShape.bind(this)}),this.login(),this.boundedHandleResize=this.handleResize.bind(this),this.focusHiddenInput=this.focusHiddenInput.bind(this)}init(){window.addEventListener(`resize`,this.boundedHandleResize),document.getElementsByTagName(`html`)[0].style[`background-color`]=`#333`,getLemEditorElement().appendChild(this.cursorOverlay)}finalize(){window.removeEventListener(`resize`,this.boundedHandleResize),this.input.finalize(),this.cursorOverlay.parentNode&&this.cursorOverlay.parentNode.removeChild(this.cursorOverlay)}closeConnection(){this.jsonrpc.close()}emitInput(e){let t=convertKeyEvent(e);if(t){if(t.key===`]`&&t.ctrl&&!t.meta&&!t.super&&!t.shift){this.jsonrpc.notify(`input`,{kind:`abort`});return}t.key!==`Unidentified`&&this.jsonrpc.notify(`input`,{kind:`key`,value:t})}}emitInputString(e){e?this.jsonrpc.notify(`input`,{kind:`input-string`,value:e}):console.error(`unexpected argument`,e)}redrawParams(){return{size:this.getDisplaySize(),fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent}}handleResize(e){this.jsonrpc.notify(`redraw`,this.redrawParams())}focusHiddenInput(){let e=this.input?.input;if(e){try{window.focus()}catch{}requestAnimationFrame(()=>{setTimeout(()=>{e.focus({preventScroll:!0})},0)})}}sendNotification(e,t){this.jsonrpc.notify(e,t)}request(e,t,n){this.jsonrpc.request(e,t,n)}getDisplaySize(){let[e,t,n,r]=this.getDisplayRectangle();return{width:Math.floor(n/this.option.fontWidth),height:Math.floor(r/this.option.fontHeight)}}callMessage(e,t){this.messageTable.get(e)(t)}findViewById(e){return this.viewMap.get(e)}login(){this.jsonrpc.request(`login`,{size:this.getDisplaySize(),foreground:this.option.foreground,background:this.option.background,fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent},e=>{if(this.updateForeground(e.foreground),this.updateBackground(e.background),e.views)for(let t of e.views)this.makeView(t);this.jsonrpc.notify(`redraw`,this.redrawParams())})}updateForeground(e){e!=null&&(this.option.foreground=e,this.input.updateForeground(e))}updateBackground(e){if(e==null)return;this.option.background=e,this.input.updateBackground(e);let t=getLemEditorElement();t.style.backgroundColor=e}makeView({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,use_modeline:l,kind:u,type:d,content:f,border:p,border_shape:m}){let h=new View({option:this.option,id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,editor:this});this.viewMap.set(e,h)}deleteView({viewInfo:{id:e}}){this.findViewById(e).delete(),this.viewMap.delete(e)}resize({viewInfo:{id:e},width:t,height:n,pixelWidth:r,pixelHeight:i}){let a=this.findViewById(e);a?a.resize(t,n,r,i):console.warn(`resize: view not found for id ${e}`)}move({viewInfo:{id:e},x:t,y:n,pixelX:r,pixelY:i}){let a=this.findViewById(e);a?a.move(t,n,r,i):console.warn(`move: view not found for id ${e}`)}redrawViewAfter({viewInfo:{id:e},isActive:t}){this.findViewById(e).touch(t)}clear({viewInfo:{id:e}}){this.findViewById(e).clear()}clearEol({viewInfo:{id:e},x:t,y:n,height:r}){this.findViewById(e).clearEol(t,n,r)}clearEob({viewInfo:{id:e},x:t,y:n}){this.findViewById(e).clearEob(t,n)}put({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,font:o}){this.findViewById(e).print(t,n,r,i,a,o)}drawBlock({viewInfo:{id:e},x:t,y:n,width:r,height:i,color:a}){this.findViewById(e).drawBlock(t,n,r,i,a)}modelineDrawBlock({viewInfo:{id:e},x:t,y:n,width:r,height:i,color:a}){this.findViewById(e).drawBlockOnModeline(t,n,r,i,a)}putImage({viewInfo:{id:e},x:t,y:n,pixelWidth:r,pixelHeight:i,clipWidth:a,clipHeight:o,url:s}){this.findViewById(e).printImage(t,n,r,i,a,o,s)}modelinePut({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a}){this.findViewById(e).printToModeline(t,n,r,i,a)}updateDisplay(){}moveCursor({viewInfo:{id:e},x:t,y:n,color:r,cursorText:i,cursorForeground:a}){let o=this.findViewById(e),[s,c]=this.getDisplayRectangle(),l=o.pixelX+t,u=o.pixelY+n;this.input.move(l,u);let d=r||this.option.foreground,f=a||this.option.background,p=this.cursorOverlay;switch(this.cursorType){case`bar`:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=`2px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;case`underline`:p.style.left=s+l+`px`,p.style.top=c+u+this.option.fontHeight-2+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=`2px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;default:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.style.font=this.option.font,p.style.paddingTop=textOffsetY+`px`,p.textContent=i||``,p.style.color=f;break}p.style.animation=`none`,p.offsetHeight,p.style.animation=``}updateCursorShape({cursorType:e}){this.cursorType=e||`box`}changeView({viewInfo:{id:e},type:t,content:n}){let r=this.findViewById(e);switch(t){case`html`:r.changeToHTMLContent(n);break;case`editor`:r.changeToEditorContent();break}}resizeDisplay({width:e,height:t}){let n=getLemEditorElement();n.style.width=Math.floor(e*this.option.fontWidth)+`px`,n.style.height=Math.floor(t*this.option.fontHeight)+`px`}bulk(e){for(let{method:t,argument:n}of e)this.callMessage(t,n)}exitEditor(){this.onExit&&this.onExit()}getClipboardText(){navigator.clipboard?.readText().then(e=>{this.jsonrpc.notify(`got-clipboard-text`,{text:e})})}setClipboardText({text:e}){navigator.clipboard&&navigator.clipboard.writeText(e)}jsEval({viewInfo:{id:e},code:t}){let n=this.findViewById(e).evalIn(t);return n&&n.toString()}setFont({fontName:e,fontSize:t}){this.option.setFont(e||this.option.fontName,t||this.option.fontSize),this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.jsonrpc.notify(`redraw`,this.redrawParams())}getFont(){return{name:this.option.fontName,size:this.option.fontSize}}loadCSS({content:e}){let t=document.createElement(`style`);t.textContent=e,document.head.appendChild(t)}notifyToServer(e,t){this.jsonrpc.notify(`invoke`,{method:e,args:t})}},canvas=document.querySelector(`#editor`);async function main(){await Promise.all([document.fonts.load(`19px file-icons`),document.fonts.load(`19px AllTheIcons`),document.fonts.load(`19px fontawesome`),document.fonts.load(`19px material-design-icons`),document.fonts.load(`19px octicons`)]),await document.fonts.ready;let e=new Editor({canvas,fontName:`Monospace`,fontSize:18,url:`${window.location.protocol===`https:`?`wss`:`ws`}://${window.location.hostname}:${window.location.port}`,onExit:null,onClosed:null});window.addEventListener(`message`,t=>{t.data.type===`invoke-lem`&&e.notifyToServer(t.data.method,t.data.args)}),e.init()}main(); \ No newline at end of file diff --git a/frontends/server/frontend/editor.js b/frontends/server/frontend/editor.js index 3ad4569fe..99f213b91 100644 --- a/frontends/server/frontend/editor.js +++ b/frontends/server/frontend/editor.js @@ -345,7 +345,7 @@ class BaseSurface { // drawing coordinates are relative to the surface's own top-left corner. drawBlock(x, y, width, height, color) { } - drawText(x, y, text, textWidth, attribute, font, height) { } + drawText(x, y, text, textWidth, attribute, font) { } drawImage(x, y, width, height, clipWidth, clipHeight, url) { } clearImages(yStart, yEnd) { } @@ -411,12 +411,11 @@ class CanvasSurface extends BaseSurface { }); } - // the background is filled first, textWidth by blockHeight, then the text drawn over it, so a - // fill with no text is an empty string with a width. only those fills pass a height, to cover a - // row an image made taller than one line of text. text keeps its own cell height. - drawText(x, y, text, textWidth, attribute, font, height) { + // the background is filled first, textWidth by one line of text, then the text drawn over it. a + // rectangle taller than that is a `drawBlock', not a text-less draw through here. + drawText(x, y, text, textWidth, attribute, font) { const option = this.editor.option; - const blockHeight = height || option.fontHeight; + const blockHeight = option.fontHeight; this.drawingQueue.push(function(ctx) { font = font ? `${option.fontSize}px ${font}` : option.font; if (!attribute) { @@ -868,7 +867,7 @@ class View { this.mainSurface.clearImages(y, this.pixelHeight); } - print(x, y, text, textWidth, attribute, font, height) { + print(x, y, text, textWidth, attribute, font) { this.mainSurface.drawText( x, y, @@ -876,15 +875,26 @@ class View { textWidth, attribute, font, - height, ); } + // a fill of its own, for a rectangle that is not one line of text tall. a missing color is the + // editor's default background, as an attribute with no background of its own would be. + drawBlock(x, y, width, height, color) { + this.mainSurface.drawBlock(x, y, width, height, color || this.option.background); + } + + drawBlockOnModeline(x, y, width, height, color) { + if (this.modelineSurface) { + this.modelineSurface.drawBlock(x, y, width, height, color || this.option.background); + } + } + printImage(x, y, pixelWidth, pixelHeight, clipWidth, clipHeight, url) { this.mainSurface.drawImage(x, y, pixelWidth, pixelHeight, clipWidth, clipHeight, url); } - printToModeline(x, y, text, textWidth, attribute, height) { + printToModeline(x, y, text, textWidth, attribute) { if (this.modelineSurface) { this.modelineSurface.drawText( x, @@ -893,7 +903,6 @@ class View { textWidth, attribute, null, - height, ); } } @@ -1245,6 +1254,8 @@ export class Editor { 'put': this.put.bind(this), 'put-image': this.putImage.bind(this), 'modeline-put': this.modelinePut.bind(this), + 'draw-block': this.drawBlock.bind(this), + 'modeline-draw-block': this.modelineDrawBlock.bind(this), 'update-display': this.updateDisplay.bind(this), 'move-cursor': this.moveCursor.bind(this), 'change-view': this.changeView.bind(this), @@ -1461,9 +1472,19 @@ export class Editor { view.clearEob(x, y); } - put({ viewInfo: { id }, x, y, text, textWidth, attribute, font, height }) { + put({ viewInfo: { id }, x, y, text, textWidth, attribute, font }) { + const view = this.findViewById(id); + view.print(x, y, text, textWidth, attribute, font); + } + + drawBlock({ viewInfo: { id }, x, y, width, height, color }) { + const view = this.findViewById(id); + view.drawBlock(x, y, width, height, color); + } + + modelineDrawBlock({ viewInfo: { id }, x, y, width, height, color }) { const view = this.findViewById(id); - view.print(x, y, text, textWidth, attribute, font, height); + view.drawBlockOnModeline(x, y, width, height, color); } putImage({ viewInfo: { id }, x, y, pixelWidth, pixelHeight, clipWidth, clipHeight, url }) { @@ -1471,9 +1492,9 @@ export class Editor { view.printImage(x, y, pixelWidth, pixelHeight, clipWidth, clipHeight, url); } - modelinePut({ viewInfo: { id }, x, y, text, textWidth, attribute, height }) { + modelinePut({ viewInfo: { id }, x, y, text, textWidth, attribute }) { const view = this.findViewById(id); - view.printToModeline(x, y, text, textWidth, attribute, height); + view.printToModeline(x, y, text, textWidth, attribute); } updateDisplay() { diff --git a/frontends/server/main.lisp b/frontends/server/main.lisp index 17b39a2e1..2c157f6cb 100644 --- a/frontends/server/main.lisp +++ b/frontends/server/main.lisp @@ -659,9 +659,8 @@ same hash." (setf attribute (lem:make-attribute :background lem-if:*background-color-of-drawing-window*))) (attribute-to-hash attribute))) -(defun put (jsonrpc view x y string attribute &key font text-width height) - "draw STRING at pixel position X, Y in VIEW, over a TEXT-WIDTH by HEIGHT pixel background. -HEIGHT defaults to one line of text." +(defun put (jsonrpc view x y string attribute &key font text-width) + "draw STRING at pixel position X, Y in VIEW, over a TEXT-WIDTH background one line of text tall." (with-error-handler () (notify* jsonrpc (ecase *put-target* @@ -672,10 +671,25 @@ HEIGHT defaults to one line of text." "y" y "text" string "textWidth" (or text-width (* (lem:string-width string) (jsonrpc-cell-width jsonrpc))) - "height" height "attribute" (ensure-attribute attribute) "font" font)))) +(defun draw-block (jsonrpc view x y width height color) + "fill the WIDTH by HEIGHT rectangle at pixel position X, Y in VIEW with COLOR. +unlike `put', which is one line of text tall, this covers a row an image made taller. a NIL COLOR +leaves the client to use its default background." + (with-error-handler () + (notify* jsonrpc + (ecase *put-target* + (:edit-area "draw-block") + (:modeline "modeline-draw-block")) + (hash "viewInfo" (view-id-hash view) + "x" x + "y" y + "width" width + "height" height + "color" (and color (lem:color-to-hex-string color)))))) + (defmethod draw-object (jsonrpc (object display:text-object) x y view) (let* ((string (display:text-object-string object)) (attribute (display:text-object-attribute object)) @@ -770,22 +784,18 @@ a string already carrying a data:/https: URL is passed through unchanged." (defun draw-row (jsonrpc view row) "draw ROW's background fill, then everything placed on it. -the client paints a put's background before its text, so the fill goes as an empty string sized -TEXT-WIDTH by HEIGHT, the row's full height, which may exceed a single text line's height when a -tall object (e.g. an image) sits on the row." +the fill covers the row's full height, which a tall object (e.g. an image) can push past a single +text line's, so it goes as a `draw-block' rather than a put's background." (let ((width (view-px-width view))) (when (and (display:row-fill-color row) (< (display:row-fill-x row) width)) - (put jsonrpc - view - (display:row-fill-x row) - (display:row-top row) - "" - (lem:make-attribute - :background - (lem:color-to-hex-string (display:row-fill-color row))) - :text-width (- width (display:row-fill-x row)) - :height (display:row-height row)))) + (draw-block jsonrpc + view + (display:row-fill-x row) + (display:row-top row) + (- width (display:row-fill-x row)) + (display:row-height row) + (display:row-fill-color row)))) (loop :for placement :in (display:row-placements row) :do (draw-object jsonrpc (display:placement-object placement) @@ -806,18 +816,15 @@ tall object (e.g. an image) sits on the row." (defmethod lem-if:render-modeline-row ((jsonrpc jsonrpc) view row default-attribute) ;; the modeline has a surface of its own here, so the row is drawn where it was laid out. (let ((*put-target* :modeline)) - (with-error-handler () - (notify* jsonrpc - "modeline-put" - (hash "viewInfo" (view-id-hash view) - "x" 0 - "y" (display:row-top row) - ;; the modeline's own background: no text, just fill - "text" "" - "textWidth" (view-px-width view) - "height" (display:row-height row) - "attribute" (attribute-to-hash default-attribute))) - (draw-row jsonrpc view row)))) + ;; the modeline's own background, under everything the row places on it + (draw-block jsonrpc + view + 0 + (display:row-top row) + (view-px-width view) + (display:row-height row) + (lem:attribute-background-with-reverse default-attribute)) + (draw-row jsonrpc view row))) (defmethod lem-if:clear-to-end-of-window ((jsonrpc jsonrpc) view y) (notify* jsonrpc From c0710175d11496ce145e1db97f1b823b7cbc7ec9 Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Mon, 3 Aug 2026 15:19:53 +0300 Subject: [PATCH 12/18] give object-width's cache a slot of its own drawing-object's width and image-object's were one slot, not two. --- src/display/physical-line.lisp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/display/physical-line.lisp b/src/display/physical-line.lisp index bc02215e2..43beef662 100644 --- a/src/display/physical-line.lisp +++ b/src/display/physical-line.lisp @@ -15,7 +15,8 @@ (setf (window-parameter window 'redrawing-cache) value)) (defclass drawing-object () - ((width :initform nil :accessor drawing-object-width))) + ;; where `object-width' caches its result. `width' is left free for subclasses like `image-object'. + ((occupied-width :initform nil :accessor drawing-object-width))) (defclass void-object (drawing-object) ()) From 6d6a09762fae3fc849eb93638614f12f36a795b4 Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Mon, 3 Aug 2026 15:19:56 +0300 Subject: [PATCH 13/18] turn a click into a column by walking the objects drawn --- src/display/physical-line.lisp | 105 +++++++++++++++++++++++++-------- src/mouse.lisp | 35 +++++++---- 2 files changed, 104 insertions(+), 36 deletions(-) diff --git a/src/display/physical-line.lisp b/src/display/physical-line.lisp index 43beef662..72483667c 100644 --- a/src/display/physical-line.lisp +++ b/src/display/physical-line.lisp @@ -63,9 +63,14 @@ (defclass image-object (drawing-object) ((image :initarg :image :reader image-object-image) + ;; the size the image is drawn at, in pixels, or NIL for its natural one. (width :initarg :width :reader image-object-width) (height :initarg :height :reader image-object-height) (attribute :initarg :attribute :reader image-object-attribute) + ;; columns of the line the image accounts for, so a click can be turned back into a position. + (columns :initarg :columns + :initform 1 + :reader image-object-columns) ;; how much of the width may be shown, or NIL for all of it. see `crop-image-object'. (visible-width :initarg :visible-width :initform nil @@ -142,6 +147,7 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." :width (image-object-width object) :height (image-object-height object) :attribute (image-object-attribute object) + :columns (image-object-columns object) :visible-width (alexandria:if-let ((visible (image-object-visible-width object))) (min width visible) width))) @@ -190,6 +196,9 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." (and (eq (image-object-image drawing-object-1) (image-object-image drawing-object-2)) (equal (image-object-width drawing-object-1) (image-object-width drawing-object-2)) (equal (image-object-height drawing-object-1) (image-object-height drawing-object-2)) + ;; the cursor landing on the image changes its attribute and nothing else + (attribute-equal (image-object-attribute drawing-object-1) + (image-object-attribute drawing-object-2)) ;; a differently cropped image draws differently, so the cached row must not be reused (equal (image-object-visible-width drawing-object-1) (image-object-visible-width drawing-object-2)))) @@ -274,6 +283,18 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." (defun object-ascent (drawing-object) (lem-if:object-ascent (implementation) drawing-object)) +(defgeneric object-columns (drawing-object) + (:documentation "How many columns of the line DRAWING-OBJECT accounts for. +Not its width in pixels (`object-width'): an image can account for one column and be hundreds of +pixels wide.") + (:method (drawing-object) 0) + (:method ((drawing-object text-object)) + (string-width (text-object-string drawing-object))) + ;; drawn past the end of the line, so it accounts for nothing on it. + (:method ((drawing-object line-end-object)) 0) + (:method ((drawing-object image-object)) + (image-object-columns drawing-object))) + (defun split-string-by-character-type (string) (loop :with pos := 0 :and items := '() :while (< pos (length string)) @@ -365,7 +386,8 @@ frontend can report one (`lem-if:image-natural-size'), otherwise one cell wide." :image (attribute-image attribute) :width (attribute-width attribute) :height (attribute-height attribute) - :attribute attribute))) + :attribute attribute + :columns (string-width string)))) (t (loop :for (type . string) :in (split-string-by-character-type string) :unless (alexandria:emptyp string) @@ -539,12 +561,13 @@ Returns T if the cached entry matches (render can be skipped)." nil))) (defun render-row-with-caching (window y objects) - "Lay OBJECTS out as one screen row of WINDOW at Y and draw it, unless it is already on screen." + "Lay OBJECTS out as one screen row of WINDOW at Y and draw it, unless it is already on screen. +Returns the laid-out row." (let* ((reduced (reduce-objects objects)) (row (layout-row y reduced))) (unless (update-and-validate-cache-p window y (row-height row) reduced) (render-row (window-view window) row)) - (row-height row))) + row)) (defun text-row-metrics () "The ascent and height of a row holding nothing but text, as (values ASCENT HEIGHT). @@ -770,11 +793,18 @@ over the top-level spine and tolerant of improper (dotted) lists." (defstruct screen-row "One drawn row of a window, recorded as it was drawn." - height ;; which buffer line this row's logical line starts on. line-number ;; this row's index within its line. a break in virtual text starts a row without advancing it. - wrap-index) + wrap-index + ;; how much of the row's left edge the left area took + left-width + ;; as `layout-row' laid it out and the frontend drew it, so a pixel position can be read back + ;; against what is on screen rather than derived a second time. + row) + +(defun screen-row-height (screen-row) + (row-height (screen-row-row screen-row))) (defun window-screen-rows (window) "Every screen row of WINDOW, top to bottom, as recorded while it was drawn." @@ -799,6 +829,27 @@ Walks the rows because they are not all one height, so there is nothing to divid there." (nth index (window-screen-rows window))) +(defun screen-row-column-at-x (screen-row x) + "The column of SCREEN-ROW's line that pixel X, measured from the window's left edge, is over. +Walks the objects drawn rather than dividing by a cell width, which would miscount every row holding +something not one cell wide." + (let ((column 0) + (right (screen-row-left-width screen-row))) + (dolist (placement (row-placements (screen-row-row screen-row))) + (let ((object (placement-object placement)) + (left (placement-x placement))) + ;; skip the left area: line numbers and the like, which account for no column + (when (<= (screen-row-left-width screen-row) left) + (let ((width (object-width object))) + (when (and (plusp width) (< x (+ left width))) + (return-from screen-row-column-at-x + (+ column (floor (* (object-columns object) (- x left)) width)))) + (incf column (object-columns object)) + (setf right (max right (+ left width))))))) + ;; no object under x, so it is out past the line where the window is plain cells. callers clamp + ;; this to the line's end. + (+ column (floor (max 0 (- x right)) (lem-if:cell-width (implementation)))))) + (defun check-line-fingerprint (window y fingerprint) "Check if the fingerprint for line at Y matches. Returns the cached list of rows, or NIL. One entry per row, so a line taken from the cache still contributes its rows to @@ -822,11 +873,12 @@ iteration per pixel, against a cache holding one entry per line drawn." (defun update-line-fingerprint (window y fingerprint rows) "Store the fingerprint and ROWS for line at Y, and drop the rows it covers. -ROWS is one (HEIGHT . WRAP-INDEX) per screen row the line drew, as the redraw functions collect -them." +ROWS is one `screen-row' per screen row the line drew, as the redraw functions collect them." (let ((cache (line-fingerprint-cache window))) (setf (gethash y cache) (cons fingerprint rows)) - (evict-line-fingerprint-shadow cache y (reduce #'+ rows :key #'car :initial-value 0)))) + (evict-line-fingerprint-shadow cache + y + (reduce #'+ rows :key #'screen-row-height :initial-value 0)))) (defun left-side-character-count (left-side-objects) (loop :for obj :in left-side-objects @@ -856,11 +908,13 @@ them." ;; an empty row is still a row when more of the line follows, which is what a break at ;; the very start of the virtual text asks for. (unless (or objects rest-line-objects) (return)) - (let* ((all-objects (append left-side-objects objects)) - (height (render-row-with-caching window y all-objects))) - (incf y height) + (let ((row (render-row-with-caching window y (append left-side-objects objects)))) + (incf y (row-height row)) (setq left-side-objects wrapped-left-side-objects) - (push (cons height wrap-index) rows) + (push (make-screen-row :row row + :wrap-index wrap-index + :left-width left-side-width) + rows) ;; only running out of width advances the position, a virtual-text break does not. (when (eq why :wrapped) (incf wrap-index)) @@ -960,7 +1014,7 @@ creating zero temporary letter-objects." (return-from redraw-logical-line-when-horizontal-scroll cached-rows)) (let* ((rows (split-objects-at-line-breaks (create-drawing-objects logical-line))) (left-side-characters (left-side-character-count left-side-objects)) - (row-heights) + (screen-rows) (total-height 0)) ;; the cursor is on one of the rows, scrolling follows it there. (dolist (row-objects rows) @@ -989,15 +1043,16 @@ creating zero temporary letter-objects." (horizontal-scroll-start window) (+ (horizontal-scroll-start window) (window-view-width window)))) - (height (render-row-with-caching window (+ y total-height) - (append side clipped)))) - (incf total-height height) + (row (render-row-with-caching window (+ y total-height) + (append side clipped)))) + (incf total-height (row-height row)) ;; wrapping is off here, so every row begins where the line does, index 0 - (push (cons height 0) row-heights)) + (push (make-screen-row :row row :wrap-index 0 :left-width left-side-width) + screen-rows)) ;; y is in the frontend's units, as is the bound (when (<= (window-view-height window) (+ y total-height)) (return)))) - (setf row-heights (nreverse row-heights)) + (setf screen-rows (nreverse screen-rows)) ;; Reuse fingerprint if scroll position didn't change; avoids redundant sxhash (update-line-fingerprint window y @@ -1006,8 +1061,8 @@ creating zero temporary letter-objects." (compute-line-fingerprint logical-line (horizontal-scroll-start window) left-side-width)) - row-heights) - row-heights))) + screen-rows) + screen-rows))) (defun redraw-lines (window) (let* ((*line-wrap* (variable-value 'line-wrap @@ -1035,12 +1090,10 @@ creating zero temporary letter-objects." (funcall redraw-fn window y logical-line left-side-objects left-side-width)) ;; read once, shared by the line's rows (line-number (line-number-at-point line-point))) - (loop :for (row-height . wrap-index) :in line-rows - :do (push (make-screen-row :height row-height - :line-number line-number - :wrap-index wrap-index) - rows) - (incf y row-height))) + (loop :for row :in line-rows + :do (setf (screen-row-line-number row) line-number) + (push row rows) + (incf y (screen-row-height row)))) (unless (< y height) (return-from outer))))) (setf (window-screen-rows window) (nreverse rows)) diff --git a/src/mouse.lisp b/src/mouse.lisp index 429bb5e0b..84acbfb54 100644 --- a/src/mouse.lisp +++ b/src/mouse.lisp @@ -83,6 +83,19 @@ with or the window is undrawn." fallback-row)) fallback-row)) +(defun mouse-event-screen-column (mouse-event window row-index fallback-column) + "The column that MOUSE-EVENT points at on ROW-INDEX of WINDOW, counted from the top of its view. +FALLBACK-COLUMN is used when there is no pixel position to walk with or no such row was drawn." + (alexandria:if-let ((screen-row (and (mouse-event-pixel-x mouse-event) + (mouse-event-pixel-y mouse-event) + (window-screen-row-at-index window row-index)))) + (multiple-value-bind (relative-x relative-y) + (get-relative-mouse-coordinates-pixels mouse-event window) + (declare (ignore relative-y)) + ;; measured from the window's left edge, where the row was laid out from + (screen-row-column-at-x screen-row relative-x)) + fallback-column)) + (defun move-point-to-screen-row (point window row) "Move POINT to the start of screen ROW of WINDOW, counting rows from the top of its view. Uses the line recorded when the row was drawn, since counting virtual lines down from the view top @@ -216,11 +229,12 @@ that was not drawn, or whose line the buffer no longer has." (mouse-event-y mouse-event)) (when (and window (window-clickable window)) - (handle-mouse-button-down (window-buffer window) - mouse-event - :window window - :x x - :y (mouse-event-screen-row mouse-event window y)))))))) + (let ((row-index (mouse-event-screen-row mouse-event window y))) + (handle-mouse-button-down (window-buffer window) + mouse-event + :window window + :x (mouse-event-screen-column mouse-event window row-index x) + :y row-index)))))))) (defmethod handle-mouse-event ((mouse-event mouse-button-up)) (setf *last-dragged-separator* nil) @@ -282,11 +296,12 @@ that was not drawn, or whose line the buffer no longer has." (mouse-event-x mouse-event) (mouse-event-y mouse-event)) (when window - (handle-mouse-hover (window-buffer window) - mouse-event - :window window - :x x - :y (mouse-event-screen-row mouse-event window y))))) + (let ((row-index (mouse-event-screen-row mouse-event window y))) + (handle-mouse-hover (window-buffer window) + mouse-event + :window window + :x (mouse-event-screen-column mouse-event window row-index x) + :y row-index))))) ((typep *last-dragged-separator* 'window-vertical-separator) (let ((x (mouse-event-x mouse-event)) (button (mouse-event-button mouse-event))) From e3f88d5920db61dba572a6b28a7bd7f30cebb1e8 Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Mon, 3 Aug 2026 15:20:02 +0300 Subject: [PATCH 14/18] highlight a row as tall as the image on it put filled a background one text line tall while extend-to-eol filled the whole row, so selecting a line with an image on it drew two heights. send the row's top and height with a put on a tall row, paint the image's own attribute behind it, and report the caret on the row's text line when the cursor sits on the image. --- .../server/frontend/dist/assets/index.js | 2 +- frontends/server/frontend/editor.js | 31 ++++--- frontends/server/main.lisp | 88 +++++++++++++------ 3 files changed, 82 insertions(+), 39 deletions(-) diff --git a/frontends/server/frontend/dist/assets/index.js b/frontends/server/frontend/dist/assets/index.js index 572821549..7cdb66a8b 100644 --- a/frontends/server/frontend/dist/assets/index.js +++ b/frontends/server/frontend/dist/assets/index.js @@ -1 +1 @@ -var __defProp=Object.defineProperty,__commonJSMin=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),__exportAll=(e,t)=>{let n={};for(var r in e)__defProp(n,r,{get:e[r],enumerable:!0});return t||__defProp(n,Symbol.toStringTag,{value:`Module`}),n};(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var require_models=__commonJSMin((e=>{var t=e&&e.__extends||(function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};return function(t,n){if(typeof n!=`function`&&n!==null)throw TypeError(`Class extends value `+String(n)+` is not a constructor or null`);e(t,n);function r(){this.constructor=t}t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}})();Object.defineProperty(e,"__esModule",{value:!0}),e.createJSONRPCNotification=e.createJSONRPCRequest=e.createJSONRPCSuccessResponse=e.createJSONRPCErrorResponse=e.JSONRPCErrorCode=e.JSONRPCErrorException=e.isJSONRPCResponses=e.isJSONRPCResponse=e.isJSONRPCRequests=e.isJSONRPCRequest=e.isJSONRPCID=e.JSONRPC=void 0,e.JSONRPC=`2.0`,e.isJSONRPCID=function(e){return typeof e==`string`||typeof e==`number`||e===null},e.isJSONRPCRequest=function(t){return t.jsonrpc===e.JSONRPC&&t.method!==void 0&&t.result===void 0&&t.error===void 0},e.isJSONRPCRequests=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCRequest)},e.isJSONRPCResponse=function(t){return t.jsonrpc===e.JSONRPC&&t.id!==void 0&&(t.result!==void 0||t.error!==void 0)},e.isJSONRPCResponses=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCResponse)};var n=function(e,t,n){var r={code:e,message:t};return n!=null&&(r.data=n),r};e.JSONRPCErrorException=function(e){t(r,e);function r(t,n,i){var a=e.call(this,t)||this;return Object.setPrototypeOf(a,r.prototype),a.code=n,a.data=i,a}return r.prototype.toObject=function(){return n(this.code,this.message,this.data)},r}(Error),(function(e){e[e.ParseError=-32700]=`ParseError`,e[e.InvalidRequest=-32600]=`InvalidRequest`,e[e.MethodNotFound=-32601]=`MethodNotFound`,e[e.InvalidParams=-32602]=`InvalidParams`,e[e.InternalError=-32603]=`InternalError`})(e.JSONRPCErrorCode||={}),e.createJSONRPCErrorResponse=function(t,r,i,a){return{jsonrpc:e.JSONRPC,id:t,error:n(r,i,a)}},e.createJSONRPCSuccessResponse=function(t,n){return{jsonrpc:e.JSONRPC,id:t,result:n??null}},e.createJSONRPCRequest=function(t,n,r){return{jsonrpc:e.JSONRPC,id:t,method:n,params:r}},e.createJSONRPCNotification=function(t,n){return{jsonrpc:e.JSONRPC,method:t,params:n}}})),require_internal=__commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.DefaultErrorCode=void 0,e.DefaultErrorCode=0})),require_client=__commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{Object.defineProperty(e,"__esModule",{value:!0})})),require_server=__commonJSMin((e=>{var t=e&&e.__assign||function(){return t=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__createBinding||(Object.create?(function(e,t,n,r){r===void 0&&(r=n);var i=Object.getOwnPropertyDescriptor(t,n);(!i||(`get`in i?!t.__esModule:i.writable||i.configurable))&&(i={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,i)}):(function(e,t,n,r){r===void 0&&(r=n),e[r]=t[n]})),n=e&&e.__exportStar||function(e,n){for(var r in e)r!=="default"&&!Object.prototype.hasOwnProperty.call(n,r)&&t(n,e,r)};Object.defineProperty(e,"__esModule",{value:!0}),n(require_client(),e),n(require_interfaces(),e),n(require_models(),e),n(require_server(),e),n(require_server_and_client(),e)})),import_dist=require_dist(),JSONRPC=class{constructor(e,{onConnected:t,onClosed:n}){this.url=e,this.onConnected=t,this.onClosed=n,this.messageQueue=[],this.serverAndClient=null,this.connect(),this.connectionEstablished=!1,this.timerId=null,this.closed=!1}close(){this.timerId&&clearTimeout(this.timerId),this.webSocket.close(),this.closed=!0}on(e,t){this.serverAndClient.addMethod(e,t)}async requestInternal(e,t,n){let r=await this.serverAndClient.request(e,t);n&&n(r)}requestMessageQueue(){this.messageQueue.forEach(e=>{let[t,n,r]=e;this.requestInternal(t,n,r)}),this.messageQueue=[]}request(e,t,n){this.webSocket.readyState===WebSocket.OPEN?this.requestInternal(e,t,n):this.messageQueue.push([e,t,n])}notify(e,t){switch(this.webSocket.readyState){case WebSocket.OPEN:this.serverAndClient.notify(e,t);break;case WebSocket.CLOSED:break}}connect(e){this.closed||(console.log(`connect`,this.url),this.webSocket=new WebSocket(this.url),this.serverAndClient||=new import_dist.JSONRPCServerAndClient(new import_dist.JSONRPCServer,new import_dist.JSONRPCClient(e=>{try{return this.webSocket.send(JSON.stringify(e)),Promise.resolve()}catch(e){return Promise.reject(e)}})),this.webSocket.onmessage=e=>{this.serverAndClient.receiveAndSend(JSON.parse(e.data.toString()))},this.webSocket.onopen=()=>{console.log(`WebSocket connection established`),this.connectionEstablished=!0,this.onConnected&&this.onConnected(),this.requestMessageQueue()},this.webSocket.onclose=e=>{console.error(`WebScoket closed`,e),this.serverAndClient.rejectAllPendingRequests(`Connection is closed (${e.reason}).`),this.connectionEstablished&&this.onClosed(),this.timerId=setTimeout(()=>{this.connect()},3e3)},this.webSocket.onerror=e=>{console.error(`WebSocket error:`,e),this.webSocket.close()})}},keyevent_exports=__exportAll({convertKeyEvent:()=>convertKeyEvent}),modifierKeys=[`Shift`,`Control`,`Alt`,`Meta`,`CapsLock`],convertKeyTable={Enter:`Return`,ArrowRight:`Right`,ArrowLeft:`Left`,ArrowUp:`Up`,ArrowDown:`Down`,"¡":`1`,"™":`2`,"£":`3`,"¢":`4`,"∞":`5`,"§":`6`,"¶":`7`,"•":`8`,ª:`9`,º:`0`,"–":`-`,"≠":`=`,"“":`[`,"‘":`]`,"«":`\\`,"…":`;`,æ:`'`,"≤":`,`,"≥":`.`,"÷":`/`,"⁄":`!`,"€":`@`,"‹":`#`,"›":`$`,fi:`%`,fl:`^`,"‡":`&`,"°":`*`,"·":`(`,"‚":`)`,"—":`_`,"±":`+`,"”":`{`,"’":`}`,"»":`|`,Ú:`:`,Æ:`"`,"¯":`<`,"˘":`>`,"¿":`?`,œ:`q`,"∑":`w`,"´":`e`,"®":`r`,"†":`t`,"¥":`y`,"¨":`u`,ˆ:`i`,ø:`o`,π:`p`,å:`a`,ß:`s`,"∂":`d`,ƒ:`f`,"©":`g`,"˙":`h`,"∆":`j`,"˚":`k`,"¬":`l`,Ω:`z`,"≈":`x`,ç:`c`,"√":`v`,"∫":`b`,"˜":`n`,µ:`m`,Œ:`Q`,"„":`W`,"´":`E`,"‰":`R`,ˇ:`T`,Á:`Y`,"¨":`U`,ˆ:`I`,Ø:`O`,"∏":`P`,Å:`A`,Í:`S`,Î:`D`,Ï:`F`,"˝":`G`,Ó:`H`,Ô:`J`,"":`K`,Ò:`L`,"¸":`Z`,"˛":`X`,Ç:`C`,"◊":`V`,ı:`B`,"˜":`N`,Â:`M`};function getKey(e){return e.altKey?convertKeyTable[e.key]||(e.code.startsWith(`Key`)?e.code[3].toLowerCase():null)||e.key:convertKeyTable[e.key]||e.key}function convertKeyEvent(e){return modifierKeys.indexOf(e.key)===-1?{key:getKey(e),ctrl:e.ctrlKey,meta:e.altKey,super:e.metaKey,shift:e.shiftKey}:null}var lib_exports=__exportAll({computeWidth:()=>computeWidth,eawVersion:()=>version,getEAW:()=>getEAW}),defs=[[0,31,`N`],[32,126,`Na`],[127,160,`N`],[161,161,`A`],[162,163,`Na`],[164,164,`A`],[165,166,`Na`],[167,168,`A`],[169,169,`N`],[170,170,`A`],[171,171,`N`],[172,172,`Na`],[173,174,`A`],[175,175,`Na`],[176,180,`A`],[181,181,`N`],[182,186,`A`],[187,187,`N`],[188,191,`A`],[192,197,`N`],[198,198,`A`],[199,207,`N`],[208,208,`A`],[209,214,`N`],[215,216,`A`],[217,221,`N`],[222,225,`A`],[226,229,`N`],[230,230,`A`],[231,231,`N`],[232,234,`A`],[235,235,`N`],[236,237,`A`],[238,239,`N`],[240,240,`A`],[241,241,`N`],[242,243,`A`],[244,246,`N`],[247,250,`A`],[251,251,`N`],[252,252,`A`],[253,253,`N`],[254,254,`A`],[255,256,`N`],[257,257,`A`],[258,272,`N`],[273,273,`A`],[274,274,`N`],[275,275,`A`],[276,282,`N`],[283,283,`A`],[284,293,`N`],[294,295,`A`],[296,298,`N`],[299,299,`A`],[300,304,`N`],[305,307,`A`],[308,311,`N`],[312,312,`A`],[313,318,`N`],[319,322,`A`],[323,323,`N`],[324,324,`A`],[325,327,`N`],[328,331,`A`],[332,332,`N`],[333,333,`A`],[334,337,`N`],[338,339,`A`],[340,357,`N`],[358,359,`A`],[360,362,`N`],[363,363,`A`],[364,461,`N`],[462,462,`A`],[463,463,`N`],[464,464,`A`],[465,465,`N`],[466,466,`A`],[467,467,`N`],[468,468,`A`],[469,469,`N`],[470,470,`A`],[471,471,`N`],[472,472,`A`],[473,473,`N`],[474,474,`A`],[475,475,`N`],[476,476,`A`],[477,592,`N`],[593,593,`A`],[594,608,`N`],[609,609,`A`],[610,707,`N`],[708,708,`A`],[709,710,`N`],[711,711,`A`],[712,712,`N`],[713,715,`A`],[716,716,`N`],[717,717,`A`],[718,719,`N`],[720,720,`A`],[721,727,`N`],[728,731,`A`],[732,732,`N`],[733,733,`A`],[734,734,`N`],[735,735,`A`],[736,767,`N`],[768,879,`A`],[880,912,`N`],[913,929,`A`],[930,930,`N`],[931,937,`A`],[938,944,`N`],[945,961,`A`],[962,962,`N`],[963,969,`A`],[970,1024,`N`],[1025,1025,`A`],[1026,1039,`N`],[1040,1103,`A`],[1104,1104,`N`],[1105,1105,`A`],[1106,4351,`N`],[4352,4447,`W`],[4448,8207,`N`],[8208,8208,`A`],[8209,8210,`N`],[8211,8214,`A`],[8215,8215,`N`],[8216,8217,`A`],[8218,8219,`N`],[8220,8221,`A`],[8222,8223,`N`],[8224,8226,`A`],[8227,8227,`N`],[8228,8231,`A`],[8232,8239,`N`],[8240,8240,`A`],[8241,8241,`N`],[8242,8243,`A`],[8244,8244,`N`],[8245,8245,`A`],[8246,8250,`N`],[8251,8251,`A`],[8252,8253,`N`],[8254,8254,`A`],[8255,8307,`N`],[8308,8308,`A`],[8309,8318,`N`],[8319,8319,`A`],[8320,8320,`N`],[8321,8324,`A`],[8325,8360,`N`],[8361,8361,`H`],[8362,8363,`N`],[8364,8364,`A`],[8365,8450,`N`],[8451,8451,`A`],[8452,8452,`N`],[8453,8453,`A`],[8454,8456,`N`],[8457,8457,`A`],[8458,8466,`N`],[8467,8467,`A`],[8468,8469,`N`],[8470,8470,`A`],[8471,8480,`N`],[8481,8482,`A`],[8483,8485,`N`],[8486,8486,`A`],[8487,8490,`N`],[8491,8491,`A`],[8492,8530,`N`],[8531,8532,`A`],[8533,8538,`N`],[8539,8542,`A`],[8543,8543,`N`],[8544,8555,`A`],[8556,8559,`N`],[8560,8569,`A`],[8570,8584,`N`],[8585,8585,`A`],[8586,8591,`N`],[8592,8601,`A`],[8602,8631,`N`],[8632,8633,`A`],[8634,8657,`N`],[8658,8658,`A`],[8659,8659,`N`],[8660,8660,`A`],[8661,8678,`N`],[8679,8679,`A`],[8680,8703,`N`],[8704,8704,`A`],[8705,8705,`N`],[8706,8707,`A`],[8708,8710,`N`],[8711,8712,`A`],[8713,8714,`N`],[8715,8715,`A`],[8716,8718,`N`],[8719,8719,`A`],[8720,8720,`N`],[8721,8721,`A`],[8722,8724,`N`],[8725,8725,`A`],[8726,8729,`N`],[8730,8730,`A`],[8731,8732,`N`],[8733,8736,`A`],[8737,8738,`N`],[8739,8739,`A`],[8740,8740,`N`],[8741,8741,`A`],[8742,8742,`N`],[8743,8748,`A`],[8749,8749,`N`],[8750,8750,`A`],[8751,8755,`N`],[8756,8759,`A`],[8760,8763,`N`],[8764,8765,`A`],[8766,8775,`N`],[8776,8776,`A`],[8777,8779,`N`],[8780,8780,`A`],[8781,8785,`N`],[8786,8786,`A`],[8787,8799,`N`],[8800,8801,`A`],[8802,8803,`N`],[8804,8807,`A`],[8808,8809,`N`],[8810,8811,`A`],[8812,8813,`N`],[8814,8815,`A`],[8816,8833,`N`],[8834,8835,`A`],[8836,8837,`N`],[8838,8839,`A`],[8840,8852,`N`],[8853,8853,`A`],[8854,8856,`N`],[8857,8857,`A`],[8858,8868,`N`],[8869,8869,`A`],[8870,8894,`N`],[8895,8895,`A`],[8896,8977,`N`],[8978,8978,`A`],[8979,8985,`N`],[8986,8987,`W`],[8988,9e3,`N`],[9001,9002,`W`],[9003,9192,`N`],[9193,9196,`W`],[9197,9199,`N`],[9200,9200,`W`],[9201,9202,`N`],[9203,9203,`W`],[9204,9311,`N`],[9312,9449,`A`],[9450,9450,`N`],[9451,9547,`A`],[9548,9551,`N`],[9552,9587,`A`],[9588,9599,`N`],[9600,9615,`A`],[9616,9617,`N`],[9618,9621,`A`],[9622,9631,`N`],[9632,9633,`A`],[9634,9634,`N`],[9635,9641,`A`],[9642,9649,`N`],[9650,9651,`A`],[9652,9653,`N`],[9654,9655,`A`],[9656,9659,`N`],[9660,9661,`A`],[9662,9663,`N`],[9664,9665,`A`],[9666,9669,`N`],[9670,9672,`A`],[9673,9674,`N`],[9675,9675,`A`],[9676,9677,`N`],[9678,9681,`A`],[9682,9697,`N`],[9698,9701,`A`],[9702,9710,`N`],[9711,9711,`A`],[9712,9724,`N`],[9725,9726,`W`],[9727,9732,`N`],[9733,9734,`A`],[9735,9736,`N`],[9737,9737,`A`],[9738,9741,`N`],[9742,9743,`A`],[9744,9747,`N`],[9748,9749,`W`],[9750,9755,`N`],[9756,9756,`A`],[9757,9757,`N`],[9758,9758,`A`],[9759,9791,`N`],[9792,9792,`A`],[9793,9793,`N`],[9794,9794,`A`],[9795,9799,`N`],[9800,9811,`W`],[9812,9823,`N`],[9824,9825,`A`],[9826,9826,`N`],[9827,9829,`A`],[9830,9830,`N`],[9831,9834,`A`],[9835,9835,`N`],[9836,9837,`A`],[9838,9838,`N`],[9839,9839,`A`],[9840,9854,`N`],[9855,9855,`W`],[9856,9874,`N`],[9875,9875,`W`],[9876,9885,`N`],[9886,9887,`A`],[9888,9888,`N`],[9889,9889,`W`],[9890,9897,`N`],[9898,9899,`W`],[9900,9916,`N`],[9917,9918,`W`],[9919,9919,`A`],[9920,9923,`N`],[9924,9925,`W`],[9926,9933,`A`],[9934,9934,`W`],[9935,9939,`A`],[9940,9940,`W`],[9941,9953,`A`],[9954,9954,`N`],[9955,9955,`A`],[9956,9959,`N`],[9960,9961,`A`],[9962,9962,`W`],[9963,9969,`A`],[9970,9971,`W`],[9972,9972,`A`],[9973,9973,`W`],[9974,9977,`A`],[9978,9978,`W`],[9979,9980,`A`],[9981,9981,`W`],[9982,9983,`A`],[9984,9988,`N`],[9989,9989,`W`],[9990,9993,`N`],[9994,9995,`W`],[9996,10023,`N`],[10024,10024,`W`],[10025,10044,`N`],[10045,10045,`A`],[10046,10059,`N`],[10060,10060,`W`],[10061,10061,`N`],[10062,10062,`W`],[10063,10066,`N`],[10067,10069,`W`],[10070,10070,`N`],[10071,10071,`W`],[10072,10101,`N`],[10102,10111,`A`],[10112,10132,`N`],[10133,10135,`W`],[10136,10159,`N`],[10160,10160,`W`],[10161,10174,`N`],[10175,10175,`W`],[10176,10213,`N`],[10214,10221,`Na`],[10222,10628,`N`],[10629,10630,`Na`],[10631,11034,`N`],[11035,11036,`W`],[11037,11087,`N`],[11088,11088,`W`],[11089,11092,`N`],[11093,11093,`W`],[11094,11097,`A`],[11098,11903,`N`],[11904,11929,`W`],[11930,11930,`N`],[11931,12019,`W`],[12020,12031,`N`],[12032,12245,`W`],[12246,12271,`N`],[12272,12287,`W`],[12288,12288,`F`],[12289,12350,`W`],[12351,12352,`N`],[12353,12438,`W`],[12439,12440,`N`],[12441,12543,`W`],[12544,12548,`N`],[12549,12591,`W`],[12592,12592,`N`],[12593,12686,`W`],[12687,12687,`N`],[12688,12771,`W`],[12772,12782,`N`],[12783,12830,`W`],[12831,12831,`N`],[12832,12871,`W`],[12872,12879,`A`],[12880,19903,`W`],[19904,19967,`N`],[19968,42124,`W`],[42125,42127,`N`],[42128,42182,`W`],[42183,43359,`N`],[43360,43388,`W`],[43389,44031,`N`],[44032,55203,`W`],[55204,57343,`N`],[57344,63743,`A`],[63744,64255,`W`],[64256,65023,`N`],[65024,65039,`A`],[65040,65049,`W`],[65050,65071,`N`],[65072,65106,`W`],[65107,65107,`N`],[65108,65126,`W`],[65127,65127,`N`],[65128,65131,`W`],[65132,65280,`N`],[65281,65376,`F`],[65377,65470,`H`],[65471,65473,`N`],[65474,65479,`H`],[65480,65481,`N`],[65482,65487,`H`],[65488,65489,`N`],[65490,65495,`H`],[65496,65497,`N`],[65498,65500,`H`],[65501,65503,`N`],[65504,65510,`F`],[65511,65511,`N`],[65512,65518,`H`],[65519,65532,`N`],[65533,65533,`A`],[65534,94175,`N`],[94176,94180,`W`],[94181,94191,`N`],[94192,94193,`W`],[94194,94207,`N`],[94208,100343,`W`],[100344,100351,`N`],[100352,101589,`W`],[101590,101631,`N`],[101632,101640,`W`],[101641,110575,`N`],[110576,110579,`W`],[110580,110580,`N`],[110581,110587,`W`],[110588,110588,`N`],[110589,110590,`W`],[110591,110591,`N`],[110592,110882,`W`],[110883,110897,`N`],[110898,110898,`W`],[110899,110927,`N`],[110928,110930,`W`],[110931,110932,`N`],[110933,110933,`W`],[110934,110947,`N`],[110948,110951,`W`],[110952,110959,`N`],[110960,111355,`W`],[111356,126979,`N`],[126980,126980,`W`],[126981,127182,`N`],[127183,127183,`W`],[127184,127231,`N`],[127232,127242,`A`],[127243,127247,`N`],[127248,127277,`A`],[127278,127279,`N`],[127280,127337,`A`],[127338,127343,`N`],[127344,127373,`A`],[127374,127374,`W`],[127375,127376,`A`],[127377,127386,`W`],[127387,127404,`A`],[127405,127487,`N`],[127488,127490,`W`],[127491,127503,`N`],[127504,127547,`W`],[127548,127551,`N`],[127552,127560,`W`],[127561,127567,`N`],[127568,127569,`W`],[127570,127583,`N`],[127584,127589,`W`],[127590,127743,`N`],[127744,127776,`W`],[127777,127788,`N`],[127789,127797,`W`],[127798,127798,`N`],[127799,127868,`W`],[127869,127869,`N`],[127870,127891,`W`],[127892,127903,`N`],[127904,127946,`W`],[127947,127950,`N`],[127951,127955,`W`],[127956,127967,`N`],[127968,127984,`W`],[127985,127987,`N`],[127988,127988,`W`],[127989,127991,`N`],[127992,128062,`W`],[128063,128063,`N`],[128064,128064,`W`],[128065,128065,`N`],[128066,128252,`W`],[128253,128254,`N`],[128255,128317,`W`],[128318,128330,`N`],[128331,128334,`W`],[128335,128335,`N`],[128336,128359,`W`],[128360,128377,`N`],[128378,128378,`W`],[128379,128404,`N`],[128405,128406,`W`],[128407,128419,`N`],[128420,128420,`W`],[128421,128506,`N`],[128507,128591,`W`],[128592,128639,`N`],[128640,128709,`W`],[128710,128715,`N`],[128716,128716,`W`],[128717,128719,`N`],[128720,128722,`W`],[128723,128724,`N`],[128725,128727,`W`],[128728,128731,`N`],[128732,128735,`W`],[128736,128746,`N`],[128747,128748,`W`],[128749,128755,`N`],[128756,128764,`W`],[128765,128991,`N`],[128992,129003,`W`],[129004,129007,`N`],[129008,129008,`W`],[129009,129291,`N`],[129292,129338,`W`],[129339,129339,`N`],[129340,129349,`W`],[129350,129350,`N`],[129351,129535,`W`],[129536,129647,`N`],[129648,129660,`W`],[129661,129663,`N`],[129664,129672,`W`],[129673,129679,`N`],[129680,129725,`W`],[129726,129726,`N`],[129727,129733,`W`],[129734,129741,`N`],[129742,129755,`W`],[129756,129759,`N`],[129760,129768,`W`],[129769,129775,`N`],[129776,129784,`W`],[129785,131071,`N`],[131072,196605,`W`],[196606,196607,`N`],[196608,262141,`W`],[262142,917759,`N`],[917760,917999,`A`],[918e3,983039,`N`],[983040,1048573,`A`],[1048574,1048575,`N`],[1048576,1114109,`A`],[1114110,1114111,`N`]],version=`15.1.0`;function getEAWOfCodePoint(e){let t=0,n=defs.length-1;for(;t!==n;){let r=t+(n-t>>1),[i,a,o]=defs[r];if(ea)t=r+1;else return o}return defs[t][2]}function getEAW(e,t=0){let n=e.codePointAt(t);if(n!==void 0)return getEAWOfCodePoint(n)}var defaultWidths={N:1,Na:1,W:2,F:2,H:1,A:1};function computeWidth(e,t){let n=0;for(let r of e){let e=getEAW(r);n+=t&&t[e]||defaultWidths[e]}return n}var textOffsetY=5,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function isWideChar(e){switch(getEAW(e)){case`F`:case`W`:return!0;default:return!1}}function isMacOS(){return window.navigator.userAgent.indexOf(`Mac OS X`)!==-1}function computeFontSize(e){let t=document.createElement(`canvas`).getContext(`2d`);t.font=e;let n=t.measureText(`W`);return[Math.floor(n.width),Math.round(n.fontBoundingBoxAscent+textOffsetY+(n.emHeightDescent||0)),Math.round(n.fontBoundingBoxAscent+textOffsetY)]}function drawBlock({ctx:e,x:t,y:n,width:r,height:i,style:a}){e.fillStyle=a,e.fillRect(t,n,r,i)}function drawText({ctx:e,x:t,y:n,text:r,font:i,style:a,option:o}){n+=Math.round(textOffsetY),e.fillStyle=a,e.font=i,e.textBaseline=`top`;for(let i of r)isWideChar(i)?(e.fillText(i,t,n,o.fontWidth*2),t+=o.fontWidth*2):(e.fillText(i,t,n,o.fontWidth),t+=o.fontWidth)}function drawHorizontalLine({ctx:e,x:t,y:n,width:r,style:i,lineWidth:a=1}){e.strokeStyle=i,e.lineWidth=a,e.setLineDash=[],e.beginPath(),e.moveTo(t,n),e.lineTo(t+r,n),e.stroke()}var Option=class{constructor({fontName:e,fontSize:t}){this.setFont(e,t),this.foreground=`#cccccc`,this.background=`#2d2d2d`}setFont(e,t){let n=t+`px `+e,[r,i,a]=computeFontSize(n);this.fontName=e,this.fontSize=t,this.fontWidth=r,this.fontHeight=i,this.fontAscent=a,this.font=n}};function getLemEditorElement(){return document.getElementById(`lem-editor`)}function normalizeWheelDelta(e,t,n,r){switch(n){case 0:return{dx:e/r,dy:t/r};case 2:return{dx:e*20,dy:t*20};default:return{dx:e,dy:t}}}function extractWholeLines(e,t){let n=Math.trunc(e),r=Math.trunc(t);return{scrollX:n,scrollY:r,remainderX:e-n,remainderY:t-r}}function cursorPosition(e,t){let[n,r]=t.getDisplayRectangle(),i=e.clientX-n,a=e.clientY-r;return{pixelX:i,pixelY:a,x:Math.floor(i/t.option.fontWidth),y:Math.floor(a/t.option.fontHeight)}}function makeWheelHandler(e){let t={x:0,y:0},n=!1,r={pixelX:0,pixelY:0,x:0,y:0};return i=>{i.preventDefault(),r=cursorPosition(i,e);let{dx:a,dy:o}=normalizeWheelDelta(i.deltaX,i.deltaY,i.deltaMode,e.option.fontHeight);t={x:t.x+a,y:t.y+o},n||(n=!0,requestAnimationFrame(()=>{n=!1;let{scrollX:i,scrollY:a,remainderX:o,remainderY:s}=extractWholeLines(t.x,t.y);t={x:o,y:s},(i!==0||a!==0)&&e.jsonrpc.notify(`input`,{kind:`wheel`,value:{...r,wheelX:-i,wheelY:-a}})}))}}function addMouseEventListeners({dom:e,editor:t,isDraggable:n,draggableStyle:r}){e.addEventListener(`contextmenu`,e=>{e.preventDefault()});let i=(e,n)=>{e.preventDefault();let[r,i]=t.getDisplayRectangle(),a=e.clientX-r,o=e.clientY-i,s=Math.floor(a/t.option.fontWidth),c=Math.floor(o/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:n,value:{x:s,y:c,pixelX:a,pixelY:o,button:e.button,clicks:e.detail}})};e.addEventListener(`mousedown`,e=>{n&&(document.body.style.cursor=r),t.focusHiddenInput(),i(e,`mousedown`)}),e.addEventListener(`mouseup`,e=>{n&&(document.body.style.cursor=`default`),i(e,`mouseup`)});let a=0;e.addEventListener(`mousemove`,e=>{e.preventDefault();let n=Date.now();if(n-a>50){a=n;let[r,i]=t.getDisplayRectangle(),o=e.clientX-r,s=e.clientY-i,c=Math.floor(o/t.option.fontWidth),l=Math.floor(s/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:`mousemove`,value:{x:c,y:l,pixelX:o,pixelY:s,button:e.buttons===0?null:e.buttons-1}})}}),n&&(e.addEventListener(`mouseover`,()=>{document.body.style.cursor=r}),e.addEventListener(`mouseout`,e=>{e.buttons!==1&&(document.body.style.cursor=`default`)})),e.addEventListener(`wheel`,makeWheelHandler(t))}var zIndexTable={"floating-window":200,modeline:100,"vertical-border":100,"horizontal-border":101};function zindex(e){return zIndexTable[e]||0}var borderOffsetX=5,borderOffsetY=10,BaseSurface=class{constructor({editor:e}){this.editor=e,this.mainDOM=null,this.wrapper=null}delete(){this.wrapper?getLemEditorElement().removeChild(this.wrapper):getLemEditorElement().removeChild(this.mainDOM)}setupDOM({dom:e,isFloating:t,border:n,cssClassName:r}){this.mainDOM=e,t&&n?(this.wrapper=document.createElement(`div`),r&&(this.wrapper.className=r),this.wrapper.style.position=`absolute`,this.wrapper.style.backgroundColor=this.editor.option.background,this.wrapper.style.zIndex=zindex(`floating-window`),this.wrapper.appendChild(e),getLemEditorElement().appendChild(this.wrapper)):(r&&(e.className=r),getLemEditorElement().appendChild(e))}move(e,t){let[n,r]=this.editor.getDisplayRectangle(),i=Math.floor(n+e),a=Math.floor(r+t);this.wrapper?(this.wrapper.style.left=i-borderOffsetX+`px`,this.wrapper.style.top=a-borderOffsetY+`px`,this.mainDOM.style.left=borderOffsetX+`px`,this.mainDOM.style.top=borderOffsetY+`px`):(this.mainDOM.style.left=i+`px`,this.mainDOM.style.top=a+`px`)}_resize(e,t){let n=window.devicePixelRatio||1;this.mainDOM.width=e*n,this.mainDOM.height=t*n,this.mainDOM.style.width=e+`px`,this.mainDOM.style.height=t+`px`,this.wrapper&&(this.wrapper.style.width=e+borderOffsetX*2+`px`,this.wrapper.style.height=t+borderOffsetY*2+`px`)}drawBlock(e,t,n,r,i){}drawText(e,t,n,r,i,a){}drawImage(e,t,n,r,i,a,o){}clearImages(e,t){}clearAllImages(){}touch(){}evalIn(code){return eval(code)}},CanvasSurface=class extends BaseSurface{constructor({editor:e,view:t,pixelX:n,pixelY:r,pixelWidth:i,pixelHeight:a,styles:o,isFloating:s,border:c,cssClassName:l}){super({editor:e});let u=this.setupCanvas(o);this.setupDOM({dom:u,isFloating:s,border:c,cssClassName:l}),this.move(n,r),this.resize(i,a),this.drawingQueue=[],addMouseEventListeners({dom:u,editor:e})}setupCanvas(e){let t=document.createElement(`canvas`);if(t.style.position=`absolute`,e)for(let n in e)t.style[n]=e[n];return t}resize(e,t){this._resize(e,t);let n=window.devicePixelRatio||1;this.mainDOM.getContext(`2d`).scale(n,n)}move(e,t){if(super.move(e,t),this.imageEls)for(let[,e]of this.imageEls)this.positionImage(e)}delete(){this.clearAllImages(),super.delete()}drawBlock(e,t,n,r,i){this.drawingQueue.push(function(a){drawBlock({ctx:a,x:e,y:t,width:n,height:r,style:i})})}drawText(e,t,n,r,i,a){let o=this.editor.option,s=o.fontHeight;this.drawingQueue.push(function(c){if(a=a?`${o.fontSize}px ${a}`:o.font,!i)drawBlock({ctx:c,x:e,y:t,width:r,height:s,style:o.background}),drawText({ctx:c,x:e,y:t,text:n,style:o.foreground,font:a,option:o});else{let{foreground:l,background:u,bold:d,reverse:f,underline:p,cursor:m}=i;if(l||=o.foreground,u||=o.background,f){let e=u;u=l,l=e}m&&(u=o.background),drawBlock({ctx:c,x:e,y:t,width:r,height:s,style:u}),drawText({ctx:c,x:e,y:t,text:n,style:l,font:d?`bold `+a:a,option:o}),p&&drawHorizontalLine({ctx:c,x:e,y:t+o.fontHeight-2,width:r,style:typeof p==`string`?p:l,lineWidth:2})}})}imageBaseLeft(){return parseFloat(this.mainDOM.style.left)||0}imageBaseTop(){return parseFloat(this.mainDOM.style.top)||0}drawImage(e,t,n,r,i,a,o){this.imageEls||=new Map;let s=e+`,`+t,c=this.imageEls.get(s);if(c&&c.url!==o&&(c.el.remove(),this.imageEls.delete(s),c=null),!c){let e=document.createElement(`img`);e.style.position=`absolute`,e.style.pointerEvents=`none`,e.style.zIndex=`1`,e.src=o,this.mainDOM.parentNode.appendChild(e),c={el:e,url:o},this.imageEls.set(s,c)}c.x=e,c.y=t,c.width=n,c.height=r,c.clipWidth=i,c.clipHeight=a,this.positionImage(c)}positionImage(e){e.el.style.left=this.imageBaseLeft()+e.x+`px`,e.el.style.top=this.imageBaseTop()+e.y+`px`,e.el.style.width=e.width+`px`,e.el.style.height=e.height+`px`;let t=e.clipWidth==null?0:Math.max(0,e.width-e.clipWidth),n=e.clipHeight==null?0:Math.max(0,e.height-e.clipHeight);e.el.style.clipPath=t>0||n>0?`inset(0px ${t}px ${n}px 0px)`:``}clearImages(e,t){if(this.imageEls)for(let[n,r]of this.imageEls){let i=r.y+(r.height||0);r.ye&&(r.el.remove(),this.imageEls.delete(n))}}clearAllImages(){if(this.imageEls){for(let[,e]of this.imageEls)e.el.remove();this.imageEls.clear()}}touch(){let e=this.mainDOM.getContext(`2d`);for(let t of this.drawingQueue)t(e);this.drawingQueue=[]}activate(){this.mainDOM.dataset.store=`active`}deactivate(){this.mainDOM.dataset.store=`inactive`}},HTMLSurface=class extends BaseSurface{constructor({editor:e,pixelX:t,pixelY:n,pixelWidth:r,pixelHeight:i,styles:a,option:o,isFloating:s,border:c,html:l}){super({editor:e});let u=document.createElement(`iframe`);this.setupDOM({dom:u,isFloating:s,border:c}),u.style.position=`absolute`,u.style.backgroundColor=o.background,u.setAttribute(`sandbox`,`allow-scripts allow-same-origin`),u.srcdoc=l,u.addEventListener(`load`,()=>{let e=u.contentWindow;e.invokeLem=(e,t)=>parent.postMessage({type:`invoke-lem`,method:e,args:t})}),this.iframe=u,this.move(t,n),this.resize(r,i)}resize(e,t){this._resize(e,t)}update(e){let t=this.iframe.contentWindow.scrollY;this.iframe.srcdoc=e,this.iframe.onload=()=>{this.iframe.onload=null,this.iframe.contentWindow.scrollTo(0,t)}}evalIn(e){return this.iframe.contentWindow.eval(e)}},VerticalBorder=class{constructor({x:e,y:t,height:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__vertical-border`,this.line.style.height=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`vertical-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`col-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=Math.floor(n+e-this.option.fontWidth/2)+`px`,this.line.style.top=r+t+`px`}resize(e){this.line.style.height=e+`px`}},HorizontalBorder=class{constructor({x:e,y:t,width:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__horizontal-border`,this.line.style.width=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`horizontal-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`row-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=n+e+`px`,this.line.style.top=Math.floor(r+t-4)+`px`}resize(e){this.line.style.width=e+`px`}},viewStyles={header:()=>{},tile:()=>{},floating:e=>({boxSizing:`border-box`,borderColor:e.foreground,backgroundColor:e.background})};function getViewStyle(e,t){return viewStyles[e](t)||{}}var View=class{constructor({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,option:h,editor:g}){switch(this.option=h,this.id=e,this.x=t,this.y=n,this.width=r,this.height=i,this.pixelX=a,this.pixelY=o,this.pixelWidth=s,this.pixelHeight=c,this.useModeline=l,this.kind=u,this.type=d,this.border=p,this.borderShape=m,this.editor=g,this.bottomBar=null,this.leftsideBar=null,u){case`tile`:this.mainSurface=this.makeSurface(d,f),this.leftSideBar=new VerticalBorder({x:a,y:o,height:c+(l?h.fontHeight:0),option:h,editor:g}),l||(this.bottomBar=new HorizontalBorder({x:a,y:o+c-h.fontHeight,width:s,option:h,editor:g}));break;case`header`:this.mainSurface=this.makeSurface(d,f);break;case`floating`:this.mainSurface=this.makeSurface(d,f),m===`left-border`&&(this.leftSideBar=new VerticalBorder({x:a,y:o,height:c,option:h,editor:g}));break}this.modelineSurface=l?this.makeModelineSurface():null}delete(){this.mainSurface.delete(),this.modelineSurface&&this.modelineSurface.delete(),this.leftSideBar&&this.leftSideBar.delete(),this.bottomBar&&this.bottomBar.delete()}move(e,t,n,r){this.x=e,this.y=t,this.pixelX=n,this.pixelY=r,this.mainSurface.move(n,r),this.modelineSurface&&this.modelineSurface.move(n,r+this.pixelHeight),this.leftSideBar&&this.leftSideBar.move(n,r),this.bottomBar&&this.bottomBar.move(n,r+this.pixelHeight)}resize(e,t,n,r){this.width=e,this.height=t,this.pixelWidth=n,this.pixelHeight=r,this.mainSurface.resize(n,r),this.modelineSurface&&(this.modelineSurface.move(this.pixelX,this.pixelY+r),this.modelineSurface.resize(n,this.option.fontHeight)),this.leftSideBar&&this.leftSideBar.resize(r+(this.modelineSurface?this.option.fontHeight:0)),this.bottomBar&&this.bottomBar.resize(n)}clear(){this.mainSurface.drawBlock(0,0,this.pixelWidth,this.pixelHeight,this.option.background),this.mainSurface.clearImages(0,this.pixelHeight)}clearEol(e,t,n){n??=this.option.fontHeight,this.mainSurface.drawBlock(e,t,this.pixelWidth-e,n,this.option.background),this.mainSurface.clearImages(t,t+n)}clearEob(e,t){this.mainSurface.drawBlock(e,t,this.pixelWidth,this.pixelHeight-t,this.option.background),this.mainSurface.clearImages(t,this.pixelHeight)}print(e,t,n,r,i,a){this.mainSurface.drawText(e,t,n,r,i,a)}drawBlock(e,t,n,r,i){this.mainSurface.drawBlock(e,t,n,r,i||this.option.background)}drawBlockOnModeline(e,t,n,r,i){this.modelineSurface&&this.modelineSurface.drawBlock(e,t,n,r,i||this.option.background)}printImage(e,t,n,r,i,a,o){this.mainSurface.drawImage(e,t,n,r,i,a,o)}printToModeline(e,t,n,r,i){this.modelineSurface&&this.modelineSurface.drawText(e,t,n,r,i,null)}touch(e){this.mainSurface.touch(),this.modelineSurface&&(this.modelineSurface.touch(),e?this.modelineSurface.activate():this.modelineSurface.deactivate())}makeSurface(e,t){switch(e){case`html`:return this.makeHTMLSurface(t);case`editor`:return this.makeEditorSurface();default:console.error(`unknown type: ${e}`)}}makeHTMLSurface(e){return new HTMLSurface({editor:this.editor,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),option:this.option,isFloating:this.kind===`floating`,border:this.border,html:e})}makeEditorSurface(){let e=this.borderShape===`left-border`?0:this.border,t=this.kind===`floating`;return new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),editor:this.editor,border:e,isFloating:t,view:this,cssClassName:t&&e?`lem-editor__floating-window--bordered`:null})}makeModelineSurface(){let e=new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY+this.pixelHeight,pixelWidth:this.pixelWidth,pixelHeight:this.option.fontHeight,editor:this.editor,view:this,styles:{zIndex:zindex(`modeline`)},cssClassName:`lem-editor__mode-line`});return addMouseEventListeners({dom:e.mainDOM,editor:this.editor,isDraggable:!0,draggableStyle:`row-resize`}),e}changeToHTMLContent(e){this.mainSurface.constructor.name===`HTMLSurface`?this.mainSurface.update(e):(this.mainSurface.delete(),this.mainSurface=this.makeHTMLSurface(e))}changeToEditorContent(){this.mainSurface.delete(),this.mainSurface=this.makeEditorSurface()}evalIn(e){return this.mainSurface.evalIn(e)}};function isPasteKeyEvent(e){return isMacOS()?e.metaKey&&e.key===`v`:e.ctrlKey&&e.shiftKey&&e.key===`V`}var Input=class{constructor(e){let t=e.option;this.editor=e,this.composition=!1,this.ignoreKeydownAfterCompositionend=!1,this.span=document.createElement(`span`),this.span.style.color=t.foreground,this.span.style.backgroundColor=t.background,this.span.style.position=`absolute`,this.span.style.zIndex=1e6,this.span.style.top=`0`,this.span.style.left=`0`,this.span.style.font=t.font,this.input=document.createElement(`input`),this.input.style.backgroundColor=`transparent`,this.input.style.color=`transparent`,this.input.style.width=`0`,this.input.style.padding=`0`,this.input.style.margin=`0`,this.input.style.border=`none`,this.input.style.position=`absolute`,this.input.style.zIndex=`-10`,this.input.style.top=`0`,this.input.style.left=`0`,this.input.style.font=t.font,this.input.addEventListener(`blur`,e=>{this.input.focus()}),this.input.addEventListener(`input`,e=>{this.composition===!1&&(this.input.value=``,this.span.innerHTML=``,this.input.style.width=`0`,isMacOS()||this.editor.emitInputString(e.data))}),this.input.addEventListener(`paste`,async e=>{e.preventDefault();let t=e.clipboardData||window.Clipboard.data,n=t?.getData(`text`)??t?.getData(`text/plain`);if(n&&n.length>0){this.editor.emitInputString(n);return}try{if(navigator.clipboard?.readText){let e=await navigator.clipboard.readText();if(e&&e.length>0){this.editor.emitInputString(e);return}}}catch(e){console.warn(`clipboard.readText() failed:`,e)}alert(`Paste failed (permission/environment restriction`)}),this.input.addEventListener(`keydown`,e=>{if(!isPasteKeyEvent(e)&&!(e.isComposing||this.composition)&&e.key!==`Process`){if(this.ignoreKeydownAfterCompositionend&&(isSafari||isMacOS())){e.preventDefault(),this.ignoreKeydownAfterCompositionend=!1;return}if(!(!isMacOS()&&!e.ctrlKey&&!e.altKey&&e.key.length===1)&&(e.preventDefault(),e.isComposing!==!0&&e.code!==``))return setTimeout(()=>{this.composition||(this.editor.emitInput(e),this.input.value=``)},0),!1}}),this.input.addEventListener(`compositionstart`,e=>{this.composition=!0,this.span.innerHTML=this.input.value,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionupdate`,e=>{this.span.innerHTML=e.data,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionend`,e=>{this.composition=!1,this.editor.emitInputString(this.input.value),this.input.value=``,this.span.innerHTML=this.input.value,this.input.style.width=`0`,this.ignoreKeydownAfterCompositionend=!0}),document.body.appendChild(this.input),document.body.appendChild(this.span),this.input.focus()}finalize(){document.body.removeChild(this.input),document.body.removeChild(this.span)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.span.style.top=r+t+`px`,this.span.style.left=n+e+`px`,this.input.style.top=this.span.offsetTop+`px`,this.input.style.left=this.span.offsetLeft+`px`}updateForeground(e){this.span.style.color=e}updateBackground(e){this.span.style.backgroundColor=e}},MessageTable=class{constructor(){this.map=new Map}register(e,t){for(let n in t){let r=t[n];this.map.set(n,r),e.on(n,r)}}get(e){return this.map.get(e)}};function getDisplayRectangleDefault(){return[0,0,window.innerWidth,window.innerHeight]}var Editor=class{constructor({getDisplayRectangle:e=getDisplayRectangleDefault,fontName:t,fontSize:n,url:r,onExit:i,onClosed:a}){this.getDisplayRectangle=e,this.option=new Option({fontName:t,fontSize:n}),this.onExit=i,this.input=new Input(this),this.cursors=new Map,this.cursorOverlay=document.createElement(`div`),this.cursorOverlay.className=`lem-cursor`,this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.cursorOverlay.style.backgroundColor=`#ffffff`,this.cursorType=`box`,this.viewMap=new Map,this.jsonrpc=new JSONRPC(r,{onClosed:()=>{a()}}),this.messageTable=new MessageTable,this.messageTable.register(this.jsonrpc,{"update-foreground":this.updateForeground.bind(this),"update-background":this.updateBackground.bind(this),"make-view":this.makeView.bind(this),"delete-view":this.deleteView.bind(this),"resize-view":this.resize.bind(this),"move-view":this.move.bind(this),"redraw-view-after":this.redrawViewAfter.bind(this),clear:this.clear.bind(this),"clear-eol":this.clearEol.bind(this),"clear-eob":this.clearEob.bind(this),put:this.put.bind(this),"put-image":this.putImage.bind(this),"modeline-put":this.modelinePut.bind(this),"draw-block":this.drawBlock.bind(this),"modeline-draw-block":this.modelineDrawBlock.bind(this),"update-display":this.updateDisplay.bind(this),"move-cursor":this.moveCursor.bind(this),"change-view":this.changeView.bind(this),"resize-display":this.resizeDisplay.bind(this),bulk:this.bulk.bind(this),exit:this.exitEditor.bind(this),"get-clipboard-text":this.getClipboardText.bind(this),"set-clipboard-text":this.setClipboardText.bind(this),"js-eval":this.jsEval.bind(this),"set-font":this.setFont.bind(this),"get-font":this.getFont.bind(this),"get-display-size":this.getDisplaySize.bind(this),"load-css":this.loadCSS.bind(this),"update-cursor-shape":this.updateCursorShape.bind(this)}),this.login(),this.boundedHandleResize=this.handleResize.bind(this),this.focusHiddenInput=this.focusHiddenInput.bind(this)}init(){window.addEventListener(`resize`,this.boundedHandleResize),document.getElementsByTagName(`html`)[0].style[`background-color`]=`#333`,getLemEditorElement().appendChild(this.cursorOverlay)}finalize(){window.removeEventListener(`resize`,this.boundedHandleResize),this.input.finalize(),this.cursorOverlay.parentNode&&this.cursorOverlay.parentNode.removeChild(this.cursorOverlay)}closeConnection(){this.jsonrpc.close()}emitInput(e){let t=convertKeyEvent(e);if(t){if(t.key===`]`&&t.ctrl&&!t.meta&&!t.super&&!t.shift){this.jsonrpc.notify(`input`,{kind:`abort`});return}t.key!==`Unidentified`&&this.jsonrpc.notify(`input`,{kind:`key`,value:t})}}emitInputString(e){e?this.jsonrpc.notify(`input`,{kind:`input-string`,value:e}):console.error(`unexpected argument`,e)}redrawParams(){return{size:this.getDisplaySize(),fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent}}handleResize(e){this.jsonrpc.notify(`redraw`,this.redrawParams())}focusHiddenInput(){let e=this.input?.input;if(e){try{window.focus()}catch{}requestAnimationFrame(()=>{setTimeout(()=>{e.focus({preventScroll:!0})},0)})}}sendNotification(e,t){this.jsonrpc.notify(e,t)}request(e,t,n){this.jsonrpc.request(e,t,n)}getDisplaySize(){let[e,t,n,r]=this.getDisplayRectangle();return{width:Math.floor(n/this.option.fontWidth),height:Math.floor(r/this.option.fontHeight)}}callMessage(e,t){this.messageTable.get(e)(t)}findViewById(e){return this.viewMap.get(e)}login(){this.jsonrpc.request(`login`,{size:this.getDisplaySize(),foreground:this.option.foreground,background:this.option.background,fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent},e=>{if(this.updateForeground(e.foreground),this.updateBackground(e.background),e.views)for(let t of e.views)this.makeView(t);this.jsonrpc.notify(`redraw`,this.redrawParams())})}updateForeground(e){e!=null&&(this.option.foreground=e,this.input.updateForeground(e))}updateBackground(e){if(e==null)return;this.option.background=e,this.input.updateBackground(e);let t=getLemEditorElement();t.style.backgroundColor=e}makeView({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,use_modeline:l,kind:u,type:d,content:f,border:p,border_shape:m}){let h=new View({option:this.option,id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,editor:this});this.viewMap.set(e,h)}deleteView({viewInfo:{id:e}}){this.findViewById(e).delete(),this.viewMap.delete(e)}resize({viewInfo:{id:e},width:t,height:n,pixelWidth:r,pixelHeight:i}){let a=this.findViewById(e);a?a.resize(t,n,r,i):console.warn(`resize: view not found for id ${e}`)}move({viewInfo:{id:e},x:t,y:n,pixelX:r,pixelY:i}){let a=this.findViewById(e);a?a.move(t,n,r,i):console.warn(`move: view not found for id ${e}`)}redrawViewAfter({viewInfo:{id:e},isActive:t}){this.findViewById(e).touch(t)}clear({viewInfo:{id:e}}){this.findViewById(e).clear()}clearEol({viewInfo:{id:e},x:t,y:n,height:r}){this.findViewById(e).clearEol(t,n,r)}clearEob({viewInfo:{id:e},x:t,y:n}){this.findViewById(e).clearEob(t,n)}put({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,font:o}){this.findViewById(e).print(t,n,r,i,a,o)}drawBlock({viewInfo:{id:e},x:t,y:n,width:r,height:i,color:a}){this.findViewById(e).drawBlock(t,n,r,i,a)}modelineDrawBlock({viewInfo:{id:e},x:t,y:n,width:r,height:i,color:a}){this.findViewById(e).drawBlockOnModeline(t,n,r,i,a)}putImage({viewInfo:{id:e},x:t,y:n,pixelWidth:r,pixelHeight:i,clipWidth:a,clipHeight:o,url:s}){this.findViewById(e).printImage(t,n,r,i,a,o,s)}modelinePut({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a}){this.findViewById(e).printToModeline(t,n,r,i,a)}updateDisplay(){}moveCursor({viewInfo:{id:e},x:t,y:n,color:r,cursorText:i,cursorForeground:a}){let o=this.findViewById(e),[s,c]=this.getDisplayRectangle(),l=o.pixelX+t,u=o.pixelY+n;this.input.move(l,u);let d=r||this.option.foreground,f=a||this.option.background,p=this.cursorOverlay;switch(this.cursorType){case`bar`:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=`2px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;case`underline`:p.style.left=s+l+`px`,p.style.top=c+u+this.option.fontHeight-2+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=`2px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;default:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.style.font=this.option.font,p.style.paddingTop=textOffsetY+`px`,p.textContent=i||``,p.style.color=f;break}p.style.animation=`none`,p.offsetHeight,p.style.animation=``}updateCursorShape({cursorType:e}){this.cursorType=e||`box`}changeView({viewInfo:{id:e},type:t,content:n}){let r=this.findViewById(e);switch(t){case`html`:r.changeToHTMLContent(n);break;case`editor`:r.changeToEditorContent();break}}resizeDisplay({width:e,height:t}){let n=getLemEditorElement();n.style.width=Math.floor(e*this.option.fontWidth)+`px`,n.style.height=Math.floor(t*this.option.fontHeight)+`px`}bulk(e){for(let{method:t,argument:n}of e)this.callMessage(t,n)}exitEditor(){this.onExit&&this.onExit()}getClipboardText(){navigator.clipboard?.readText().then(e=>{this.jsonrpc.notify(`got-clipboard-text`,{text:e})})}setClipboardText({text:e}){navigator.clipboard&&navigator.clipboard.writeText(e)}jsEval({viewInfo:{id:e},code:t}){let n=this.findViewById(e).evalIn(t);return n&&n.toString()}setFont({fontName:e,fontSize:t}){this.option.setFont(e||this.option.fontName,t||this.option.fontSize),this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.jsonrpc.notify(`redraw`,this.redrawParams())}getFont(){return{name:this.option.fontName,size:this.option.fontSize}}loadCSS({content:e}){let t=document.createElement(`style`);t.textContent=e,document.head.appendChild(t)}notifyToServer(e,t){this.jsonrpc.notify(`invoke`,{method:e,args:t})}},canvas=document.querySelector(`#editor`);async function main(){await Promise.all([document.fonts.load(`19px file-icons`),document.fonts.load(`19px AllTheIcons`),document.fonts.load(`19px fontawesome`),document.fonts.load(`19px material-design-icons`),document.fonts.load(`19px octicons`)]),await document.fonts.ready;let e=new Editor({canvas,fontName:`Monospace`,fontSize:18,url:`${window.location.protocol===`https:`?`wss`:`ws`}://${window.location.hostname}:${window.location.port}`,onExit:null,onClosed:null});window.addEventListener(`message`,t=>{t.data.type===`invoke-lem`&&e.notifyToServer(t.data.method,t.data.args)}),e.init()}main(); \ No newline at end of file +var __defProp=Object.defineProperty,__commonJSMin=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),__exportAll=(e,t)=>{let n={};for(var r in e)__defProp(n,r,{get:e[r],enumerable:!0});return t||__defProp(n,Symbol.toStringTag,{value:`Module`}),n};(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var require_models=__commonJSMin((e=>{var t=e&&e.__extends||(function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};return function(t,n){if(typeof n!=`function`&&n!==null)throw TypeError(`Class extends value `+String(n)+` is not a constructor or null`);e(t,n);function r(){this.constructor=t}t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}})();Object.defineProperty(e,"__esModule",{value:!0}),e.createJSONRPCNotification=e.createJSONRPCRequest=e.createJSONRPCSuccessResponse=e.createJSONRPCErrorResponse=e.JSONRPCErrorCode=e.JSONRPCErrorException=e.isJSONRPCResponses=e.isJSONRPCResponse=e.isJSONRPCRequests=e.isJSONRPCRequest=e.isJSONRPCID=e.JSONRPC=void 0,e.JSONRPC=`2.0`,e.isJSONRPCID=function(e){return typeof e==`string`||typeof e==`number`||e===null},e.isJSONRPCRequest=function(t){return t.jsonrpc===e.JSONRPC&&t.method!==void 0&&t.result===void 0&&t.error===void 0},e.isJSONRPCRequests=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCRequest)},e.isJSONRPCResponse=function(t){return t.jsonrpc===e.JSONRPC&&t.id!==void 0&&(t.result!==void 0||t.error!==void 0)},e.isJSONRPCResponses=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCResponse)};var n=function(e,t,n){var r={code:e,message:t};return n!=null&&(r.data=n),r};e.JSONRPCErrorException=function(e){t(r,e);function r(t,n,i){var a=e.call(this,t)||this;return Object.setPrototypeOf(a,r.prototype),a.code=n,a.data=i,a}return r.prototype.toObject=function(){return n(this.code,this.message,this.data)},r}(Error),(function(e){e[e.ParseError=-32700]=`ParseError`,e[e.InvalidRequest=-32600]=`InvalidRequest`,e[e.MethodNotFound=-32601]=`MethodNotFound`,e[e.InvalidParams=-32602]=`InvalidParams`,e[e.InternalError=-32603]=`InternalError`})(e.JSONRPCErrorCode||={}),e.createJSONRPCErrorResponse=function(t,r,i,a){return{jsonrpc:e.JSONRPC,id:t,error:n(r,i,a)}},e.createJSONRPCSuccessResponse=function(t,n){return{jsonrpc:e.JSONRPC,id:t,result:n??null}},e.createJSONRPCRequest=function(t,n,r){return{jsonrpc:e.JSONRPC,id:t,method:n,params:r}},e.createJSONRPCNotification=function(t,n){return{jsonrpc:e.JSONRPC,method:t,params:n}}})),require_internal=__commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.DefaultErrorCode=void 0,e.DefaultErrorCode=0})),require_client=__commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{Object.defineProperty(e,"__esModule",{value:!0})})),require_server=__commonJSMin((e=>{var t=e&&e.__assign||function(){return t=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__createBinding||(Object.create?(function(e,t,n,r){r===void 0&&(r=n);var i=Object.getOwnPropertyDescriptor(t,n);(!i||(`get`in i?!t.__esModule:i.writable||i.configurable))&&(i={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,i)}):(function(e,t,n,r){r===void 0&&(r=n),e[r]=t[n]})),n=e&&e.__exportStar||function(e,n){for(var r in e)r!=="default"&&!Object.prototype.hasOwnProperty.call(n,r)&&t(n,e,r)};Object.defineProperty(e,"__esModule",{value:!0}),n(require_client(),e),n(require_interfaces(),e),n(require_models(),e),n(require_server(),e),n(require_server_and_client(),e)})),import_dist=require_dist(),JSONRPC=class{constructor(e,{onConnected:t,onClosed:n}){this.url=e,this.onConnected=t,this.onClosed=n,this.messageQueue=[],this.serverAndClient=null,this.connect(),this.connectionEstablished=!1,this.timerId=null,this.closed=!1}close(){this.timerId&&clearTimeout(this.timerId),this.webSocket.close(),this.closed=!0}on(e,t){this.serverAndClient.addMethod(e,t)}async requestInternal(e,t,n){let r=await this.serverAndClient.request(e,t);n&&n(r)}requestMessageQueue(){this.messageQueue.forEach(e=>{let[t,n,r]=e;this.requestInternal(t,n,r)}),this.messageQueue=[]}request(e,t,n){this.webSocket.readyState===WebSocket.OPEN?this.requestInternal(e,t,n):this.messageQueue.push([e,t,n])}notify(e,t){switch(this.webSocket.readyState){case WebSocket.OPEN:this.serverAndClient.notify(e,t);break;case WebSocket.CLOSED:break}}connect(e){this.closed||(console.log(`connect`,this.url),this.webSocket=new WebSocket(this.url),this.serverAndClient||=new import_dist.JSONRPCServerAndClient(new import_dist.JSONRPCServer,new import_dist.JSONRPCClient(e=>{try{return this.webSocket.send(JSON.stringify(e)),Promise.resolve()}catch(e){return Promise.reject(e)}})),this.webSocket.onmessage=e=>{this.serverAndClient.receiveAndSend(JSON.parse(e.data.toString()))},this.webSocket.onopen=()=>{console.log(`WebSocket connection established`),this.connectionEstablished=!0,this.onConnected&&this.onConnected(),this.requestMessageQueue()},this.webSocket.onclose=e=>{console.error(`WebScoket closed`,e),this.serverAndClient.rejectAllPendingRequests(`Connection is closed (${e.reason}).`),this.connectionEstablished&&this.onClosed(),this.timerId=setTimeout(()=>{this.connect()},3e3)},this.webSocket.onerror=e=>{console.error(`WebSocket error:`,e),this.webSocket.close()})}},keyevent_exports=__exportAll({convertKeyEvent:()=>convertKeyEvent}),modifierKeys=[`Shift`,`Control`,`Alt`,`Meta`,`CapsLock`],convertKeyTable={Enter:`Return`,ArrowRight:`Right`,ArrowLeft:`Left`,ArrowUp:`Up`,ArrowDown:`Down`,"¡":`1`,"™":`2`,"£":`3`,"¢":`4`,"∞":`5`,"§":`6`,"¶":`7`,"•":`8`,ª:`9`,º:`0`,"–":`-`,"≠":`=`,"“":`[`,"‘":`]`,"«":`\\`,"…":`;`,æ:`'`,"≤":`,`,"≥":`.`,"÷":`/`,"⁄":`!`,"€":`@`,"‹":`#`,"›":`$`,fi:`%`,fl:`^`,"‡":`&`,"°":`*`,"·":`(`,"‚":`)`,"—":`_`,"±":`+`,"”":`{`,"’":`}`,"»":`|`,Ú:`:`,Æ:`"`,"¯":`<`,"˘":`>`,"¿":`?`,œ:`q`,"∑":`w`,"´":`e`,"®":`r`,"†":`t`,"¥":`y`,"¨":`u`,ˆ:`i`,ø:`o`,π:`p`,å:`a`,ß:`s`,"∂":`d`,ƒ:`f`,"©":`g`,"˙":`h`,"∆":`j`,"˚":`k`,"¬":`l`,Ω:`z`,"≈":`x`,ç:`c`,"√":`v`,"∫":`b`,"˜":`n`,µ:`m`,Œ:`Q`,"„":`W`,"´":`E`,"‰":`R`,ˇ:`T`,Á:`Y`,"¨":`U`,ˆ:`I`,Ø:`O`,"∏":`P`,Å:`A`,Í:`S`,Î:`D`,Ï:`F`,"˝":`G`,Ó:`H`,Ô:`J`,"":`K`,Ò:`L`,"¸":`Z`,"˛":`X`,Ç:`C`,"◊":`V`,ı:`B`,"˜":`N`,Â:`M`};function getKey(e){return e.altKey?convertKeyTable[e.key]||(e.code.startsWith(`Key`)?e.code[3].toLowerCase():null)||e.key:convertKeyTable[e.key]||e.key}function convertKeyEvent(e){return modifierKeys.indexOf(e.key)===-1?{key:getKey(e),ctrl:e.ctrlKey,meta:e.altKey,super:e.metaKey,shift:e.shiftKey}:null}var lib_exports=__exportAll({computeWidth:()=>computeWidth,eawVersion:()=>version,getEAW:()=>getEAW}),defs=[[0,31,`N`],[32,126,`Na`],[127,160,`N`],[161,161,`A`],[162,163,`Na`],[164,164,`A`],[165,166,`Na`],[167,168,`A`],[169,169,`N`],[170,170,`A`],[171,171,`N`],[172,172,`Na`],[173,174,`A`],[175,175,`Na`],[176,180,`A`],[181,181,`N`],[182,186,`A`],[187,187,`N`],[188,191,`A`],[192,197,`N`],[198,198,`A`],[199,207,`N`],[208,208,`A`],[209,214,`N`],[215,216,`A`],[217,221,`N`],[222,225,`A`],[226,229,`N`],[230,230,`A`],[231,231,`N`],[232,234,`A`],[235,235,`N`],[236,237,`A`],[238,239,`N`],[240,240,`A`],[241,241,`N`],[242,243,`A`],[244,246,`N`],[247,250,`A`],[251,251,`N`],[252,252,`A`],[253,253,`N`],[254,254,`A`],[255,256,`N`],[257,257,`A`],[258,272,`N`],[273,273,`A`],[274,274,`N`],[275,275,`A`],[276,282,`N`],[283,283,`A`],[284,293,`N`],[294,295,`A`],[296,298,`N`],[299,299,`A`],[300,304,`N`],[305,307,`A`],[308,311,`N`],[312,312,`A`],[313,318,`N`],[319,322,`A`],[323,323,`N`],[324,324,`A`],[325,327,`N`],[328,331,`A`],[332,332,`N`],[333,333,`A`],[334,337,`N`],[338,339,`A`],[340,357,`N`],[358,359,`A`],[360,362,`N`],[363,363,`A`],[364,461,`N`],[462,462,`A`],[463,463,`N`],[464,464,`A`],[465,465,`N`],[466,466,`A`],[467,467,`N`],[468,468,`A`],[469,469,`N`],[470,470,`A`],[471,471,`N`],[472,472,`A`],[473,473,`N`],[474,474,`A`],[475,475,`N`],[476,476,`A`],[477,592,`N`],[593,593,`A`],[594,608,`N`],[609,609,`A`],[610,707,`N`],[708,708,`A`],[709,710,`N`],[711,711,`A`],[712,712,`N`],[713,715,`A`],[716,716,`N`],[717,717,`A`],[718,719,`N`],[720,720,`A`],[721,727,`N`],[728,731,`A`],[732,732,`N`],[733,733,`A`],[734,734,`N`],[735,735,`A`],[736,767,`N`],[768,879,`A`],[880,912,`N`],[913,929,`A`],[930,930,`N`],[931,937,`A`],[938,944,`N`],[945,961,`A`],[962,962,`N`],[963,969,`A`],[970,1024,`N`],[1025,1025,`A`],[1026,1039,`N`],[1040,1103,`A`],[1104,1104,`N`],[1105,1105,`A`],[1106,4351,`N`],[4352,4447,`W`],[4448,8207,`N`],[8208,8208,`A`],[8209,8210,`N`],[8211,8214,`A`],[8215,8215,`N`],[8216,8217,`A`],[8218,8219,`N`],[8220,8221,`A`],[8222,8223,`N`],[8224,8226,`A`],[8227,8227,`N`],[8228,8231,`A`],[8232,8239,`N`],[8240,8240,`A`],[8241,8241,`N`],[8242,8243,`A`],[8244,8244,`N`],[8245,8245,`A`],[8246,8250,`N`],[8251,8251,`A`],[8252,8253,`N`],[8254,8254,`A`],[8255,8307,`N`],[8308,8308,`A`],[8309,8318,`N`],[8319,8319,`A`],[8320,8320,`N`],[8321,8324,`A`],[8325,8360,`N`],[8361,8361,`H`],[8362,8363,`N`],[8364,8364,`A`],[8365,8450,`N`],[8451,8451,`A`],[8452,8452,`N`],[8453,8453,`A`],[8454,8456,`N`],[8457,8457,`A`],[8458,8466,`N`],[8467,8467,`A`],[8468,8469,`N`],[8470,8470,`A`],[8471,8480,`N`],[8481,8482,`A`],[8483,8485,`N`],[8486,8486,`A`],[8487,8490,`N`],[8491,8491,`A`],[8492,8530,`N`],[8531,8532,`A`],[8533,8538,`N`],[8539,8542,`A`],[8543,8543,`N`],[8544,8555,`A`],[8556,8559,`N`],[8560,8569,`A`],[8570,8584,`N`],[8585,8585,`A`],[8586,8591,`N`],[8592,8601,`A`],[8602,8631,`N`],[8632,8633,`A`],[8634,8657,`N`],[8658,8658,`A`],[8659,8659,`N`],[8660,8660,`A`],[8661,8678,`N`],[8679,8679,`A`],[8680,8703,`N`],[8704,8704,`A`],[8705,8705,`N`],[8706,8707,`A`],[8708,8710,`N`],[8711,8712,`A`],[8713,8714,`N`],[8715,8715,`A`],[8716,8718,`N`],[8719,8719,`A`],[8720,8720,`N`],[8721,8721,`A`],[8722,8724,`N`],[8725,8725,`A`],[8726,8729,`N`],[8730,8730,`A`],[8731,8732,`N`],[8733,8736,`A`],[8737,8738,`N`],[8739,8739,`A`],[8740,8740,`N`],[8741,8741,`A`],[8742,8742,`N`],[8743,8748,`A`],[8749,8749,`N`],[8750,8750,`A`],[8751,8755,`N`],[8756,8759,`A`],[8760,8763,`N`],[8764,8765,`A`],[8766,8775,`N`],[8776,8776,`A`],[8777,8779,`N`],[8780,8780,`A`],[8781,8785,`N`],[8786,8786,`A`],[8787,8799,`N`],[8800,8801,`A`],[8802,8803,`N`],[8804,8807,`A`],[8808,8809,`N`],[8810,8811,`A`],[8812,8813,`N`],[8814,8815,`A`],[8816,8833,`N`],[8834,8835,`A`],[8836,8837,`N`],[8838,8839,`A`],[8840,8852,`N`],[8853,8853,`A`],[8854,8856,`N`],[8857,8857,`A`],[8858,8868,`N`],[8869,8869,`A`],[8870,8894,`N`],[8895,8895,`A`],[8896,8977,`N`],[8978,8978,`A`],[8979,8985,`N`],[8986,8987,`W`],[8988,9e3,`N`],[9001,9002,`W`],[9003,9192,`N`],[9193,9196,`W`],[9197,9199,`N`],[9200,9200,`W`],[9201,9202,`N`],[9203,9203,`W`],[9204,9311,`N`],[9312,9449,`A`],[9450,9450,`N`],[9451,9547,`A`],[9548,9551,`N`],[9552,9587,`A`],[9588,9599,`N`],[9600,9615,`A`],[9616,9617,`N`],[9618,9621,`A`],[9622,9631,`N`],[9632,9633,`A`],[9634,9634,`N`],[9635,9641,`A`],[9642,9649,`N`],[9650,9651,`A`],[9652,9653,`N`],[9654,9655,`A`],[9656,9659,`N`],[9660,9661,`A`],[9662,9663,`N`],[9664,9665,`A`],[9666,9669,`N`],[9670,9672,`A`],[9673,9674,`N`],[9675,9675,`A`],[9676,9677,`N`],[9678,9681,`A`],[9682,9697,`N`],[9698,9701,`A`],[9702,9710,`N`],[9711,9711,`A`],[9712,9724,`N`],[9725,9726,`W`],[9727,9732,`N`],[9733,9734,`A`],[9735,9736,`N`],[9737,9737,`A`],[9738,9741,`N`],[9742,9743,`A`],[9744,9747,`N`],[9748,9749,`W`],[9750,9755,`N`],[9756,9756,`A`],[9757,9757,`N`],[9758,9758,`A`],[9759,9791,`N`],[9792,9792,`A`],[9793,9793,`N`],[9794,9794,`A`],[9795,9799,`N`],[9800,9811,`W`],[9812,9823,`N`],[9824,9825,`A`],[9826,9826,`N`],[9827,9829,`A`],[9830,9830,`N`],[9831,9834,`A`],[9835,9835,`N`],[9836,9837,`A`],[9838,9838,`N`],[9839,9839,`A`],[9840,9854,`N`],[9855,9855,`W`],[9856,9874,`N`],[9875,9875,`W`],[9876,9885,`N`],[9886,9887,`A`],[9888,9888,`N`],[9889,9889,`W`],[9890,9897,`N`],[9898,9899,`W`],[9900,9916,`N`],[9917,9918,`W`],[9919,9919,`A`],[9920,9923,`N`],[9924,9925,`W`],[9926,9933,`A`],[9934,9934,`W`],[9935,9939,`A`],[9940,9940,`W`],[9941,9953,`A`],[9954,9954,`N`],[9955,9955,`A`],[9956,9959,`N`],[9960,9961,`A`],[9962,9962,`W`],[9963,9969,`A`],[9970,9971,`W`],[9972,9972,`A`],[9973,9973,`W`],[9974,9977,`A`],[9978,9978,`W`],[9979,9980,`A`],[9981,9981,`W`],[9982,9983,`A`],[9984,9988,`N`],[9989,9989,`W`],[9990,9993,`N`],[9994,9995,`W`],[9996,10023,`N`],[10024,10024,`W`],[10025,10044,`N`],[10045,10045,`A`],[10046,10059,`N`],[10060,10060,`W`],[10061,10061,`N`],[10062,10062,`W`],[10063,10066,`N`],[10067,10069,`W`],[10070,10070,`N`],[10071,10071,`W`],[10072,10101,`N`],[10102,10111,`A`],[10112,10132,`N`],[10133,10135,`W`],[10136,10159,`N`],[10160,10160,`W`],[10161,10174,`N`],[10175,10175,`W`],[10176,10213,`N`],[10214,10221,`Na`],[10222,10628,`N`],[10629,10630,`Na`],[10631,11034,`N`],[11035,11036,`W`],[11037,11087,`N`],[11088,11088,`W`],[11089,11092,`N`],[11093,11093,`W`],[11094,11097,`A`],[11098,11903,`N`],[11904,11929,`W`],[11930,11930,`N`],[11931,12019,`W`],[12020,12031,`N`],[12032,12245,`W`],[12246,12271,`N`],[12272,12287,`W`],[12288,12288,`F`],[12289,12350,`W`],[12351,12352,`N`],[12353,12438,`W`],[12439,12440,`N`],[12441,12543,`W`],[12544,12548,`N`],[12549,12591,`W`],[12592,12592,`N`],[12593,12686,`W`],[12687,12687,`N`],[12688,12771,`W`],[12772,12782,`N`],[12783,12830,`W`],[12831,12831,`N`],[12832,12871,`W`],[12872,12879,`A`],[12880,19903,`W`],[19904,19967,`N`],[19968,42124,`W`],[42125,42127,`N`],[42128,42182,`W`],[42183,43359,`N`],[43360,43388,`W`],[43389,44031,`N`],[44032,55203,`W`],[55204,57343,`N`],[57344,63743,`A`],[63744,64255,`W`],[64256,65023,`N`],[65024,65039,`A`],[65040,65049,`W`],[65050,65071,`N`],[65072,65106,`W`],[65107,65107,`N`],[65108,65126,`W`],[65127,65127,`N`],[65128,65131,`W`],[65132,65280,`N`],[65281,65376,`F`],[65377,65470,`H`],[65471,65473,`N`],[65474,65479,`H`],[65480,65481,`N`],[65482,65487,`H`],[65488,65489,`N`],[65490,65495,`H`],[65496,65497,`N`],[65498,65500,`H`],[65501,65503,`N`],[65504,65510,`F`],[65511,65511,`N`],[65512,65518,`H`],[65519,65532,`N`],[65533,65533,`A`],[65534,94175,`N`],[94176,94180,`W`],[94181,94191,`N`],[94192,94193,`W`],[94194,94207,`N`],[94208,100343,`W`],[100344,100351,`N`],[100352,101589,`W`],[101590,101631,`N`],[101632,101640,`W`],[101641,110575,`N`],[110576,110579,`W`],[110580,110580,`N`],[110581,110587,`W`],[110588,110588,`N`],[110589,110590,`W`],[110591,110591,`N`],[110592,110882,`W`],[110883,110897,`N`],[110898,110898,`W`],[110899,110927,`N`],[110928,110930,`W`],[110931,110932,`N`],[110933,110933,`W`],[110934,110947,`N`],[110948,110951,`W`],[110952,110959,`N`],[110960,111355,`W`],[111356,126979,`N`],[126980,126980,`W`],[126981,127182,`N`],[127183,127183,`W`],[127184,127231,`N`],[127232,127242,`A`],[127243,127247,`N`],[127248,127277,`A`],[127278,127279,`N`],[127280,127337,`A`],[127338,127343,`N`],[127344,127373,`A`],[127374,127374,`W`],[127375,127376,`A`],[127377,127386,`W`],[127387,127404,`A`],[127405,127487,`N`],[127488,127490,`W`],[127491,127503,`N`],[127504,127547,`W`],[127548,127551,`N`],[127552,127560,`W`],[127561,127567,`N`],[127568,127569,`W`],[127570,127583,`N`],[127584,127589,`W`],[127590,127743,`N`],[127744,127776,`W`],[127777,127788,`N`],[127789,127797,`W`],[127798,127798,`N`],[127799,127868,`W`],[127869,127869,`N`],[127870,127891,`W`],[127892,127903,`N`],[127904,127946,`W`],[127947,127950,`N`],[127951,127955,`W`],[127956,127967,`N`],[127968,127984,`W`],[127985,127987,`N`],[127988,127988,`W`],[127989,127991,`N`],[127992,128062,`W`],[128063,128063,`N`],[128064,128064,`W`],[128065,128065,`N`],[128066,128252,`W`],[128253,128254,`N`],[128255,128317,`W`],[128318,128330,`N`],[128331,128334,`W`],[128335,128335,`N`],[128336,128359,`W`],[128360,128377,`N`],[128378,128378,`W`],[128379,128404,`N`],[128405,128406,`W`],[128407,128419,`N`],[128420,128420,`W`],[128421,128506,`N`],[128507,128591,`W`],[128592,128639,`N`],[128640,128709,`W`],[128710,128715,`N`],[128716,128716,`W`],[128717,128719,`N`],[128720,128722,`W`],[128723,128724,`N`],[128725,128727,`W`],[128728,128731,`N`],[128732,128735,`W`],[128736,128746,`N`],[128747,128748,`W`],[128749,128755,`N`],[128756,128764,`W`],[128765,128991,`N`],[128992,129003,`W`],[129004,129007,`N`],[129008,129008,`W`],[129009,129291,`N`],[129292,129338,`W`],[129339,129339,`N`],[129340,129349,`W`],[129350,129350,`N`],[129351,129535,`W`],[129536,129647,`N`],[129648,129660,`W`],[129661,129663,`N`],[129664,129672,`W`],[129673,129679,`N`],[129680,129725,`W`],[129726,129726,`N`],[129727,129733,`W`],[129734,129741,`N`],[129742,129755,`W`],[129756,129759,`N`],[129760,129768,`W`],[129769,129775,`N`],[129776,129784,`W`],[129785,131071,`N`],[131072,196605,`W`],[196606,196607,`N`],[196608,262141,`W`],[262142,917759,`N`],[917760,917999,`A`],[918e3,983039,`N`],[983040,1048573,`A`],[1048574,1048575,`N`],[1048576,1114109,`A`],[1114110,1114111,`N`]],version=`15.1.0`;function getEAWOfCodePoint(e){let t=0,n=defs.length-1;for(;t!==n;){let r=t+(n-t>>1),[i,a,o]=defs[r];if(ea)t=r+1;else return o}return defs[t][2]}function getEAW(e,t=0){let n=e.codePointAt(t);if(n!==void 0)return getEAWOfCodePoint(n)}var defaultWidths={N:1,Na:1,W:2,F:2,H:1,A:1};function computeWidth(e,t){let n=0;for(let r of e){let e=getEAW(r);n+=t&&t[e]||defaultWidths[e]}return n}var textOffsetY=5,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function isWideChar(e){switch(getEAW(e)){case`F`:case`W`:return!0;default:return!1}}function isMacOS(){return window.navigator.userAgent.indexOf(`Mac OS X`)!==-1}function computeFontSize(e){let t=document.createElement(`canvas`).getContext(`2d`);t.font=e;let n=t.measureText(`W`);return[Math.floor(n.width),Math.round(n.fontBoundingBoxAscent+textOffsetY+(n.emHeightDescent||0)),Math.round(n.fontBoundingBoxAscent+textOffsetY)]}function drawBlock({ctx:e,x:t,y:n,width:r,height:i,style:a}){e.fillStyle=a,e.fillRect(t,n,r,i)}function drawText({ctx:e,x:t,y:n,text:r,font:i,style:a,option:o}){n+=Math.round(textOffsetY),e.fillStyle=a,e.font=i,e.textBaseline=`top`;for(let i of r)isWideChar(i)?(e.fillText(i,t,n,o.fontWidth*2),t+=o.fontWidth*2):(e.fillText(i,t,n,o.fontWidth),t+=o.fontWidth)}function drawHorizontalLine({ctx:e,x:t,y:n,width:r,style:i,lineWidth:a=1}){e.strokeStyle=i,e.lineWidth=a,e.setLineDash=[],e.beginPath(),e.moveTo(t,n),e.lineTo(t+r,n),e.stroke()}var Option=class{constructor({fontName:e,fontSize:t}){this.setFont(e,t),this.foreground=`#cccccc`,this.background=`#2d2d2d`}setFont(e,t){let n=t+`px `+e,[r,i,a]=computeFontSize(n);this.fontName=e,this.fontSize=t,this.fontWidth=r,this.fontHeight=i,this.fontAscent=a,this.font=n}};function getLemEditorElement(){return document.getElementById(`lem-editor`)}function normalizeWheelDelta(e,t,n,r){switch(n){case 0:return{dx:e/r,dy:t/r};case 2:return{dx:e*20,dy:t*20};default:return{dx:e,dy:t}}}function extractWholeLines(e,t){let n=Math.trunc(e),r=Math.trunc(t);return{scrollX:n,scrollY:r,remainderX:e-n,remainderY:t-r}}function cursorPosition(e,t){let[n,r]=t.getDisplayRectangle(),i=e.clientX-n,a=e.clientY-r;return{pixelX:i,pixelY:a,x:Math.floor(i/t.option.fontWidth),y:Math.floor(a/t.option.fontHeight)}}function makeWheelHandler(e){let t={x:0,y:0},n=!1,r={pixelX:0,pixelY:0,x:0,y:0};return i=>{i.preventDefault(),r=cursorPosition(i,e);let{dx:a,dy:o}=normalizeWheelDelta(i.deltaX,i.deltaY,i.deltaMode,e.option.fontHeight);t={x:t.x+a,y:t.y+o},n||(n=!0,requestAnimationFrame(()=>{n=!1;let{scrollX:i,scrollY:a,remainderX:o,remainderY:s}=extractWholeLines(t.x,t.y);t={x:o,y:s},(i!==0||a!==0)&&e.jsonrpc.notify(`input`,{kind:`wheel`,value:{...r,wheelX:-i,wheelY:-a}})}))}}function addMouseEventListeners({dom:e,editor:t,isDraggable:n,draggableStyle:r}){e.addEventListener(`contextmenu`,e=>{e.preventDefault()});let i=(e,n)=>{e.preventDefault();let[r,i]=t.getDisplayRectangle(),a=e.clientX-r,o=e.clientY-i,s=Math.floor(a/t.option.fontWidth),c=Math.floor(o/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:n,value:{x:s,y:c,pixelX:a,pixelY:o,button:e.button,clicks:e.detail}})};e.addEventListener(`mousedown`,e=>{n&&(document.body.style.cursor=r),t.focusHiddenInput(),i(e,`mousedown`)}),e.addEventListener(`mouseup`,e=>{n&&(document.body.style.cursor=`default`),i(e,`mouseup`)});let a=0;e.addEventListener(`mousemove`,e=>{e.preventDefault();let n=Date.now();if(n-a>50){a=n;let[r,i]=t.getDisplayRectangle(),o=e.clientX-r,s=e.clientY-i,c=Math.floor(o/t.option.fontWidth),l=Math.floor(s/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:`mousemove`,value:{x:c,y:l,pixelX:o,pixelY:s,button:e.buttons===0?null:e.buttons-1}})}}),n&&(e.addEventListener(`mouseover`,()=>{document.body.style.cursor=r}),e.addEventListener(`mouseout`,e=>{e.buttons!==1&&(document.body.style.cursor=`default`)})),e.addEventListener(`wheel`,makeWheelHandler(t))}var zIndexTable={"floating-window":200,modeline:100,"vertical-border":100,"horizontal-border":101};function zindex(e){return zIndexTable[e]||0}var borderOffsetX=5,borderOffsetY=10,BaseSurface=class{constructor({editor:e}){this.editor=e,this.mainDOM=null,this.wrapper=null}delete(){this.wrapper?getLemEditorElement().removeChild(this.wrapper):getLemEditorElement().removeChild(this.mainDOM)}setupDOM({dom:e,isFloating:t,border:n,cssClassName:r}){this.mainDOM=e,t&&n?(this.wrapper=document.createElement(`div`),r&&(this.wrapper.className=r),this.wrapper.style.position=`absolute`,this.wrapper.style.backgroundColor=this.editor.option.background,this.wrapper.style.zIndex=zindex(`floating-window`),this.wrapper.appendChild(e),getLemEditorElement().appendChild(this.wrapper)):(r&&(e.className=r),getLemEditorElement().appendChild(e))}move(e,t){let[n,r]=this.editor.getDisplayRectangle(),i=Math.floor(n+e),a=Math.floor(r+t);this.wrapper?(this.wrapper.style.left=i-borderOffsetX+`px`,this.wrapper.style.top=a-borderOffsetY+`px`,this.mainDOM.style.left=borderOffsetX+`px`,this.mainDOM.style.top=borderOffsetY+`px`):(this.mainDOM.style.left=i+`px`,this.mainDOM.style.top=a+`px`)}_resize(e,t){let n=window.devicePixelRatio||1;this.mainDOM.width=e*n,this.mainDOM.height=t*n,this.mainDOM.style.width=e+`px`,this.mainDOM.style.height=t+`px`,this.wrapper&&(this.wrapper.style.width=e+borderOffsetX*2+`px`,this.wrapper.style.height=t+borderOffsetY*2+`px`)}drawBlock(e,t,n,r,i){}drawText(e,t,n,r,i,a,o,s){}drawImage(e,t,n,r,i,a,o){}clearImages(e,t){}clearAllImages(){}touch(){}evalIn(code){return eval(code)}},CanvasSurface=class extends BaseSurface{constructor({editor:e,view:t,pixelX:n,pixelY:r,pixelWidth:i,pixelHeight:a,styles:o,isFloating:s,border:c,cssClassName:l}){super({editor:e});let u=this.setupCanvas(o);this.setupDOM({dom:u,isFloating:s,border:c,cssClassName:l}),this.move(n,r),this.resize(i,a),this.drawingQueue=[],addMouseEventListeners({dom:u,editor:e})}setupCanvas(e){let t=document.createElement(`canvas`);if(t.style.position=`absolute`,e)for(let n in e)t.style[n]=e[n];return t}resize(e,t){this._resize(e,t);let n=window.devicePixelRatio||1;this.mainDOM.getContext(`2d`).scale(n,n)}move(e,t){if(super.move(e,t),this.imageEls)for(let[,e]of this.imageEls)this.positionImage(e)}delete(){this.clearAllImages(),super.delete()}drawBlock(e,t,n,r,i){this.drawingQueue.push(function(a){drawBlock({ctx:a,x:e,y:t,width:n,height:r,style:i})})}drawText(e,t,n,r,i,a,o,s){let c=this.editor.option,l=o??t,u=s??c.fontHeight;this.drawingQueue.push(function(o){if(a=a?`${c.fontSize}px ${a}`:c.font,!i)drawBlock({ctx:o,x:e,y:l,width:r,height:u,style:c.background}),drawText({ctx:o,x:e,y:t,text:n,style:c.foreground,font:a,option:c});else{let{foreground:s,background:d,bold:f,reverse:p,underline:m,cursor:h}=i;if(s||=c.foreground,d||=c.background,p){let e=d;d=s,s=e}h&&(d=c.background),drawBlock({ctx:o,x:e,y:l,width:r,height:u,style:d}),drawText({ctx:o,x:e,y:t,text:n,style:s,font:f?`bold `+a:a,option:c}),m&&drawHorizontalLine({ctx:o,x:e,y:t+c.fontHeight-2,width:r,style:typeof m==`string`?m:s,lineWidth:2})}})}imageBaseLeft(){return parseFloat(this.mainDOM.style.left)||0}imageBaseTop(){return parseFloat(this.mainDOM.style.top)||0}drawImage(e,t,n,r,i,a,o){this.imageEls||=new Map;let s=e+`,`+t,c=this.imageEls.get(s);if(c&&c.url!==o&&(c.el.remove(),this.imageEls.delete(s),c=null),!c){let e=document.createElement(`img`);e.style.position=`absolute`,e.style.pointerEvents=`none`,e.style.zIndex=`1`,e.src=o,this.mainDOM.parentNode.appendChild(e),c={el:e,url:o},this.imageEls.set(s,c)}c.x=e,c.y=t,c.width=n,c.height=r,c.clipWidth=i,c.clipHeight=a,this.positionImage(c)}positionImage(e){e.el.style.left=this.imageBaseLeft()+e.x+`px`,e.el.style.top=this.imageBaseTop()+e.y+`px`,e.el.style.width=e.width+`px`,e.el.style.height=e.height+`px`;let t=e.clipWidth==null?0:Math.max(0,e.width-e.clipWidth),n=e.clipHeight==null?0:Math.max(0,e.height-e.clipHeight);e.el.style.clipPath=t>0||n>0?`inset(0px ${t}px ${n}px 0px)`:``}clearImages(e,t){if(this.imageEls)for(let[n,r]of this.imageEls){let i=r.y+(r.height||0);r.ye&&(r.el.remove(),this.imageEls.delete(n))}}clearAllImages(){if(this.imageEls){for(let[,e]of this.imageEls)e.el.remove();this.imageEls.clear()}}touch(){let e=this.mainDOM.getContext(`2d`);for(let t of this.drawingQueue)t(e);this.drawingQueue=[]}activate(){this.mainDOM.dataset.store=`active`}deactivate(){this.mainDOM.dataset.store=`inactive`}},HTMLSurface=class extends BaseSurface{constructor({editor:e,pixelX:t,pixelY:n,pixelWidth:r,pixelHeight:i,styles:a,option:o,isFloating:s,border:c,html:l}){super({editor:e});let u=document.createElement(`iframe`);this.setupDOM({dom:u,isFloating:s,border:c}),u.style.position=`absolute`,u.style.backgroundColor=o.background,u.setAttribute(`sandbox`,`allow-scripts allow-same-origin`),u.srcdoc=l,u.addEventListener(`load`,()=>{let e=u.contentWindow;e.invokeLem=(e,t)=>parent.postMessage({type:`invoke-lem`,method:e,args:t})}),this.iframe=u,this.move(t,n),this.resize(r,i)}resize(e,t){this._resize(e,t)}update(e){let t=this.iframe.contentWindow.scrollY;this.iframe.srcdoc=e,this.iframe.onload=()=>{this.iframe.onload=null,this.iframe.contentWindow.scrollTo(0,t)}}evalIn(e){return this.iframe.contentWindow.eval(e)}},VerticalBorder=class{constructor({x:e,y:t,height:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__vertical-border`,this.line.style.height=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`vertical-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`col-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=Math.floor(n+e-this.option.fontWidth/2)+`px`,this.line.style.top=r+t+`px`}resize(e){this.line.style.height=e+`px`}},HorizontalBorder=class{constructor({x:e,y:t,width:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__horizontal-border`,this.line.style.width=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`horizontal-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`row-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=n+e+`px`,this.line.style.top=Math.floor(r+t-4)+`px`}resize(e){this.line.style.width=e+`px`}},viewStyles={header:()=>{},tile:()=>{},floating:e=>({boxSizing:`border-box`,borderColor:e.foreground,backgroundColor:e.background})};function getViewStyle(e,t){return viewStyles[e](t)||{}}var View=class{constructor({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,option:h,editor:g}){switch(this.option=h,this.id=e,this.x=t,this.y=n,this.width=r,this.height=i,this.pixelX=a,this.pixelY=o,this.pixelWidth=s,this.pixelHeight=c,this.useModeline=l,this.kind=u,this.type=d,this.border=p,this.borderShape=m,this.editor=g,this.bottomBar=null,this.leftsideBar=null,u){case`tile`:this.mainSurface=this.makeSurface(d,f),this.leftSideBar=new VerticalBorder({x:a,y:o,height:c+(l?h.fontHeight:0),option:h,editor:g}),l||(this.bottomBar=new HorizontalBorder({x:a,y:o+c-h.fontHeight,width:s,option:h,editor:g}));break;case`header`:this.mainSurface=this.makeSurface(d,f);break;case`floating`:this.mainSurface=this.makeSurface(d,f),m===`left-border`&&(this.leftSideBar=new VerticalBorder({x:a,y:o,height:c,option:h,editor:g}));break}this.modelineSurface=l?this.makeModelineSurface():null}delete(){this.mainSurface.delete(),this.modelineSurface&&this.modelineSurface.delete(),this.leftSideBar&&this.leftSideBar.delete(),this.bottomBar&&this.bottomBar.delete()}move(e,t,n,r){this.x=e,this.y=t,this.pixelX=n,this.pixelY=r,this.mainSurface.move(n,r),this.modelineSurface&&this.modelineSurface.move(n,r+this.pixelHeight),this.leftSideBar&&this.leftSideBar.move(n,r),this.bottomBar&&this.bottomBar.move(n,r+this.pixelHeight)}resize(e,t,n,r){this.width=e,this.height=t,this.pixelWidth=n,this.pixelHeight=r,this.mainSurface.resize(n,r),this.modelineSurface&&(this.modelineSurface.move(this.pixelX,this.pixelY+r),this.modelineSurface.resize(n,this.option.fontHeight)),this.leftSideBar&&this.leftSideBar.resize(r+(this.modelineSurface?this.option.fontHeight:0)),this.bottomBar&&this.bottomBar.resize(n)}clear(){this.mainSurface.drawBlock(0,0,this.pixelWidth,this.pixelHeight,this.option.background),this.mainSurface.clearImages(0,this.pixelHeight)}clearEol(e,t,n){n??=this.option.fontHeight,this.mainSurface.drawBlock(e,t,this.pixelWidth-e,n,this.option.background),this.mainSurface.clearImages(t,t+n)}clearEob(e,t){this.mainSurface.drawBlock(e,t,this.pixelWidth,this.pixelHeight-t,this.option.background),this.mainSurface.clearImages(t,this.pixelHeight)}print(e,t,n,r,i,a,o,s){this.mainSurface.drawText(e,t,n,r,i,a,o,s)}drawBlock(e,t,n,r,i){this.mainSurface.drawBlock(e,t,n,r,i||this.option.background)}drawBlockOnModeline(e,t,n,r,i){this.modelineSurface&&this.modelineSurface.drawBlock(e,t,n,r,i||this.option.background)}printImage(e,t,n,r,i,a,o){this.mainSurface.drawImage(e,t,n,r,i,a,o)}printToModeline(e,t,n,r,i,a,o){this.modelineSurface&&this.modelineSurface.drawText(e,t,n,r,i,null,a,o)}touch(e){this.mainSurface.touch(),this.modelineSurface&&(this.modelineSurface.touch(),e?this.modelineSurface.activate():this.modelineSurface.deactivate())}makeSurface(e,t){switch(e){case`html`:return this.makeHTMLSurface(t);case`editor`:return this.makeEditorSurface();default:console.error(`unknown type: ${e}`)}}makeHTMLSurface(e){return new HTMLSurface({editor:this.editor,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),option:this.option,isFloating:this.kind===`floating`,border:this.border,html:e})}makeEditorSurface(){let e=this.borderShape===`left-border`?0:this.border,t=this.kind===`floating`;return new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),editor:this.editor,border:e,isFloating:t,view:this,cssClassName:t&&e?`lem-editor__floating-window--bordered`:null})}makeModelineSurface(){let e=new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY+this.pixelHeight,pixelWidth:this.pixelWidth,pixelHeight:this.option.fontHeight,editor:this.editor,view:this,styles:{zIndex:zindex(`modeline`)},cssClassName:`lem-editor__mode-line`});return addMouseEventListeners({dom:e.mainDOM,editor:this.editor,isDraggable:!0,draggableStyle:`row-resize`}),e}changeToHTMLContent(e){this.mainSurface.constructor.name===`HTMLSurface`?this.mainSurface.update(e):(this.mainSurface.delete(),this.mainSurface=this.makeHTMLSurface(e))}changeToEditorContent(){this.mainSurface.delete(),this.mainSurface=this.makeEditorSurface()}evalIn(e){return this.mainSurface.evalIn(e)}};function isPasteKeyEvent(e){return isMacOS()?e.metaKey&&e.key===`v`:e.ctrlKey&&e.shiftKey&&e.key===`V`}var Input=class{constructor(e){let t=e.option;this.editor=e,this.composition=!1,this.ignoreKeydownAfterCompositionend=!1,this.span=document.createElement(`span`),this.span.style.color=t.foreground,this.span.style.backgroundColor=t.background,this.span.style.position=`absolute`,this.span.style.zIndex=1e6,this.span.style.top=`0`,this.span.style.left=`0`,this.span.style.font=t.font,this.input=document.createElement(`input`),this.input.style.backgroundColor=`transparent`,this.input.style.color=`transparent`,this.input.style.width=`0`,this.input.style.padding=`0`,this.input.style.margin=`0`,this.input.style.border=`none`,this.input.style.position=`absolute`,this.input.style.zIndex=`-10`,this.input.style.top=`0`,this.input.style.left=`0`,this.input.style.font=t.font,this.input.addEventListener(`blur`,e=>{this.input.focus()}),this.input.addEventListener(`input`,e=>{this.composition===!1&&(this.input.value=``,this.span.innerHTML=``,this.input.style.width=`0`,isMacOS()||this.editor.emitInputString(e.data))}),this.input.addEventListener(`paste`,async e=>{e.preventDefault();let t=e.clipboardData||window.Clipboard.data,n=t?.getData(`text`)??t?.getData(`text/plain`);if(n&&n.length>0){this.editor.emitInputString(n);return}try{if(navigator.clipboard?.readText){let e=await navigator.clipboard.readText();if(e&&e.length>0){this.editor.emitInputString(e);return}}}catch(e){console.warn(`clipboard.readText() failed:`,e)}alert(`Paste failed (permission/environment restriction`)}),this.input.addEventListener(`keydown`,e=>{if(!isPasteKeyEvent(e)&&!(e.isComposing||this.composition)&&e.key!==`Process`){if(this.ignoreKeydownAfterCompositionend&&(isSafari||isMacOS())){e.preventDefault(),this.ignoreKeydownAfterCompositionend=!1;return}if(!(!isMacOS()&&!e.ctrlKey&&!e.altKey&&e.key.length===1)&&(e.preventDefault(),e.isComposing!==!0&&e.code!==``))return setTimeout(()=>{this.composition||(this.editor.emitInput(e),this.input.value=``)},0),!1}}),this.input.addEventListener(`compositionstart`,e=>{this.composition=!0,this.span.innerHTML=this.input.value,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionupdate`,e=>{this.span.innerHTML=e.data,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionend`,e=>{this.composition=!1,this.editor.emitInputString(this.input.value),this.input.value=``,this.span.innerHTML=this.input.value,this.input.style.width=`0`,this.ignoreKeydownAfterCompositionend=!0}),document.body.appendChild(this.input),document.body.appendChild(this.span),this.input.focus()}finalize(){document.body.removeChild(this.input),document.body.removeChild(this.span)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.span.style.top=r+t+`px`,this.span.style.left=n+e+`px`,this.input.style.top=this.span.offsetTop+`px`,this.input.style.left=this.span.offsetLeft+`px`}updateForeground(e){this.span.style.color=e}updateBackground(e){this.span.style.backgroundColor=e}},MessageTable=class{constructor(){this.map=new Map}register(e,t){for(let n in t){let r=t[n];this.map.set(n,r),e.on(n,r)}}get(e){return this.map.get(e)}};function getDisplayRectangleDefault(){return[0,0,window.innerWidth,window.innerHeight]}var Editor=class{constructor({getDisplayRectangle:e=getDisplayRectangleDefault,fontName:t,fontSize:n,url:r,onExit:i,onClosed:a}){this.getDisplayRectangle=e,this.option=new Option({fontName:t,fontSize:n}),this.onExit=i,this.input=new Input(this),this.cursors=new Map,this.cursorOverlay=document.createElement(`div`),this.cursorOverlay.className=`lem-cursor`,this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.cursorOverlay.style.backgroundColor=`#ffffff`,this.cursorType=`box`,this.viewMap=new Map,this.jsonrpc=new JSONRPC(r,{onClosed:()=>{a()}}),this.messageTable=new MessageTable,this.messageTable.register(this.jsonrpc,{"update-foreground":this.updateForeground.bind(this),"update-background":this.updateBackground.bind(this),"make-view":this.makeView.bind(this),"delete-view":this.deleteView.bind(this),"resize-view":this.resize.bind(this),"move-view":this.move.bind(this),"redraw-view-after":this.redrawViewAfter.bind(this),clear:this.clear.bind(this),"clear-eol":this.clearEol.bind(this),"clear-eob":this.clearEob.bind(this),put:this.put.bind(this),"put-image":this.putImage.bind(this),"modeline-put":this.modelinePut.bind(this),"draw-block":this.drawBlock.bind(this),"modeline-draw-block":this.modelineDrawBlock.bind(this),"update-display":this.updateDisplay.bind(this),"move-cursor":this.moveCursor.bind(this),"change-view":this.changeView.bind(this),"resize-display":this.resizeDisplay.bind(this),bulk:this.bulk.bind(this),exit:this.exitEditor.bind(this),"get-clipboard-text":this.getClipboardText.bind(this),"set-clipboard-text":this.setClipboardText.bind(this),"js-eval":this.jsEval.bind(this),"set-font":this.setFont.bind(this),"get-font":this.getFont.bind(this),"get-display-size":this.getDisplaySize.bind(this),"load-css":this.loadCSS.bind(this),"update-cursor-shape":this.updateCursorShape.bind(this)}),this.login(),this.boundedHandleResize=this.handleResize.bind(this),this.focusHiddenInput=this.focusHiddenInput.bind(this)}init(){window.addEventListener(`resize`,this.boundedHandleResize),document.getElementsByTagName(`html`)[0].style[`background-color`]=`#333`,getLemEditorElement().appendChild(this.cursorOverlay)}finalize(){window.removeEventListener(`resize`,this.boundedHandleResize),this.input.finalize(),this.cursorOverlay.parentNode&&this.cursorOverlay.parentNode.removeChild(this.cursorOverlay)}closeConnection(){this.jsonrpc.close()}emitInput(e){let t=convertKeyEvent(e);if(t){if(t.key===`]`&&t.ctrl&&!t.meta&&!t.super&&!t.shift){this.jsonrpc.notify(`input`,{kind:`abort`});return}t.key!==`Unidentified`&&this.jsonrpc.notify(`input`,{kind:`key`,value:t})}}emitInputString(e){e?this.jsonrpc.notify(`input`,{kind:`input-string`,value:e}):console.error(`unexpected argument`,e)}redrawParams(){return{size:this.getDisplaySize(),fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent}}handleResize(e){this.jsonrpc.notify(`redraw`,this.redrawParams())}focusHiddenInput(){let e=this.input?.input;if(e){try{window.focus()}catch{}requestAnimationFrame(()=>{setTimeout(()=>{e.focus({preventScroll:!0})},0)})}}sendNotification(e,t){this.jsonrpc.notify(e,t)}request(e,t,n){this.jsonrpc.request(e,t,n)}getDisplaySize(){let[e,t,n,r]=this.getDisplayRectangle();return{width:Math.floor(n/this.option.fontWidth),height:Math.floor(r/this.option.fontHeight)}}callMessage(e,t){this.messageTable.get(e)(t)}findViewById(e){return this.viewMap.get(e)}login(){this.jsonrpc.request(`login`,{size:this.getDisplaySize(),foreground:this.option.foreground,background:this.option.background,fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent},e=>{if(this.updateForeground(e.foreground),this.updateBackground(e.background),e.views)for(let t of e.views)this.makeView(t);this.jsonrpc.notify(`redraw`,this.redrawParams())})}updateForeground(e){e!=null&&(this.option.foreground=e,this.input.updateForeground(e))}updateBackground(e){if(e==null)return;this.option.background=e,this.input.updateBackground(e);let t=getLemEditorElement();t.style.backgroundColor=e}makeView({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,use_modeline:l,kind:u,type:d,content:f,border:p,border_shape:m}){let h=new View({option:this.option,id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,editor:this});this.viewMap.set(e,h)}deleteView({viewInfo:{id:e}}){this.findViewById(e).delete(),this.viewMap.delete(e)}resize({viewInfo:{id:e},width:t,height:n,pixelWidth:r,pixelHeight:i}){let a=this.findViewById(e);a?a.resize(t,n,r,i):console.warn(`resize: view not found for id ${e}`)}move({viewInfo:{id:e},x:t,y:n,pixelX:r,pixelY:i}){let a=this.findViewById(e);a?a.move(t,n,r,i):console.warn(`move: view not found for id ${e}`)}redrawViewAfter({viewInfo:{id:e},isActive:t}){this.findViewById(e).touch(t)}clear({viewInfo:{id:e}}){this.findViewById(e).clear()}clearEol({viewInfo:{id:e},x:t,y:n,height:r}){this.findViewById(e).clearEol(t,n,r)}clearEob({viewInfo:{id:e},x:t,y:n}){this.findViewById(e).clearEob(t,n)}put({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,font:o,backgroundY:s,backgroundHeight:c}){this.findViewById(e).print(t,n,r,i,a,o,s,c)}drawBlock({viewInfo:{id:e},x:t,y:n,width:r,height:i,color:a}){this.findViewById(e).drawBlock(t,n,r,i,a)}modelineDrawBlock({viewInfo:{id:e},x:t,y:n,width:r,height:i,color:a}){this.findViewById(e).drawBlockOnModeline(t,n,r,i,a)}putImage({viewInfo:{id:e},x:t,y:n,pixelWidth:r,pixelHeight:i,clipWidth:a,clipHeight:o,url:s}){this.findViewById(e).printImage(t,n,r,i,a,o,s)}modelinePut({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,backgroundY:o,backgroundHeight:s}){this.findViewById(e).printToModeline(t,n,r,i,a,o,s)}updateDisplay(){}moveCursor({viewInfo:{id:e},x:t,y:n,color:r,cursorText:i,cursorForeground:a}){let o=this.findViewById(e),[s,c]=this.getDisplayRectangle(),l=o.pixelX+t,u=o.pixelY+n;this.input.move(l,u);let d=r||this.option.foreground,f=a||this.option.background,p=this.cursorOverlay;switch(this.cursorType){case`bar`:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=`2px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;case`underline`:p.style.left=s+l+`px`,p.style.top=c+u+this.option.fontHeight-2+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=`2px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;default:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.style.font=this.option.font,p.style.paddingTop=textOffsetY+`px`,p.textContent=i||``,p.style.color=f;break}p.style.animation=`none`,p.offsetHeight,p.style.animation=``}updateCursorShape({cursorType:e}){this.cursorType=e||`box`}changeView({viewInfo:{id:e},type:t,content:n}){let r=this.findViewById(e);switch(t){case`html`:r.changeToHTMLContent(n);break;case`editor`:r.changeToEditorContent();break}}resizeDisplay({width:e,height:t}){let n=getLemEditorElement();n.style.width=Math.floor(e*this.option.fontWidth)+`px`,n.style.height=Math.floor(t*this.option.fontHeight)+`px`}bulk(e){for(let{method:t,argument:n}of e)this.callMessage(t,n)}exitEditor(){this.onExit&&this.onExit()}getClipboardText(){navigator.clipboard?.readText().then(e=>{this.jsonrpc.notify(`got-clipboard-text`,{text:e})})}setClipboardText({text:e}){navigator.clipboard&&navigator.clipboard.writeText(e)}jsEval({viewInfo:{id:e},code:t}){let n=this.findViewById(e).evalIn(t);return n&&n.toString()}setFont({fontName:e,fontSize:t}){this.option.setFont(e||this.option.fontName,t||this.option.fontSize),this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.jsonrpc.notify(`redraw`,this.redrawParams())}getFont(){return{name:this.option.fontName,size:this.option.fontSize}}loadCSS({content:e}){let t=document.createElement(`style`);t.textContent=e,document.head.appendChild(t)}notifyToServer(e,t){this.jsonrpc.notify(`invoke`,{method:e,args:t})}},canvas=document.querySelector(`#editor`);async function main(){await Promise.all([document.fonts.load(`19px file-icons`),document.fonts.load(`19px AllTheIcons`),document.fonts.load(`19px fontawesome`),document.fonts.load(`19px material-design-icons`),document.fonts.load(`19px octicons`)]),await document.fonts.ready;let e=new Editor({canvas,fontName:`Monospace`,fontSize:18,url:`${window.location.protocol===`https:`?`wss`:`ws`}://${window.location.hostname}:${window.location.port}`,onExit:null,onClosed:null});window.addEventListener(`message`,t=>{t.data.type===`invoke-lem`&&e.notifyToServer(t.data.method,t.data.args)}),e.init()}main(); \ No newline at end of file diff --git a/frontends/server/frontend/editor.js b/frontends/server/frontend/editor.js index 99f213b91..1eaf87557 100644 --- a/frontends/server/frontend/editor.js +++ b/frontends/server/frontend/editor.js @@ -345,7 +345,7 @@ class BaseSurface { // drawing coordinates are relative to the surface's own top-left corner. drawBlock(x, y, width, height, color) { } - drawText(x, y, text, textWidth, attribute, font) { } + drawText(x, y, text, textWidth, attribute, font, backgroundY, backgroundHeight) { } drawImage(x, y, width, height, clipWidth, clipHeight, url) { } clearImages(yStart, yEnd) { } @@ -411,18 +411,19 @@ class CanvasSurface extends BaseSurface { }); } - // the background is filled first, textWidth by one line of text, then the text drawn over it. a - // rectangle taller than that is a `drawBlock', not a text-less draw through here. - drawText(x, y, text, textWidth, attribute, font) { + // the background is filled first, then the text over it. it covers the row the text sits on, + // which an image can make taller, and defaults to one line at the text's own y. + drawText(x, y, text, textWidth, attribute, font, backgroundY, backgroundHeight) { const option = this.editor.option; - const blockHeight = option.fontHeight; + const blockY = backgroundY == null ? y : backgroundY; + const blockHeight = backgroundHeight == null ? option.fontHeight : backgroundHeight; this.drawingQueue.push(function(ctx) { font = font ? `${option.fontSize}px ${font}` : option.font; if (!attribute) { drawBlock({ ctx, x: x, - y: y, + y: blockY, width: textWidth, height: blockHeight, style: option.background, @@ -457,7 +458,7 @@ class CanvasSurface extends BaseSurface { drawBlock({ ctx, x: x, - y: y, + y: blockY, width: textWidth, height: blockHeight, style: background, @@ -867,7 +868,7 @@ class View { this.mainSurface.clearImages(y, this.pixelHeight); } - print(x, y, text, textWidth, attribute, font) { + print(x, y, text, textWidth, attribute, font, backgroundY, backgroundHeight) { this.mainSurface.drawText( x, y, @@ -875,6 +876,8 @@ class View { textWidth, attribute, font, + backgroundY, + backgroundHeight, ); } @@ -894,7 +897,7 @@ class View { this.mainSurface.drawImage(x, y, pixelWidth, pixelHeight, clipWidth, clipHeight, url); } - printToModeline(x, y, text, textWidth, attribute) { + printToModeline(x, y, text, textWidth, attribute, backgroundY, backgroundHeight) { if (this.modelineSurface) { this.modelineSurface.drawText( x, @@ -903,6 +906,8 @@ class View { textWidth, attribute, null, + backgroundY, + backgroundHeight, ); } } @@ -1472,9 +1477,9 @@ export class Editor { view.clearEob(x, y); } - put({ viewInfo: { id }, x, y, text, textWidth, attribute, font }) { + put({ viewInfo: { id }, x, y, text, textWidth, attribute, font, backgroundY, backgroundHeight }) { const view = this.findViewById(id); - view.print(x, y, text, textWidth, attribute, font); + view.print(x, y, text, textWidth, attribute, font, backgroundY, backgroundHeight); } drawBlock({ viewInfo: { id }, x, y, width, height, color }) { @@ -1492,9 +1497,9 @@ export class Editor { view.printImage(x, y, pixelWidth, pixelHeight, clipWidth, clipHeight, url); } - modelinePut({ viewInfo: { id }, x, y, text, textWidth, attribute }) { + modelinePut({ viewInfo: { id }, x, y, text, textWidth, attribute, backgroundY, backgroundHeight }) { const view = this.findViewById(id); - view.printToModeline(x, y, text, textWidth, attribute); + view.printToModeline(x, y, text, textWidth, attribute, backgroundY, backgroundHeight); } updateDisplay() { diff --git a/frontends/server/main.lisp b/frontends/server/main.lisp index 2c157f6cb..ec1de4e26 100644 --- a/frontends/server/main.lisp +++ b/frontends/server/main.lisp @@ -616,12 +616,13 @@ returns true when one of them changed, since nothing already measured survives a ;;; drawing -(defgeneric draw-object (jsonrpc object x y view) +(defgeneric draw-object (jsonrpc object x y view row) (:documentation "draw OBJECT into VIEW with its top-left corner at pixel position X, Y. -`lem-core/display:layout-row' already chose Y as the row's baseline minus this object's ascent, so -a method never needs to know the row's own top or height.")) +`lem-core/display:layout-row' already positioned it, so ROW is only for what an object shares with +the rest of its row: the full height a background fills and where the row's text sits, which is +where the caret goes.")) -(defmethod draw-object (jsonrpc (object display:void-object) x y view) +(defmethod draw-object (jsonrpc (object display:void-object) x y view row) (values)) (defvar *put-target* :edit-area) @@ -659,20 +660,28 @@ same hash." (setf attribute (lem:make-attribute :background lem-if:*background-color-of-drawing-window*))) (attribute-to-hash attribute))) -(defun put (jsonrpc view x y string attribute &key font text-width) - "draw STRING at pixel position X, Y in VIEW, over a TEXT-WIDTH background one line of text tall." +(defun taller-than-text-p (jsonrpc row) + "whether ROW is taller than a line of text, which an image on it can make it." + (and row (> (display:row-height row) (jsonrpc-cell-height jsonrpc)))) + +(defun put (jsonrpc view x y string attribute &key font text-width row) + "draw STRING at pixel position X, Y in VIEW, over a background TEXT-WIDTH wide and as tall as ROW." (with-error-handler () - (notify* jsonrpc - (ecase *put-target* - (:edit-area "put") - (:modeline "modeline-put")) - (hash "viewInfo" (view-id-hash view) - "x" x - "y" y - "text" string - "textWidth" (or text-width (* (lem:string-width string) (jsonrpc-cell-width jsonrpc))) - "attribute" (ensure-attribute attribute) - "font" font)))) + (let ((tall (taller-than-text-p jsonrpc row))) + (notify* jsonrpc + (ecase *put-target* + (:edit-area "put") + (:modeline "modeline-put")) + (hash "viewInfo" (view-id-hash view) + "x" x + "y" y + "text" string + "textWidth" (or text-width + (* (lem:string-width string) (jsonrpc-cell-width jsonrpc))) + "backgroundY" (and tall (display:row-top row)) + "backgroundHeight" (and tall (display:row-height row)) + "attribute" (ensure-attribute attribute) + "font" font))))) (defun draw-block (jsonrpc view x y width height color) "fill the WIDTH by HEIGHT rectangle at pixel position X, Y in VIEW with COLOR. @@ -690,7 +699,7 @@ leaves the client to use its default background." "height" height "color" (and color (lem:color-to-hex-string color)))))) -(defmethod draw-object (jsonrpc (object display:text-object) x y view) +(defmethod draw-object (jsonrpc (object display:text-object) x y view row) (let* ((string (display:text-object-string object)) (attribute (display:text-object-attribute object)) (type (display:text-object-type object)) @@ -703,9 +712,10 @@ leaves the client to use its default background." y string attribute - :text-width width))) + :text-width width + :row row))) -(defmethod draw-object (jsonrpc (object display:icon-object) x y view) +(defmethod draw-object (jsonrpc (object display:icon-object) x y view row) (let* ((string (display:text-object-string object)) (attribute (display:text-object-attribute object)) (type (display:text-object-type object)) @@ -719,10 +729,11 @@ leaves the client to use its default background." string attribute :text-width width + :row row :font (lem:icon-value (char-code (char string 0)) :font)))) -(defmethod draw-object (jsonrpc (object display:eol-cursor-object) x y view) +(defmethod draw-object (jsonrpc (object display:eol-cursor-object) x y view row) (lem-core:set-last-print-cursor (view-window view) x y) (let ((attr (lem:make-attribute :background @@ -730,7 +741,7 @@ leaves the client to use its default background." (lem-core:set-cursor-attribute attr) (put jsonrpc view x y " " attr :text-width (jsonrpc-cell-width jsonrpc)))) -(defmethod draw-object (jsonrpc (object display:line-end-object) x y view) +(defmethod draw-object (jsonrpc (object display:line-end-object) x y view row) (let ((string (display:text-object-string object)) (attribute (display:text-object-attribute object)) (width (lem-if:object-width jsonrpc object))) @@ -741,7 +752,8 @@ leaves the client to use its default background." y string attribute - :text-width width))) + :text-width width + :row row))) (defun image-object-url (object) "return a URL the JS client can load for OBJECT's image, or NIL. @@ -757,7 +769,32 @@ a string already carrying a data:/https: URL is passed through unchanged." (format nil "/local~A" image))) (t nil)))) -(defmethod draw-object (jsonrpc (object display:image-object) x y view) +(defun attribute-own-background (attribute) + "the background ATTRIBUTE asks for as a color, or NIL when it asks for none. +not `lem:attribute-background-with-reverse', which answers with the default background rather than NIL." + (alexandria:when-let ((background (if (lem:attribute-reverse attribute) + (lem:attribute-foreground attribute) + (lem:attribute-background attribute)))) + (typecase background + (lem:color background) + (string (lem:parse-color background))))) + +(defun row-text-top (jsonrpc row) + "the top of a line of text on ROW: its baseline less the font's ascent." + (- (display:row-baseline row) + (or (jsonrpc-cell-ascent jsonrpc) (jsonrpc-cell-height jsonrpc)))) + +(defmethod draw-object (jsonrpc (object display:image-object) x y view row) + (alexandria:when-let ((attribute (lem:ensure-attribute (display:image-object-attribute object) + nil))) + ;; the image carries the attribute of the text it replaced, so selecting the line reaches it too + (alexandria:when-let ((color (attribute-own-background attribute))) + (draw-block jsonrpc view x (display:row-top row) (lem-if:object-width jsonrpc object) + (display:row-height row) color)) + ;; the cursor can sit on an image. Y is the image's top, which can be far above the row's text, + ;; so report the text's top instead and the caret aligns with the text. + (when (lem-core:cursor-attribute-p attribute) + (lem-core:set-last-print-cursor (view-window view) x (row-text-top jsonrpc row)))) (let ((url (image-object-url object))) (when url (with-error-handler () @@ -801,7 +838,8 @@ text line's, so it goes as a `draw-block' rather than a put's background." (display:placement-object placement) (display:placement-x placement) (display:placement-top placement) - view))) + view + row))) (defmethod lem-if:render-row ((jsonrpc jsonrpc) view row) (with-error-handler () From 47f2bf580b966f1eb16f62f6930c2d506977953b Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Mon, 3 Aug 2026 23:20:15 +0300 Subject: [PATCH 15/18] let frontends report the font's em size --- frontends/sdl2/main.lisp | 7 +++++++ frontends/server/frontend/dist/assets/index.js | 2 +- frontends/server/frontend/editor.js | 2 ++ frontends/server/main.lisp | 11 +++++++++-- src/interface.lisp | 6 ++++++ src/internal-packages.lisp | 1 + 6 files changed, 26 insertions(+), 3 deletions(-) diff --git a/frontends/sdl2/main.lisp b/frontends/sdl2/main.lisp index d218d664c..5f46e8071 100644 --- a/frontends/sdl2/main.lisp +++ b/frontends/sdl2/main.lisp @@ -484,6 +484,13 @@ (display:display-char-height display) (display:display-font-ascent display)))) +(defmethod lem-if:font-em-pixels ((implementation sdl2)) + (display:with-display (display) + ;; a high dpi display opens the font at a multiple of the configured size, and the cell + ;; metrics are measured from the font as opened, so this has to be that size and not the + ;; configured one. + (font-config-size (display:display-font-config display)))) + (defmethod lem-if:view-width ((implementation sdl2) view) (display:with-display (display) (* (display:display-char-width display) diff --git a/frontends/server/frontend/dist/assets/index.js b/frontends/server/frontend/dist/assets/index.js index 7cdb66a8b..1c50a8893 100644 --- a/frontends/server/frontend/dist/assets/index.js +++ b/frontends/server/frontend/dist/assets/index.js @@ -1 +1 @@ -var __defProp=Object.defineProperty,__commonJSMin=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),__exportAll=(e,t)=>{let n={};for(var r in e)__defProp(n,r,{get:e[r],enumerable:!0});return t||__defProp(n,Symbol.toStringTag,{value:`Module`}),n};(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var require_models=__commonJSMin((e=>{var t=e&&e.__extends||(function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};return function(t,n){if(typeof n!=`function`&&n!==null)throw TypeError(`Class extends value `+String(n)+` is not a constructor or null`);e(t,n);function r(){this.constructor=t}t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}})();Object.defineProperty(e,"__esModule",{value:!0}),e.createJSONRPCNotification=e.createJSONRPCRequest=e.createJSONRPCSuccessResponse=e.createJSONRPCErrorResponse=e.JSONRPCErrorCode=e.JSONRPCErrorException=e.isJSONRPCResponses=e.isJSONRPCResponse=e.isJSONRPCRequests=e.isJSONRPCRequest=e.isJSONRPCID=e.JSONRPC=void 0,e.JSONRPC=`2.0`,e.isJSONRPCID=function(e){return typeof e==`string`||typeof e==`number`||e===null},e.isJSONRPCRequest=function(t){return t.jsonrpc===e.JSONRPC&&t.method!==void 0&&t.result===void 0&&t.error===void 0},e.isJSONRPCRequests=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCRequest)},e.isJSONRPCResponse=function(t){return t.jsonrpc===e.JSONRPC&&t.id!==void 0&&(t.result!==void 0||t.error!==void 0)},e.isJSONRPCResponses=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCResponse)};var n=function(e,t,n){var r={code:e,message:t};return n!=null&&(r.data=n),r};e.JSONRPCErrorException=function(e){t(r,e);function r(t,n,i){var a=e.call(this,t)||this;return Object.setPrototypeOf(a,r.prototype),a.code=n,a.data=i,a}return r.prototype.toObject=function(){return n(this.code,this.message,this.data)},r}(Error),(function(e){e[e.ParseError=-32700]=`ParseError`,e[e.InvalidRequest=-32600]=`InvalidRequest`,e[e.MethodNotFound=-32601]=`MethodNotFound`,e[e.InvalidParams=-32602]=`InvalidParams`,e[e.InternalError=-32603]=`InternalError`})(e.JSONRPCErrorCode||={}),e.createJSONRPCErrorResponse=function(t,r,i,a){return{jsonrpc:e.JSONRPC,id:t,error:n(r,i,a)}},e.createJSONRPCSuccessResponse=function(t,n){return{jsonrpc:e.JSONRPC,id:t,result:n??null}},e.createJSONRPCRequest=function(t,n,r){return{jsonrpc:e.JSONRPC,id:t,method:n,params:r}},e.createJSONRPCNotification=function(t,n){return{jsonrpc:e.JSONRPC,method:t,params:n}}})),require_internal=__commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.DefaultErrorCode=void 0,e.DefaultErrorCode=0})),require_client=__commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{Object.defineProperty(e,"__esModule",{value:!0})})),require_server=__commonJSMin((e=>{var t=e&&e.__assign||function(){return t=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__createBinding||(Object.create?(function(e,t,n,r){r===void 0&&(r=n);var i=Object.getOwnPropertyDescriptor(t,n);(!i||(`get`in i?!t.__esModule:i.writable||i.configurable))&&(i={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,i)}):(function(e,t,n,r){r===void 0&&(r=n),e[r]=t[n]})),n=e&&e.__exportStar||function(e,n){for(var r in e)r!=="default"&&!Object.prototype.hasOwnProperty.call(n,r)&&t(n,e,r)};Object.defineProperty(e,"__esModule",{value:!0}),n(require_client(),e),n(require_interfaces(),e),n(require_models(),e),n(require_server(),e),n(require_server_and_client(),e)})),import_dist=require_dist(),JSONRPC=class{constructor(e,{onConnected:t,onClosed:n}){this.url=e,this.onConnected=t,this.onClosed=n,this.messageQueue=[],this.serverAndClient=null,this.connect(),this.connectionEstablished=!1,this.timerId=null,this.closed=!1}close(){this.timerId&&clearTimeout(this.timerId),this.webSocket.close(),this.closed=!0}on(e,t){this.serverAndClient.addMethod(e,t)}async requestInternal(e,t,n){let r=await this.serverAndClient.request(e,t);n&&n(r)}requestMessageQueue(){this.messageQueue.forEach(e=>{let[t,n,r]=e;this.requestInternal(t,n,r)}),this.messageQueue=[]}request(e,t,n){this.webSocket.readyState===WebSocket.OPEN?this.requestInternal(e,t,n):this.messageQueue.push([e,t,n])}notify(e,t){switch(this.webSocket.readyState){case WebSocket.OPEN:this.serverAndClient.notify(e,t);break;case WebSocket.CLOSED:break}}connect(e){this.closed||(console.log(`connect`,this.url),this.webSocket=new WebSocket(this.url),this.serverAndClient||=new import_dist.JSONRPCServerAndClient(new import_dist.JSONRPCServer,new import_dist.JSONRPCClient(e=>{try{return this.webSocket.send(JSON.stringify(e)),Promise.resolve()}catch(e){return Promise.reject(e)}})),this.webSocket.onmessage=e=>{this.serverAndClient.receiveAndSend(JSON.parse(e.data.toString()))},this.webSocket.onopen=()=>{console.log(`WebSocket connection established`),this.connectionEstablished=!0,this.onConnected&&this.onConnected(),this.requestMessageQueue()},this.webSocket.onclose=e=>{console.error(`WebScoket closed`,e),this.serverAndClient.rejectAllPendingRequests(`Connection is closed (${e.reason}).`),this.connectionEstablished&&this.onClosed(),this.timerId=setTimeout(()=>{this.connect()},3e3)},this.webSocket.onerror=e=>{console.error(`WebSocket error:`,e),this.webSocket.close()})}},keyevent_exports=__exportAll({convertKeyEvent:()=>convertKeyEvent}),modifierKeys=[`Shift`,`Control`,`Alt`,`Meta`,`CapsLock`],convertKeyTable={Enter:`Return`,ArrowRight:`Right`,ArrowLeft:`Left`,ArrowUp:`Up`,ArrowDown:`Down`,"¡":`1`,"™":`2`,"£":`3`,"¢":`4`,"∞":`5`,"§":`6`,"¶":`7`,"•":`8`,ª:`9`,º:`0`,"–":`-`,"≠":`=`,"“":`[`,"‘":`]`,"«":`\\`,"…":`;`,æ:`'`,"≤":`,`,"≥":`.`,"÷":`/`,"⁄":`!`,"€":`@`,"‹":`#`,"›":`$`,fi:`%`,fl:`^`,"‡":`&`,"°":`*`,"·":`(`,"‚":`)`,"—":`_`,"±":`+`,"”":`{`,"’":`}`,"»":`|`,Ú:`:`,Æ:`"`,"¯":`<`,"˘":`>`,"¿":`?`,œ:`q`,"∑":`w`,"´":`e`,"®":`r`,"†":`t`,"¥":`y`,"¨":`u`,ˆ:`i`,ø:`o`,π:`p`,å:`a`,ß:`s`,"∂":`d`,ƒ:`f`,"©":`g`,"˙":`h`,"∆":`j`,"˚":`k`,"¬":`l`,Ω:`z`,"≈":`x`,ç:`c`,"√":`v`,"∫":`b`,"˜":`n`,µ:`m`,Œ:`Q`,"„":`W`,"´":`E`,"‰":`R`,ˇ:`T`,Á:`Y`,"¨":`U`,ˆ:`I`,Ø:`O`,"∏":`P`,Å:`A`,Í:`S`,Î:`D`,Ï:`F`,"˝":`G`,Ó:`H`,Ô:`J`,"":`K`,Ò:`L`,"¸":`Z`,"˛":`X`,Ç:`C`,"◊":`V`,ı:`B`,"˜":`N`,Â:`M`};function getKey(e){return e.altKey?convertKeyTable[e.key]||(e.code.startsWith(`Key`)?e.code[3].toLowerCase():null)||e.key:convertKeyTable[e.key]||e.key}function convertKeyEvent(e){return modifierKeys.indexOf(e.key)===-1?{key:getKey(e),ctrl:e.ctrlKey,meta:e.altKey,super:e.metaKey,shift:e.shiftKey}:null}var lib_exports=__exportAll({computeWidth:()=>computeWidth,eawVersion:()=>version,getEAW:()=>getEAW}),defs=[[0,31,`N`],[32,126,`Na`],[127,160,`N`],[161,161,`A`],[162,163,`Na`],[164,164,`A`],[165,166,`Na`],[167,168,`A`],[169,169,`N`],[170,170,`A`],[171,171,`N`],[172,172,`Na`],[173,174,`A`],[175,175,`Na`],[176,180,`A`],[181,181,`N`],[182,186,`A`],[187,187,`N`],[188,191,`A`],[192,197,`N`],[198,198,`A`],[199,207,`N`],[208,208,`A`],[209,214,`N`],[215,216,`A`],[217,221,`N`],[222,225,`A`],[226,229,`N`],[230,230,`A`],[231,231,`N`],[232,234,`A`],[235,235,`N`],[236,237,`A`],[238,239,`N`],[240,240,`A`],[241,241,`N`],[242,243,`A`],[244,246,`N`],[247,250,`A`],[251,251,`N`],[252,252,`A`],[253,253,`N`],[254,254,`A`],[255,256,`N`],[257,257,`A`],[258,272,`N`],[273,273,`A`],[274,274,`N`],[275,275,`A`],[276,282,`N`],[283,283,`A`],[284,293,`N`],[294,295,`A`],[296,298,`N`],[299,299,`A`],[300,304,`N`],[305,307,`A`],[308,311,`N`],[312,312,`A`],[313,318,`N`],[319,322,`A`],[323,323,`N`],[324,324,`A`],[325,327,`N`],[328,331,`A`],[332,332,`N`],[333,333,`A`],[334,337,`N`],[338,339,`A`],[340,357,`N`],[358,359,`A`],[360,362,`N`],[363,363,`A`],[364,461,`N`],[462,462,`A`],[463,463,`N`],[464,464,`A`],[465,465,`N`],[466,466,`A`],[467,467,`N`],[468,468,`A`],[469,469,`N`],[470,470,`A`],[471,471,`N`],[472,472,`A`],[473,473,`N`],[474,474,`A`],[475,475,`N`],[476,476,`A`],[477,592,`N`],[593,593,`A`],[594,608,`N`],[609,609,`A`],[610,707,`N`],[708,708,`A`],[709,710,`N`],[711,711,`A`],[712,712,`N`],[713,715,`A`],[716,716,`N`],[717,717,`A`],[718,719,`N`],[720,720,`A`],[721,727,`N`],[728,731,`A`],[732,732,`N`],[733,733,`A`],[734,734,`N`],[735,735,`A`],[736,767,`N`],[768,879,`A`],[880,912,`N`],[913,929,`A`],[930,930,`N`],[931,937,`A`],[938,944,`N`],[945,961,`A`],[962,962,`N`],[963,969,`A`],[970,1024,`N`],[1025,1025,`A`],[1026,1039,`N`],[1040,1103,`A`],[1104,1104,`N`],[1105,1105,`A`],[1106,4351,`N`],[4352,4447,`W`],[4448,8207,`N`],[8208,8208,`A`],[8209,8210,`N`],[8211,8214,`A`],[8215,8215,`N`],[8216,8217,`A`],[8218,8219,`N`],[8220,8221,`A`],[8222,8223,`N`],[8224,8226,`A`],[8227,8227,`N`],[8228,8231,`A`],[8232,8239,`N`],[8240,8240,`A`],[8241,8241,`N`],[8242,8243,`A`],[8244,8244,`N`],[8245,8245,`A`],[8246,8250,`N`],[8251,8251,`A`],[8252,8253,`N`],[8254,8254,`A`],[8255,8307,`N`],[8308,8308,`A`],[8309,8318,`N`],[8319,8319,`A`],[8320,8320,`N`],[8321,8324,`A`],[8325,8360,`N`],[8361,8361,`H`],[8362,8363,`N`],[8364,8364,`A`],[8365,8450,`N`],[8451,8451,`A`],[8452,8452,`N`],[8453,8453,`A`],[8454,8456,`N`],[8457,8457,`A`],[8458,8466,`N`],[8467,8467,`A`],[8468,8469,`N`],[8470,8470,`A`],[8471,8480,`N`],[8481,8482,`A`],[8483,8485,`N`],[8486,8486,`A`],[8487,8490,`N`],[8491,8491,`A`],[8492,8530,`N`],[8531,8532,`A`],[8533,8538,`N`],[8539,8542,`A`],[8543,8543,`N`],[8544,8555,`A`],[8556,8559,`N`],[8560,8569,`A`],[8570,8584,`N`],[8585,8585,`A`],[8586,8591,`N`],[8592,8601,`A`],[8602,8631,`N`],[8632,8633,`A`],[8634,8657,`N`],[8658,8658,`A`],[8659,8659,`N`],[8660,8660,`A`],[8661,8678,`N`],[8679,8679,`A`],[8680,8703,`N`],[8704,8704,`A`],[8705,8705,`N`],[8706,8707,`A`],[8708,8710,`N`],[8711,8712,`A`],[8713,8714,`N`],[8715,8715,`A`],[8716,8718,`N`],[8719,8719,`A`],[8720,8720,`N`],[8721,8721,`A`],[8722,8724,`N`],[8725,8725,`A`],[8726,8729,`N`],[8730,8730,`A`],[8731,8732,`N`],[8733,8736,`A`],[8737,8738,`N`],[8739,8739,`A`],[8740,8740,`N`],[8741,8741,`A`],[8742,8742,`N`],[8743,8748,`A`],[8749,8749,`N`],[8750,8750,`A`],[8751,8755,`N`],[8756,8759,`A`],[8760,8763,`N`],[8764,8765,`A`],[8766,8775,`N`],[8776,8776,`A`],[8777,8779,`N`],[8780,8780,`A`],[8781,8785,`N`],[8786,8786,`A`],[8787,8799,`N`],[8800,8801,`A`],[8802,8803,`N`],[8804,8807,`A`],[8808,8809,`N`],[8810,8811,`A`],[8812,8813,`N`],[8814,8815,`A`],[8816,8833,`N`],[8834,8835,`A`],[8836,8837,`N`],[8838,8839,`A`],[8840,8852,`N`],[8853,8853,`A`],[8854,8856,`N`],[8857,8857,`A`],[8858,8868,`N`],[8869,8869,`A`],[8870,8894,`N`],[8895,8895,`A`],[8896,8977,`N`],[8978,8978,`A`],[8979,8985,`N`],[8986,8987,`W`],[8988,9e3,`N`],[9001,9002,`W`],[9003,9192,`N`],[9193,9196,`W`],[9197,9199,`N`],[9200,9200,`W`],[9201,9202,`N`],[9203,9203,`W`],[9204,9311,`N`],[9312,9449,`A`],[9450,9450,`N`],[9451,9547,`A`],[9548,9551,`N`],[9552,9587,`A`],[9588,9599,`N`],[9600,9615,`A`],[9616,9617,`N`],[9618,9621,`A`],[9622,9631,`N`],[9632,9633,`A`],[9634,9634,`N`],[9635,9641,`A`],[9642,9649,`N`],[9650,9651,`A`],[9652,9653,`N`],[9654,9655,`A`],[9656,9659,`N`],[9660,9661,`A`],[9662,9663,`N`],[9664,9665,`A`],[9666,9669,`N`],[9670,9672,`A`],[9673,9674,`N`],[9675,9675,`A`],[9676,9677,`N`],[9678,9681,`A`],[9682,9697,`N`],[9698,9701,`A`],[9702,9710,`N`],[9711,9711,`A`],[9712,9724,`N`],[9725,9726,`W`],[9727,9732,`N`],[9733,9734,`A`],[9735,9736,`N`],[9737,9737,`A`],[9738,9741,`N`],[9742,9743,`A`],[9744,9747,`N`],[9748,9749,`W`],[9750,9755,`N`],[9756,9756,`A`],[9757,9757,`N`],[9758,9758,`A`],[9759,9791,`N`],[9792,9792,`A`],[9793,9793,`N`],[9794,9794,`A`],[9795,9799,`N`],[9800,9811,`W`],[9812,9823,`N`],[9824,9825,`A`],[9826,9826,`N`],[9827,9829,`A`],[9830,9830,`N`],[9831,9834,`A`],[9835,9835,`N`],[9836,9837,`A`],[9838,9838,`N`],[9839,9839,`A`],[9840,9854,`N`],[9855,9855,`W`],[9856,9874,`N`],[9875,9875,`W`],[9876,9885,`N`],[9886,9887,`A`],[9888,9888,`N`],[9889,9889,`W`],[9890,9897,`N`],[9898,9899,`W`],[9900,9916,`N`],[9917,9918,`W`],[9919,9919,`A`],[9920,9923,`N`],[9924,9925,`W`],[9926,9933,`A`],[9934,9934,`W`],[9935,9939,`A`],[9940,9940,`W`],[9941,9953,`A`],[9954,9954,`N`],[9955,9955,`A`],[9956,9959,`N`],[9960,9961,`A`],[9962,9962,`W`],[9963,9969,`A`],[9970,9971,`W`],[9972,9972,`A`],[9973,9973,`W`],[9974,9977,`A`],[9978,9978,`W`],[9979,9980,`A`],[9981,9981,`W`],[9982,9983,`A`],[9984,9988,`N`],[9989,9989,`W`],[9990,9993,`N`],[9994,9995,`W`],[9996,10023,`N`],[10024,10024,`W`],[10025,10044,`N`],[10045,10045,`A`],[10046,10059,`N`],[10060,10060,`W`],[10061,10061,`N`],[10062,10062,`W`],[10063,10066,`N`],[10067,10069,`W`],[10070,10070,`N`],[10071,10071,`W`],[10072,10101,`N`],[10102,10111,`A`],[10112,10132,`N`],[10133,10135,`W`],[10136,10159,`N`],[10160,10160,`W`],[10161,10174,`N`],[10175,10175,`W`],[10176,10213,`N`],[10214,10221,`Na`],[10222,10628,`N`],[10629,10630,`Na`],[10631,11034,`N`],[11035,11036,`W`],[11037,11087,`N`],[11088,11088,`W`],[11089,11092,`N`],[11093,11093,`W`],[11094,11097,`A`],[11098,11903,`N`],[11904,11929,`W`],[11930,11930,`N`],[11931,12019,`W`],[12020,12031,`N`],[12032,12245,`W`],[12246,12271,`N`],[12272,12287,`W`],[12288,12288,`F`],[12289,12350,`W`],[12351,12352,`N`],[12353,12438,`W`],[12439,12440,`N`],[12441,12543,`W`],[12544,12548,`N`],[12549,12591,`W`],[12592,12592,`N`],[12593,12686,`W`],[12687,12687,`N`],[12688,12771,`W`],[12772,12782,`N`],[12783,12830,`W`],[12831,12831,`N`],[12832,12871,`W`],[12872,12879,`A`],[12880,19903,`W`],[19904,19967,`N`],[19968,42124,`W`],[42125,42127,`N`],[42128,42182,`W`],[42183,43359,`N`],[43360,43388,`W`],[43389,44031,`N`],[44032,55203,`W`],[55204,57343,`N`],[57344,63743,`A`],[63744,64255,`W`],[64256,65023,`N`],[65024,65039,`A`],[65040,65049,`W`],[65050,65071,`N`],[65072,65106,`W`],[65107,65107,`N`],[65108,65126,`W`],[65127,65127,`N`],[65128,65131,`W`],[65132,65280,`N`],[65281,65376,`F`],[65377,65470,`H`],[65471,65473,`N`],[65474,65479,`H`],[65480,65481,`N`],[65482,65487,`H`],[65488,65489,`N`],[65490,65495,`H`],[65496,65497,`N`],[65498,65500,`H`],[65501,65503,`N`],[65504,65510,`F`],[65511,65511,`N`],[65512,65518,`H`],[65519,65532,`N`],[65533,65533,`A`],[65534,94175,`N`],[94176,94180,`W`],[94181,94191,`N`],[94192,94193,`W`],[94194,94207,`N`],[94208,100343,`W`],[100344,100351,`N`],[100352,101589,`W`],[101590,101631,`N`],[101632,101640,`W`],[101641,110575,`N`],[110576,110579,`W`],[110580,110580,`N`],[110581,110587,`W`],[110588,110588,`N`],[110589,110590,`W`],[110591,110591,`N`],[110592,110882,`W`],[110883,110897,`N`],[110898,110898,`W`],[110899,110927,`N`],[110928,110930,`W`],[110931,110932,`N`],[110933,110933,`W`],[110934,110947,`N`],[110948,110951,`W`],[110952,110959,`N`],[110960,111355,`W`],[111356,126979,`N`],[126980,126980,`W`],[126981,127182,`N`],[127183,127183,`W`],[127184,127231,`N`],[127232,127242,`A`],[127243,127247,`N`],[127248,127277,`A`],[127278,127279,`N`],[127280,127337,`A`],[127338,127343,`N`],[127344,127373,`A`],[127374,127374,`W`],[127375,127376,`A`],[127377,127386,`W`],[127387,127404,`A`],[127405,127487,`N`],[127488,127490,`W`],[127491,127503,`N`],[127504,127547,`W`],[127548,127551,`N`],[127552,127560,`W`],[127561,127567,`N`],[127568,127569,`W`],[127570,127583,`N`],[127584,127589,`W`],[127590,127743,`N`],[127744,127776,`W`],[127777,127788,`N`],[127789,127797,`W`],[127798,127798,`N`],[127799,127868,`W`],[127869,127869,`N`],[127870,127891,`W`],[127892,127903,`N`],[127904,127946,`W`],[127947,127950,`N`],[127951,127955,`W`],[127956,127967,`N`],[127968,127984,`W`],[127985,127987,`N`],[127988,127988,`W`],[127989,127991,`N`],[127992,128062,`W`],[128063,128063,`N`],[128064,128064,`W`],[128065,128065,`N`],[128066,128252,`W`],[128253,128254,`N`],[128255,128317,`W`],[128318,128330,`N`],[128331,128334,`W`],[128335,128335,`N`],[128336,128359,`W`],[128360,128377,`N`],[128378,128378,`W`],[128379,128404,`N`],[128405,128406,`W`],[128407,128419,`N`],[128420,128420,`W`],[128421,128506,`N`],[128507,128591,`W`],[128592,128639,`N`],[128640,128709,`W`],[128710,128715,`N`],[128716,128716,`W`],[128717,128719,`N`],[128720,128722,`W`],[128723,128724,`N`],[128725,128727,`W`],[128728,128731,`N`],[128732,128735,`W`],[128736,128746,`N`],[128747,128748,`W`],[128749,128755,`N`],[128756,128764,`W`],[128765,128991,`N`],[128992,129003,`W`],[129004,129007,`N`],[129008,129008,`W`],[129009,129291,`N`],[129292,129338,`W`],[129339,129339,`N`],[129340,129349,`W`],[129350,129350,`N`],[129351,129535,`W`],[129536,129647,`N`],[129648,129660,`W`],[129661,129663,`N`],[129664,129672,`W`],[129673,129679,`N`],[129680,129725,`W`],[129726,129726,`N`],[129727,129733,`W`],[129734,129741,`N`],[129742,129755,`W`],[129756,129759,`N`],[129760,129768,`W`],[129769,129775,`N`],[129776,129784,`W`],[129785,131071,`N`],[131072,196605,`W`],[196606,196607,`N`],[196608,262141,`W`],[262142,917759,`N`],[917760,917999,`A`],[918e3,983039,`N`],[983040,1048573,`A`],[1048574,1048575,`N`],[1048576,1114109,`A`],[1114110,1114111,`N`]],version=`15.1.0`;function getEAWOfCodePoint(e){let t=0,n=defs.length-1;for(;t!==n;){let r=t+(n-t>>1),[i,a,o]=defs[r];if(ea)t=r+1;else return o}return defs[t][2]}function getEAW(e,t=0){let n=e.codePointAt(t);if(n!==void 0)return getEAWOfCodePoint(n)}var defaultWidths={N:1,Na:1,W:2,F:2,H:1,A:1};function computeWidth(e,t){let n=0;for(let r of e){let e=getEAW(r);n+=t&&t[e]||defaultWidths[e]}return n}var textOffsetY=5,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function isWideChar(e){switch(getEAW(e)){case`F`:case`W`:return!0;default:return!1}}function isMacOS(){return window.navigator.userAgent.indexOf(`Mac OS X`)!==-1}function computeFontSize(e){let t=document.createElement(`canvas`).getContext(`2d`);t.font=e;let n=t.measureText(`W`);return[Math.floor(n.width),Math.round(n.fontBoundingBoxAscent+textOffsetY+(n.emHeightDescent||0)),Math.round(n.fontBoundingBoxAscent+textOffsetY)]}function drawBlock({ctx:e,x:t,y:n,width:r,height:i,style:a}){e.fillStyle=a,e.fillRect(t,n,r,i)}function drawText({ctx:e,x:t,y:n,text:r,font:i,style:a,option:o}){n+=Math.round(textOffsetY),e.fillStyle=a,e.font=i,e.textBaseline=`top`;for(let i of r)isWideChar(i)?(e.fillText(i,t,n,o.fontWidth*2),t+=o.fontWidth*2):(e.fillText(i,t,n,o.fontWidth),t+=o.fontWidth)}function drawHorizontalLine({ctx:e,x:t,y:n,width:r,style:i,lineWidth:a=1}){e.strokeStyle=i,e.lineWidth=a,e.setLineDash=[],e.beginPath(),e.moveTo(t,n),e.lineTo(t+r,n),e.stroke()}var Option=class{constructor({fontName:e,fontSize:t}){this.setFont(e,t),this.foreground=`#cccccc`,this.background=`#2d2d2d`}setFont(e,t){let n=t+`px `+e,[r,i,a]=computeFontSize(n);this.fontName=e,this.fontSize=t,this.fontWidth=r,this.fontHeight=i,this.fontAscent=a,this.font=n}};function getLemEditorElement(){return document.getElementById(`lem-editor`)}function normalizeWheelDelta(e,t,n,r){switch(n){case 0:return{dx:e/r,dy:t/r};case 2:return{dx:e*20,dy:t*20};default:return{dx:e,dy:t}}}function extractWholeLines(e,t){let n=Math.trunc(e),r=Math.trunc(t);return{scrollX:n,scrollY:r,remainderX:e-n,remainderY:t-r}}function cursorPosition(e,t){let[n,r]=t.getDisplayRectangle(),i=e.clientX-n,a=e.clientY-r;return{pixelX:i,pixelY:a,x:Math.floor(i/t.option.fontWidth),y:Math.floor(a/t.option.fontHeight)}}function makeWheelHandler(e){let t={x:0,y:0},n=!1,r={pixelX:0,pixelY:0,x:0,y:0};return i=>{i.preventDefault(),r=cursorPosition(i,e);let{dx:a,dy:o}=normalizeWheelDelta(i.deltaX,i.deltaY,i.deltaMode,e.option.fontHeight);t={x:t.x+a,y:t.y+o},n||(n=!0,requestAnimationFrame(()=>{n=!1;let{scrollX:i,scrollY:a,remainderX:o,remainderY:s}=extractWholeLines(t.x,t.y);t={x:o,y:s},(i!==0||a!==0)&&e.jsonrpc.notify(`input`,{kind:`wheel`,value:{...r,wheelX:-i,wheelY:-a}})}))}}function addMouseEventListeners({dom:e,editor:t,isDraggable:n,draggableStyle:r}){e.addEventListener(`contextmenu`,e=>{e.preventDefault()});let i=(e,n)=>{e.preventDefault();let[r,i]=t.getDisplayRectangle(),a=e.clientX-r,o=e.clientY-i,s=Math.floor(a/t.option.fontWidth),c=Math.floor(o/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:n,value:{x:s,y:c,pixelX:a,pixelY:o,button:e.button,clicks:e.detail}})};e.addEventListener(`mousedown`,e=>{n&&(document.body.style.cursor=r),t.focusHiddenInput(),i(e,`mousedown`)}),e.addEventListener(`mouseup`,e=>{n&&(document.body.style.cursor=`default`),i(e,`mouseup`)});let a=0;e.addEventListener(`mousemove`,e=>{e.preventDefault();let n=Date.now();if(n-a>50){a=n;let[r,i]=t.getDisplayRectangle(),o=e.clientX-r,s=e.clientY-i,c=Math.floor(o/t.option.fontWidth),l=Math.floor(s/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:`mousemove`,value:{x:c,y:l,pixelX:o,pixelY:s,button:e.buttons===0?null:e.buttons-1}})}}),n&&(e.addEventListener(`mouseover`,()=>{document.body.style.cursor=r}),e.addEventListener(`mouseout`,e=>{e.buttons!==1&&(document.body.style.cursor=`default`)})),e.addEventListener(`wheel`,makeWheelHandler(t))}var zIndexTable={"floating-window":200,modeline:100,"vertical-border":100,"horizontal-border":101};function zindex(e){return zIndexTable[e]||0}var borderOffsetX=5,borderOffsetY=10,BaseSurface=class{constructor({editor:e}){this.editor=e,this.mainDOM=null,this.wrapper=null}delete(){this.wrapper?getLemEditorElement().removeChild(this.wrapper):getLemEditorElement().removeChild(this.mainDOM)}setupDOM({dom:e,isFloating:t,border:n,cssClassName:r}){this.mainDOM=e,t&&n?(this.wrapper=document.createElement(`div`),r&&(this.wrapper.className=r),this.wrapper.style.position=`absolute`,this.wrapper.style.backgroundColor=this.editor.option.background,this.wrapper.style.zIndex=zindex(`floating-window`),this.wrapper.appendChild(e),getLemEditorElement().appendChild(this.wrapper)):(r&&(e.className=r),getLemEditorElement().appendChild(e))}move(e,t){let[n,r]=this.editor.getDisplayRectangle(),i=Math.floor(n+e),a=Math.floor(r+t);this.wrapper?(this.wrapper.style.left=i-borderOffsetX+`px`,this.wrapper.style.top=a-borderOffsetY+`px`,this.mainDOM.style.left=borderOffsetX+`px`,this.mainDOM.style.top=borderOffsetY+`px`):(this.mainDOM.style.left=i+`px`,this.mainDOM.style.top=a+`px`)}_resize(e,t){let n=window.devicePixelRatio||1;this.mainDOM.width=e*n,this.mainDOM.height=t*n,this.mainDOM.style.width=e+`px`,this.mainDOM.style.height=t+`px`,this.wrapper&&(this.wrapper.style.width=e+borderOffsetX*2+`px`,this.wrapper.style.height=t+borderOffsetY*2+`px`)}drawBlock(e,t,n,r,i){}drawText(e,t,n,r,i,a,o,s){}drawImage(e,t,n,r,i,a,o){}clearImages(e,t){}clearAllImages(){}touch(){}evalIn(code){return eval(code)}},CanvasSurface=class extends BaseSurface{constructor({editor:e,view:t,pixelX:n,pixelY:r,pixelWidth:i,pixelHeight:a,styles:o,isFloating:s,border:c,cssClassName:l}){super({editor:e});let u=this.setupCanvas(o);this.setupDOM({dom:u,isFloating:s,border:c,cssClassName:l}),this.move(n,r),this.resize(i,a),this.drawingQueue=[],addMouseEventListeners({dom:u,editor:e})}setupCanvas(e){let t=document.createElement(`canvas`);if(t.style.position=`absolute`,e)for(let n in e)t.style[n]=e[n];return t}resize(e,t){this._resize(e,t);let n=window.devicePixelRatio||1;this.mainDOM.getContext(`2d`).scale(n,n)}move(e,t){if(super.move(e,t),this.imageEls)for(let[,e]of this.imageEls)this.positionImage(e)}delete(){this.clearAllImages(),super.delete()}drawBlock(e,t,n,r,i){this.drawingQueue.push(function(a){drawBlock({ctx:a,x:e,y:t,width:n,height:r,style:i})})}drawText(e,t,n,r,i,a,o,s){let c=this.editor.option,l=o??t,u=s??c.fontHeight;this.drawingQueue.push(function(o){if(a=a?`${c.fontSize}px ${a}`:c.font,!i)drawBlock({ctx:o,x:e,y:l,width:r,height:u,style:c.background}),drawText({ctx:o,x:e,y:t,text:n,style:c.foreground,font:a,option:c});else{let{foreground:s,background:d,bold:f,reverse:p,underline:m,cursor:h}=i;if(s||=c.foreground,d||=c.background,p){let e=d;d=s,s=e}h&&(d=c.background),drawBlock({ctx:o,x:e,y:l,width:r,height:u,style:d}),drawText({ctx:o,x:e,y:t,text:n,style:s,font:f?`bold `+a:a,option:c}),m&&drawHorizontalLine({ctx:o,x:e,y:t+c.fontHeight-2,width:r,style:typeof m==`string`?m:s,lineWidth:2})}})}imageBaseLeft(){return parseFloat(this.mainDOM.style.left)||0}imageBaseTop(){return parseFloat(this.mainDOM.style.top)||0}drawImage(e,t,n,r,i,a,o){this.imageEls||=new Map;let s=e+`,`+t,c=this.imageEls.get(s);if(c&&c.url!==o&&(c.el.remove(),this.imageEls.delete(s),c=null),!c){let e=document.createElement(`img`);e.style.position=`absolute`,e.style.pointerEvents=`none`,e.style.zIndex=`1`,e.src=o,this.mainDOM.parentNode.appendChild(e),c={el:e,url:o},this.imageEls.set(s,c)}c.x=e,c.y=t,c.width=n,c.height=r,c.clipWidth=i,c.clipHeight=a,this.positionImage(c)}positionImage(e){e.el.style.left=this.imageBaseLeft()+e.x+`px`,e.el.style.top=this.imageBaseTop()+e.y+`px`,e.el.style.width=e.width+`px`,e.el.style.height=e.height+`px`;let t=e.clipWidth==null?0:Math.max(0,e.width-e.clipWidth),n=e.clipHeight==null?0:Math.max(0,e.height-e.clipHeight);e.el.style.clipPath=t>0||n>0?`inset(0px ${t}px ${n}px 0px)`:``}clearImages(e,t){if(this.imageEls)for(let[n,r]of this.imageEls){let i=r.y+(r.height||0);r.ye&&(r.el.remove(),this.imageEls.delete(n))}}clearAllImages(){if(this.imageEls){for(let[,e]of this.imageEls)e.el.remove();this.imageEls.clear()}}touch(){let e=this.mainDOM.getContext(`2d`);for(let t of this.drawingQueue)t(e);this.drawingQueue=[]}activate(){this.mainDOM.dataset.store=`active`}deactivate(){this.mainDOM.dataset.store=`inactive`}},HTMLSurface=class extends BaseSurface{constructor({editor:e,pixelX:t,pixelY:n,pixelWidth:r,pixelHeight:i,styles:a,option:o,isFloating:s,border:c,html:l}){super({editor:e});let u=document.createElement(`iframe`);this.setupDOM({dom:u,isFloating:s,border:c}),u.style.position=`absolute`,u.style.backgroundColor=o.background,u.setAttribute(`sandbox`,`allow-scripts allow-same-origin`),u.srcdoc=l,u.addEventListener(`load`,()=>{let e=u.contentWindow;e.invokeLem=(e,t)=>parent.postMessage({type:`invoke-lem`,method:e,args:t})}),this.iframe=u,this.move(t,n),this.resize(r,i)}resize(e,t){this._resize(e,t)}update(e){let t=this.iframe.contentWindow.scrollY;this.iframe.srcdoc=e,this.iframe.onload=()=>{this.iframe.onload=null,this.iframe.contentWindow.scrollTo(0,t)}}evalIn(e){return this.iframe.contentWindow.eval(e)}},VerticalBorder=class{constructor({x:e,y:t,height:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__vertical-border`,this.line.style.height=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`vertical-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`col-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=Math.floor(n+e-this.option.fontWidth/2)+`px`,this.line.style.top=r+t+`px`}resize(e){this.line.style.height=e+`px`}},HorizontalBorder=class{constructor({x:e,y:t,width:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__horizontal-border`,this.line.style.width=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`horizontal-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`row-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=n+e+`px`,this.line.style.top=Math.floor(r+t-4)+`px`}resize(e){this.line.style.width=e+`px`}},viewStyles={header:()=>{},tile:()=>{},floating:e=>({boxSizing:`border-box`,borderColor:e.foreground,backgroundColor:e.background})};function getViewStyle(e,t){return viewStyles[e](t)||{}}var View=class{constructor({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,option:h,editor:g}){switch(this.option=h,this.id=e,this.x=t,this.y=n,this.width=r,this.height=i,this.pixelX=a,this.pixelY=o,this.pixelWidth=s,this.pixelHeight=c,this.useModeline=l,this.kind=u,this.type=d,this.border=p,this.borderShape=m,this.editor=g,this.bottomBar=null,this.leftsideBar=null,u){case`tile`:this.mainSurface=this.makeSurface(d,f),this.leftSideBar=new VerticalBorder({x:a,y:o,height:c+(l?h.fontHeight:0),option:h,editor:g}),l||(this.bottomBar=new HorizontalBorder({x:a,y:o+c-h.fontHeight,width:s,option:h,editor:g}));break;case`header`:this.mainSurface=this.makeSurface(d,f);break;case`floating`:this.mainSurface=this.makeSurface(d,f),m===`left-border`&&(this.leftSideBar=new VerticalBorder({x:a,y:o,height:c,option:h,editor:g}));break}this.modelineSurface=l?this.makeModelineSurface():null}delete(){this.mainSurface.delete(),this.modelineSurface&&this.modelineSurface.delete(),this.leftSideBar&&this.leftSideBar.delete(),this.bottomBar&&this.bottomBar.delete()}move(e,t,n,r){this.x=e,this.y=t,this.pixelX=n,this.pixelY=r,this.mainSurface.move(n,r),this.modelineSurface&&this.modelineSurface.move(n,r+this.pixelHeight),this.leftSideBar&&this.leftSideBar.move(n,r),this.bottomBar&&this.bottomBar.move(n,r+this.pixelHeight)}resize(e,t,n,r){this.width=e,this.height=t,this.pixelWidth=n,this.pixelHeight=r,this.mainSurface.resize(n,r),this.modelineSurface&&(this.modelineSurface.move(this.pixelX,this.pixelY+r),this.modelineSurface.resize(n,this.option.fontHeight)),this.leftSideBar&&this.leftSideBar.resize(r+(this.modelineSurface?this.option.fontHeight:0)),this.bottomBar&&this.bottomBar.resize(n)}clear(){this.mainSurface.drawBlock(0,0,this.pixelWidth,this.pixelHeight,this.option.background),this.mainSurface.clearImages(0,this.pixelHeight)}clearEol(e,t,n){n??=this.option.fontHeight,this.mainSurface.drawBlock(e,t,this.pixelWidth-e,n,this.option.background),this.mainSurface.clearImages(t,t+n)}clearEob(e,t){this.mainSurface.drawBlock(e,t,this.pixelWidth,this.pixelHeight-t,this.option.background),this.mainSurface.clearImages(t,this.pixelHeight)}print(e,t,n,r,i,a,o,s){this.mainSurface.drawText(e,t,n,r,i,a,o,s)}drawBlock(e,t,n,r,i){this.mainSurface.drawBlock(e,t,n,r,i||this.option.background)}drawBlockOnModeline(e,t,n,r,i){this.modelineSurface&&this.modelineSurface.drawBlock(e,t,n,r,i||this.option.background)}printImage(e,t,n,r,i,a,o){this.mainSurface.drawImage(e,t,n,r,i,a,o)}printToModeline(e,t,n,r,i,a,o){this.modelineSurface&&this.modelineSurface.drawText(e,t,n,r,i,null,a,o)}touch(e){this.mainSurface.touch(),this.modelineSurface&&(this.modelineSurface.touch(),e?this.modelineSurface.activate():this.modelineSurface.deactivate())}makeSurface(e,t){switch(e){case`html`:return this.makeHTMLSurface(t);case`editor`:return this.makeEditorSurface();default:console.error(`unknown type: ${e}`)}}makeHTMLSurface(e){return new HTMLSurface({editor:this.editor,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),option:this.option,isFloating:this.kind===`floating`,border:this.border,html:e})}makeEditorSurface(){let e=this.borderShape===`left-border`?0:this.border,t=this.kind===`floating`;return new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),editor:this.editor,border:e,isFloating:t,view:this,cssClassName:t&&e?`lem-editor__floating-window--bordered`:null})}makeModelineSurface(){let e=new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY+this.pixelHeight,pixelWidth:this.pixelWidth,pixelHeight:this.option.fontHeight,editor:this.editor,view:this,styles:{zIndex:zindex(`modeline`)},cssClassName:`lem-editor__mode-line`});return addMouseEventListeners({dom:e.mainDOM,editor:this.editor,isDraggable:!0,draggableStyle:`row-resize`}),e}changeToHTMLContent(e){this.mainSurface.constructor.name===`HTMLSurface`?this.mainSurface.update(e):(this.mainSurface.delete(),this.mainSurface=this.makeHTMLSurface(e))}changeToEditorContent(){this.mainSurface.delete(),this.mainSurface=this.makeEditorSurface()}evalIn(e){return this.mainSurface.evalIn(e)}};function isPasteKeyEvent(e){return isMacOS()?e.metaKey&&e.key===`v`:e.ctrlKey&&e.shiftKey&&e.key===`V`}var Input=class{constructor(e){let t=e.option;this.editor=e,this.composition=!1,this.ignoreKeydownAfterCompositionend=!1,this.span=document.createElement(`span`),this.span.style.color=t.foreground,this.span.style.backgroundColor=t.background,this.span.style.position=`absolute`,this.span.style.zIndex=1e6,this.span.style.top=`0`,this.span.style.left=`0`,this.span.style.font=t.font,this.input=document.createElement(`input`),this.input.style.backgroundColor=`transparent`,this.input.style.color=`transparent`,this.input.style.width=`0`,this.input.style.padding=`0`,this.input.style.margin=`0`,this.input.style.border=`none`,this.input.style.position=`absolute`,this.input.style.zIndex=`-10`,this.input.style.top=`0`,this.input.style.left=`0`,this.input.style.font=t.font,this.input.addEventListener(`blur`,e=>{this.input.focus()}),this.input.addEventListener(`input`,e=>{this.composition===!1&&(this.input.value=``,this.span.innerHTML=``,this.input.style.width=`0`,isMacOS()||this.editor.emitInputString(e.data))}),this.input.addEventListener(`paste`,async e=>{e.preventDefault();let t=e.clipboardData||window.Clipboard.data,n=t?.getData(`text`)??t?.getData(`text/plain`);if(n&&n.length>0){this.editor.emitInputString(n);return}try{if(navigator.clipboard?.readText){let e=await navigator.clipboard.readText();if(e&&e.length>0){this.editor.emitInputString(e);return}}}catch(e){console.warn(`clipboard.readText() failed:`,e)}alert(`Paste failed (permission/environment restriction`)}),this.input.addEventListener(`keydown`,e=>{if(!isPasteKeyEvent(e)&&!(e.isComposing||this.composition)&&e.key!==`Process`){if(this.ignoreKeydownAfterCompositionend&&(isSafari||isMacOS())){e.preventDefault(),this.ignoreKeydownAfterCompositionend=!1;return}if(!(!isMacOS()&&!e.ctrlKey&&!e.altKey&&e.key.length===1)&&(e.preventDefault(),e.isComposing!==!0&&e.code!==``))return setTimeout(()=>{this.composition||(this.editor.emitInput(e),this.input.value=``)},0),!1}}),this.input.addEventListener(`compositionstart`,e=>{this.composition=!0,this.span.innerHTML=this.input.value,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionupdate`,e=>{this.span.innerHTML=e.data,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionend`,e=>{this.composition=!1,this.editor.emitInputString(this.input.value),this.input.value=``,this.span.innerHTML=this.input.value,this.input.style.width=`0`,this.ignoreKeydownAfterCompositionend=!0}),document.body.appendChild(this.input),document.body.appendChild(this.span),this.input.focus()}finalize(){document.body.removeChild(this.input),document.body.removeChild(this.span)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.span.style.top=r+t+`px`,this.span.style.left=n+e+`px`,this.input.style.top=this.span.offsetTop+`px`,this.input.style.left=this.span.offsetLeft+`px`}updateForeground(e){this.span.style.color=e}updateBackground(e){this.span.style.backgroundColor=e}},MessageTable=class{constructor(){this.map=new Map}register(e,t){for(let n in t){let r=t[n];this.map.set(n,r),e.on(n,r)}}get(e){return this.map.get(e)}};function getDisplayRectangleDefault(){return[0,0,window.innerWidth,window.innerHeight]}var Editor=class{constructor({getDisplayRectangle:e=getDisplayRectangleDefault,fontName:t,fontSize:n,url:r,onExit:i,onClosed:a}){this.getDisplayRectangle=e,this.option=new Option({fontName:t,fontSize:n}),this.onExit=i,this.input=new Input(this),this.cursors=new Map,this.cursorOverlay=document.createElement(`div`),this.cursorOverlay.className=`lem-cursor`,this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.cursorOverlay.style.backgroundColor=`#ffffff`,this.cursorType=`box`,this.viewMap=new Map,this.jsonrpc=new JSONRPC(r,{onClosed:()=>{a()}}),this.messageTable=new MessageTable,this.messageTable.register(this.jsonrpc,{"update-foreground":this.updateForeground.bind(this),"update-background":this.updateBackground.bind(this),"make-view":this.makeView.bind(this),"delete-view":this.deleteView.bind(this),"resize-view":this.resize.bind(this),"move-view":this.move.bind(this),"redraw-view-after":this.redrawViewAfter.bind(this),clear:this.clear.bind(this),"clear-eol":this.clearEol.bind(this),"clear-eob":this.clearEob.bind(this),put:this.put.bind(this),"put-image":this.putImage.bind(this),"modeline-put":this.modelinePut.bind(this),"draw-block":this.drawBlock.bind(this),"modeline-draw-block":this.modelineDrawBlock.bind(this),"update-display":this.updateDisplay.bind(this),"move-cursor":this.moveCursor.bind(this),"change-view":this.changeView.bind(this),"resize-display":this.resizeDisplay.bind(this),bulk:this.bulk.bind(this),exit:this.exitEditor.bind(this),"get-clipboard-text":this.getClipboardText.bind(this),"set-clipboard-text":this.setClipboardText.bind(this),"js-eval":this.jsEval.bind(this),"set-font":this.setFont.bind(this),"get-font":this.getFont.bind(this),"get-display-size":this.getDisplaySize.bind(this),"load-css":this.loadCSS.bind(this),"update-cursor-shape":this.updateCursorShape.bind(this)}),this.login(),this.boundedHandleResize=this.handleResize.bind(this),this.focusHiddenInput=this.focusHiddenInput.bind(this)}init(){window.addEventListener(`resize`,this.boundedHandleResize),document.getElementsByTagName(`html`)[0].style[`background-color`]=`#333`,getLemEditorElement().appendChild(this.cursorOverlay)}finalize(){window.removeEventListener(`resize`,this.boundedHandleResize),this.input.finalize(),this.cursorOverlay.parentNode&&this.cursorOverlay.parentNode.removeChild(this.cursorOverlay)}closeConnection(){this.jsonrpc.close()}emitInput(e){let t=convertKeyEvent(e);if(t){if(t.key===`]`&&t.ctrl&&!t.meta&&!t.super&&!t.shift){this.jsonrpc.notify(`input`,{kind:`abort`});return}t.key!==`Unidentified`&&this.jsonrpc.notify(`input`,{kind:`key`,value:t})}}emitInputString(e){e?this.jsonrpc.notify(`input`,{kind:`input-string`,value:e}):console.error(`unexpected argument`,e)}redrawParams(){return{size:this.getDisplaySize(),fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent}}handleResize(e){this.jsonrpc.notify(`redraw`,this.redrawParams())}focusHiddenInput(){let e=this.input?.input;if(e){try{window.focus()}catch{}requestAnimationFrame(()=>{setTimeout(()=>{e.focus({preventScroll:!0})},0)})}}sendNotification(e,t){this.jsonrpc.notify(e,t)}request(e,t,n){this.jsonrpc.request(e,t,n)}getDisplaySize(){let[e,t,n,r]=this.getDisplayRectangle();return{width:Math.floor(n/this.option.fontWidth),height:Math.floor(r/this.option.fontHeight)}}callMessage(e,t){this.messageTable.get(e)(t)}findViewById(e){return this.viewMap.get(e)}login(){this.jsonrpc.request(`login`,{size:this.getDisplaySize(),foreground:this.option.foreground,background:this.option.background,fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent},e=>{if(this.updateForeground(e.foreground),this.updateBackground(e.background),e.views)for(let t of e.views)this.makeView(t);this.jsonrpc.notify(`redraw`,this.redrawParams())})}updateForeground(e){e!=null&&(this.option.foreground=e,this.input.updateForeground(e))}updateBackground(e){if(e==null)return;this.option.background=e,this.input.updateBackground(e);let t=getLemEditorElement();t.style.backgroundColor=e}makeView({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,use_modeline:l,kind:u,type:d,content:f,border:p,border_shape:m}){let h=new View({option:this.option,id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,editor:this});this.viewMap.set(e,h)}deleteView({viewInfo:{id:e}}){this.findViewById(e).delete(),this.viewMap.delete(e)}resize({viewInfo:{id:e},width:t,height:n,pixelWidth:r,pixelHeight:i}){let a=this.findViewById(e);a?a.resize(t,n,r,i):console.warn(`resize: view not found for id ${e}`)}move({viewInfo:{id:e},x:t,y:n,pixelX:r,pixelY:i}){let a=this.findViewById(e);a?a.move(t,n,r,i):console.warn(`move: view not found for id ${e}`)}redrawViewAfter({viewInfo:{id:e},isActive:t}){this.findViewById(e).touch(t)}clear({viewInfo:{id:e}}){this.findViewById(e).clear()}clearEol({viewInfo:{id:e},x:t,y:n,height:r}){this.findViewById(e).clearEol(t,n,r)}clearEob({viewInfo:{id:e},x:t,y:n}){this.findViewById(e).clearEob(t,n)}put({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,font:o,backgroundY:s,backgroundHeight:c}){this.findViewById(e).print(t,n,r,i,a,o,s,c)}drawBlock({viewInfo:{id:e},x:t,y:n,width:r,height:i,color:a}){this.findViewById(e).drawBlock(t,n,r,i,a)}modelineDrawBlock({viewInfo:{id:e},x:t,y:n,width:r,height:i,color:a}){this.findViewById(e).drawBlockOnModeline(t,n,r,i,a)}putImage({viewInfo:{id:e},x:t,y:n,pixelWidth:r,pixelHeight:i,clipWidth:a,clipHeight:o,url:s}){this.findViewById(e).printImage(t,n,r,i,a,o,s)}modelinePut({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,backgroundY:o,backgroundHeight:s}){this.findViewById(e).printToModeline(t,n,r,i,a,o,s)}updateDisplay(){}moveCursor({viewInfo:{id:e},x:t,y:n,color:r,cursorText:i,cursorForeground:a}){let o=this.findViewById(e),[s,c]=this.getDisplayRectangle(),l=o.pixelX+t,u=o.pixelY+n;this.input.move(l,u);let d=r||this.option.foreground,f=a||this.option.background,p=this.cursorOverlay;switch(this.cursorType){case`bar`:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=`2px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;case`underline`:p.style.left=s+l+`px`,p.style.top=c+u+this.option.fontHeight-2+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=`2px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;default:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.style.font=this.option.font,p.style.paddingTop=textOffsetY+`px`,p.textContent=i||``,p.style.color=f;break}p.style.animation=`none`,p.offsetHeight,p.style.animation=``}updateCursorShape({cursorType:e}){this.cursorType=e||`box`}changeView({viewInfo:{id:e},type:t,content:n}){let r=this.findViewById(e);switch(t){case`html`:r.changeToHTMLContent(n);break;case`editor`:r.changeToEditorContent();break}}resizeDisplay({width:e,height:t}){let n=getLemEditorElement();n.style.width=Math.floor(e*this.option.fontWidth)+`px`,n.style.height=Math.floor(t*this.option.fontHeight)+`px`}bulk(e){for(let{method:t,argument:n}of e)this.callMessage(t,n)}exitEditor(){this.onExit&&this.onExit()}getClipboardText(){navigator.clipboard?.readText().then(e=>{this.jsonrpc.notify(`got-clipboard-text`,{text:e})})}setClipboardText({text:e}){navigator.clipboard&&navigator.clipboard.writeText(e)}jsEval({viewInfo:{id:e},code:t}){let n=this.findViewById(e).evalIn(t);return n&&n.toString()}setFont({fontName:e,fontSize:t}){this.option.setFont(e||this.option.fontName,t||this.option.fontSize),this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.jsonrpc.notify(`redraw`,this.redrawParams())}getFont(){return{name:this.option.fontName,size:this.option.fontSize}}loadCSS({content:e}){let t=document.createElement(`style`);t.textContent=e,document.head.appendChild(t)}notifyToServer(e,t){this.jsonrpc.notify(`invoke`,{method:e,args:t})}},canvas=document.querySelector(`#editor`);async function main(){await Promise.all([document.fonts.load(`19px file-icons`),document.fonts.load(`19px AllTheIcons`),document.fonts.load(`19px fontawesome`),document.fonts.load(`19px material-design-icons`),document.fonts.load(`19px octicons`)]),await document.fonts.ready;let e=new Editor({canvas,fontName:`Monospace`,fontSize:18,url:`${window.location.protocol===`https:`?`wss`:`ws`}://${window.location.hostname}:${window.location.port}`,onExit:null,onClosed:null});window.addEventListener(`message`,t=>{t.data.type===`invoke-lem`&&e.notifyToServer(t.data.method,t.data.args)}),e.init()}main(); \ No newline at end of file +var __defProp=Object.defineProperty,__commonJSMin=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),__exportAll=(e,t)=>{let n={};for(var r in e)__defProp(n,r,{get:e[r],enumerable:!0});return t||__defProp(n,Symbol.toStringTag,{value:`Module`}),n};(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var require_models=__commonJSMin((e=>{var t=e&&e.__extends||(function(){var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};return function(t,n){if(typeof n!=`function`&&n!==null)throw TypeError(`Class extends value `+String(n)+` is not a constructor or null`);e(t,n);function r(){this.constructor=t}t.prototype=n===null?Object.create(n):(r.prototype=n.prototype,new r)}})();Object.defineProperty(e,"__esModule",{value:!0}),e.createJSONRPCNotification=e.createJSONRPCRequest=e.createJSONRPCSuccessResponse=e.createJSONRPCErrorResponse=e.JSONRPCErrorCode=e.JSONRPCErrorException=e.isJSONRPCResponses=e.isJSONRPCResponse=e.isJSONRPCRequests=e.isJSONRPCRequest=e.isJSONRPCID=e.JSONRPC=void 0,e.JSONRPC=`2.0`,e.isJSONRPCID=function(e){return typeof e==`string`||typeof e==`number`||e===null},e.isJSONRPCRequest=function(t){return t.jsonrpc===e.JSONRPC&&t.method!==void 0&&t.result===void 0&&t.error===void 0},e.isJSONRPCRequests=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCRequest)},e.isJSONRPCResponse=function(t){return t.jsonrpc===e.JSONRPC&&t.id!==void 0&&(t.result!==void 0||t.error!==void 0)},e.isJSONRPCResponses=function(t){return Array.isArray(t)&&t.every(e.isJSONRPCResponse)};var n=function(e,t,n){var r={code:e,message:t};return n!=null&&(r.data=n),r};e.JSONRPCErrorException=function(e){t(r,e);function r(t,n,i){var a=e.call(this,t)||this;return Object.setPrototypeOf(a,r.prototype),a.code=n,a.data=i,a}return r.prototype.toObject=function(){return n(this.code,this.message,this.data)},r}(Error),(function(e){e[e.ParseError=-32700]=`ParseError`,e[e.InvalidRequest=-32600]=`InvalidRequest`,e[e.MethodNotFound=-32601]=`MethodNotFound`,e[e.InvalidParams=-32602]=`InvalidParams`,e[e.InternalError=-32603]=`InternalError`})(e.JSONRPCErrorCode||={}),e.createJSONRPCErrorResponse=function(t,r,i,a){return{jsonrpc:e.JSONRPC,id:t,error:n(r,i,a)}},e.createJSONRPCSuccessResponse=function(t,n){return{jsonrpc:e.JSONRPC,id:t,result:n??null}},e.createJSONRPCRequest=function(t,n,r){return{jsonrpc:e.JSONRPC,id:t,method:n,params:r}},e.createJSONRPCNotification=function(t,n){return{jsonrpc:e.JSONRPC,method:t,params:n}}})),require_internal=__commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.DefaultErrorCode=void 0,e.DefaultErrorCode=0})),require_client=__commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{Object.defineProperty(e,"__esModule",{value:!0})})),require_server=__commonJSMin((e=>{var t=e&&e.__assign||function(){return t=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__awaiter||function(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})},n=e&&e.__generator||function(e,t){var n={label:0,sent:function(){if(a[0]&1)throw a[1];return a[1]},trys:[],ops:[]},r,i,a,o;return o={next:s(0),throw:s(1),return:s(2)},typeof Symbol==`function`&&(o[Symbol.iterator]=function(){return this}),o;function s(e){return function(t){return c([e,t])}}function c(s){if(r)throw TypeError(`Generator is already executing.`);for(;o&&(o=0,s[0]&&(n=0)),n;)try{if(r=1,i&&(a=s[0]&2?i.return:s[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,s[1])).done)return a;switch(i=0,a&&(s=[s[0]&2,a.value]),s[0]){case 0:case 1:a=s;break;case 4:return n.label++,{value:s[1],done:!1};case 5:n.label++,i=s[1],s=[0];continue;case 7:s=n.ops.pop(),n.trys.pop();continue;default:if((a=n.trys,!(a=a.length>0&&a[a.length-1]))&&(s[0]===6||s[0]===2)){n=0;continue}if(s[0]===3&&(!a||s[1]>a[0]&&s[1]{var t=e&&e.__createBinding||(Object.create?(function(e,t,n,r){r===void 0&&(r=n);var i=Object.getOwnPropertyDescriptor(t,n);(!i||(`get`in i?!t.__esModule:i.writable||i.configurable))&&(i={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,i)}):(function(e,t,n,r){r===void 0&&(r=n),e[r]=t[n]})),n=e&&e.__exportStar||function(e,n){for(var r in e)r!=="default"&&!Object.prototype.hasOwnProperty.call(n,r)&&t(n,e,r)};Object.defineProperty(e,"__esModule",{value:!0}),n(require_client(),e),n(require_interfaces(),e),n(require_models(),e),n(require_server(),e),n(require_server_and_client(),e)})),import_dist=require_dist(),JSONRPC=class{constructor(e,{onConnected:t,onClosed:n}){this.url=e,this.onConnected=t,this.onClosed=n,this.messageQueue=[],this.serverAndClient=null,this.connect(),this.connectionEstablished=!1,this.timerId=null,this.closed=!1}close(){this.timerId&&clearTimeout(this.timerId),this.webSocket.close(),this.closed=!0}on(e,t){this.serverAndClient.addMethod(e,t)}async requestInternal(e,t,n){let r=await this.serverAndClient.request(e,t);n&&n(r)}requestMessageQueue(){this.messageQueue.forEach(e=>{let[t,n,r]=e;this.requestInternal(t,n,r)}),this.messageQueue=[]}request(e,t,n){this.webSocket.readyState===WebSocket.OPEN?this.requestInternal(e,t,n):this.messageQueue.push([e,t,n])}notify(e,t){switch(this.webSocket.readyState){case WebSocket.OPEN:this.serverAndClient.notify(e,t);break;case WebSocket.CLOSED:break}}connect(e){this.closed||(console.log(`connect`,this.url),this.webSocket=new WebSocket(this.url),this.serverAndClient||=new import_dist.JSONRPCServerAndClient(new import_dist.JSONRPCServer,new import_dist.JSONRPCClient(e=>{try{return this.webSocket.send(JSON.stringify(e)),Promise.resolve()}catch(e){return Promise.reject(e)}})),this.webSocket.onmessage=e=>{this.serverAndClient.receiveAndSend(JSON.parse(e.data.toString()))},this.webSocket.onopen=()=>{console.log(`WebSocket connection established`),this.connectionEstablished=!0,this.onConnected&&this.onConnected(),this.requestMessageQueue()},this.webSocket.onclose=e=>{console.error(`WebScoket closed`,e),this.serverAndClient.rejectAllPendingRequests(`Connection is closed (${e.reason}).`),this.connectionEstablished&&this.onClosed(),this.timerId=setTimeout(()=>{this.connect()},3e3)},this.webSocket.onerror=e=>{console.error(`WebSocket error:`,e),this.webSocket.close()})}},keyevent_exports=__exportAll({convertKeyEvent:()=>convertKeyEvent}),modifierKeys=[`Shift`,`Control`,`Alt`,`Meta`,`CapsLock`],convertKeyTable={Enter:`Return`,ArrowRight:`Right`,ArrowLeft:`Left`,ArrowUp:`Up`,ArrowDown:`Down`,"¡":`1`,"™":`2`,"£":`3`,"¢":`4`,"∞":`5`,"§":`6`,"¶":`7`,"•":`8`,ª:`9`,º:`0`,"–":`-`,"≠":`=`,"“":`[`,"‘":`]`,"«":`\\`,"…":`;`,æ:`'`,"≤":`,`,"≥":`.`,"÷":`/`,"⁄":`!`,"€":`@`,"‹":`#`,"›":`$`,fi:`%`,fl:`^`,"‡":`&`,"°":`*`,"·":`(`,"‚":`)`,"—":`_`,"±":`+`,"”":`{`,"’":`}`,"»":`|`,Ú:`:`,Æ:`"`,"¯":`<`,"˘":`>`,"¿":`?`,œ:`q`,"∑":`w`,"´":`e`,"®":`r`,"†":`t`,"¥":`y`,"¨":`u`,ˆ:`i`,ø:`o`,π:`p`,å:`a`,ß:`s`,"∂":`d`,ƒ:`f`,"©":`g`,"˙":`h`,"∆":`j`,"˚":`k`,"¬":`l`,Ω:`z`,"≈":`x`,ç:`c`,"√":`v`,"∫":`b`,"˜":`n`,µ:`m`,Œ:`Q`,"„":`W`,"´":`E`,"‰":`R`,ˇ:`T`,Á:`Y`,"¨":`U`,ˆ:`I`,Ø:`O`,"∏":`P`,Å:`A`,Í:`S`,Î:`D`,Ï:`F`,"˝":`G`,Ó:`H`,Ô:`J`,"":`K`,Ò:`L`,"¸":`Z`,"˛":`X`,Ç:`C`,"◊":`V`,ı:`B`,"˜":`N`,Â:`M`};function getKey(e){return e.altKey?convertKeyTable[e.key]||(e.code.startsWith(`Key`)?e.code[3].toLowerCase():null)||e.key:convertKeyTable[e.key]||e.key}function convertKeyEvent(e){return modifierKeys.indexOf(e.key)===-1?{key:getKey(e),ctrl:e.ctrlKey,meta:e.altKey,super:e.metaKey,shift:e.shiftKey}:null}var lib_exports=__exportAll({computeWidth:()=>computeWidth,eawVersion:()=>version,getEAW:()=>getEAW}),defs=[[0,31,`N`],[32,126,`Na`],[127,160,`N`],[161,161,`A`],[162,163,`Na`],[164,164,`A`],[165,166,`Na`],[167,168,`A`],[169,169,`N`],[170,170,`A`],[171,171,`N`],[172,172,`Na`],[173,174,`A`],[175,175,`Na`],[176,180,`A`],[181,181,`N`],[182,186,`A`],[187,187,`N`],[188,191,`A`],[192,197,`N`],[198,198,`A`],[199,207,`N`],[208,208,`A`],[209,214,`N`],[215,216,`A`],[217,221,`N`],[222,225,`A`],[226,229,`N`],[230,230,`A`],[231,231,`N`],[232,234,`A`],[235,235,`N`],[236,237,`A`],[238,239,`N`],[240,240,`A`],[241,241,`N`],[242,243,`A`],[244,246,`N`],[247,250,`A`],[251,251,`N`],[252,252,`A`],[253,253,`N`],[254,254,`A`],[255,256,`N`],[257,257,`A`],[258,272,`N`],[273,273,`A`],[274,274,`N`],[275,275,`A`],[276,282,`N`],[283,283,`A`],[284,293,`N`],[294,295,`A`],[296,298,`N`],[299,299,`A`],[300,304,`N`],[305,307,`A`],[308,311,`N`],[312,312,`A`],[313,318,`N`],[319,322,`A`],[323,323,`N`],[324,324,`A`],[325,327,`N`],[328,331,`A`],[332,332,`N`],[333,333,`A`],[334,337,`N`],[338,339,`A`],[340,357,`N`],[358,359,`A`],[360,362,`N`],[363,363,`A`],[364,461,`N`],[462,462,`A`],[463,463,`N`],[464,464,`A`],[465,465,`N`],[466,466,`A`],[467,467,`N`],[468,468,`A`],[469,469,`N`],[470,470,`A`],[471,471,`N`],[472,472,`A`],[473,473,`N`],[474,474,`A`],[475,475,`N`],[476,476,`A`],[477,592,`N`],[593,593,`A`],[594,608,`N`],[609,609,`A`],[610,707,`N`],[708,708,`A`],[709,710,`N`],[711,711,`A`],[712,712,`N`],[713,715,`A`],[716,716,`N`],[717,717,`A`],[718,719,`N`],[720,720,`A`],[721,727,`N`],[728,731,`A`],[732,732,`N`],[733,733,`A`],[734,734,`N`],[735,735,`A`],[736,767,`N`],[768,879,`A`],[880,912,`N`],[913,929,`A`],[930,930,`N`],[931,937,`A`],[938,944,`N`],[945,961,`A`],[962,962,`N`],[963,969,`A`],[970,1024,`N`],[1025,1025,`A`],[1026,1039,`N`],[1040,1103,`A`],[1104,1104,`N`],[1105,1105,`A`],[1106,4351,`N`],[4352,4447,`W`],[4448,8207,`N`],[8208,8208,`A`],[8209,8210,`N`],[8211,8214,`A`],[8215,8215,`N`],[8216,8217,`A`],[8218,8219,`N`],[8220,8221,`A`],[8222,8223,`N`],[8224,8226,`A`],[8227,8227,`N`],[8228,8231,`A`],[8232,8239,`N`],[8240,8240,`A`],[8241,8241,`N`],[8242,8243,`A`],[8244,8244,`N`],[8245,8245,`A`],[8246,8250,`N`],[8251,8251,`A`],[8252,8253,`N`],[8254,8254,`A`],[8255,8307,`N`],[8308,8308,`A`],[8309,8318,`N`],[8319,8319,`A`],[8320,8320,`N`],[8321,8324,`A`],[8325,8360,`N`],[8361,8361,`H`],[8362,8363,`N`],[8364,8364,`A`],[8365,8450,`N`],[8451,8451,`A`],[8452,8452,`N`],[8453,8453,`A`],[8454,8456,`N`],[8457,8457,`A`],[8458,8466,`N`],[8467,8467,`A`],[8468,8469,`N`],[8470,8470,`A`],[8471,8480,`N`],[8481,8482,`A`],[8483,8485,`N`],[8486,8486,`A`],[8487,8490,`N`],[8491,8491,`A`],[8492,8530,`N`],[8531,8532,`A`],[8533,8538,`N`],[8539,8542,`A`],[8543,8543,`N`],[8544,8555,`A`],[8556,8559,`N`],[8560,8569,`A`],[8570,8584,`N`],[8585,8585,`A`],[8586,8591,`N`],[8592,8601,`A`],[8602,8631,`N`],[8632,8633,`A`],[8634,8657,`N`],[8658,8658,`A`],[8659,8659,`N`],[8660,8660,`A`],[8661,8678,`N`],[8679,8679,`A`],[8680,8703,`N`],[8704,8704,`A`],[8705,8705,`N`],[8706,8707,`A`],[8708,8710,`N`],[8711,8712,`A`],[8713,8714,`N`],[8715,8715,`A`],[8716,8718,`N`],[8719,8719,`A`],[8720,8720,`N`],[8721,8721,`A`],[8722,8724,`N`],[8725,8725,`A`],[8726,8729,`N`],[8730,8730,`A`],[8731,8732,`N`],[8733,8736,`A`],[8737,8738,`N`],[8739,8739,`A`],[8740,8740,`N`],[8741,8741,`A`],[8742,8742,`N`],[8743,8748,`A`],[8749,8749,`N`],[8750,8750,`A`],[8751,8755,`N`],[8756,8759,`A`],[8760,8763,`N`],[8764,8765,`A`],[8766,8775,`N`],[8776,8776,`A`],[8777,8779,`N`],[8780,8780,`A`],[8781,8785,`N`],[8786,8786,`A`],[8787,8799,`N`],[8800,8801,`A`],[8802,8803,`N`],[8804,8807,`A`],[8808,8809,`N`],[8810,8811,`A`],[8812,8813,`N`],[8814,8815,`A`],[8816,8833,`N`],[8834,8835,`A`],[8836,8837,`N`],[8838,8839,`A`],[8840,8852,`N`],[8853,8853,`A`],[8854,8856,`N`],[8857,8857,`A`],[8858,8868,`N`],[8869,8869,`A`],[8870,8894,`N`],[8895,8895,`A`],[8896,8977,`N`],[8978,8978,`A`],[8979,8985,`N`],[8986,8987,`W`],[8988,9e3,`N`],[9001,9002,`W`],[9003,9192,`N`],[9193,9196,`W`],[9197,9199,`N`],[9200,9200,`W`],[9201,9202,`N`],[9203,9203,`W`],[9204,9311,`N`],[9312,9449,`A`],[9450,9450,`N`],[9451,9547,`A`],[9548,9551,`N`],[9552,9587,`A`],[9588,9599,`N`],[9600,9615,`A`],[9616,9617,`N`],[9618,9621,`A`],[9622,9631,`N`],[9632,9633,`A`],[9634,9634,`N`],[9635,9641,`A`],[9642,9649,`N`],[9650,9651,`A`],[9652,9653,`N`],[9654,9655,`A`],[9656,9659,`N`],[9660,9661,`A`],[9662,9663,`N`],[9664,9665,`A`],[9666,9669,`N`],[9670,9672,`A`],[9673,9674,`N`],[9675,9675,`A`],[9676,9677,`N`],[9678,9681,`A`],[9682,9697,`N`],[9698,9701,`A`],[9702,9710,`N`],[9711,9711,`A`],[9712,9724,`N`],[9725,9726,`W`],[9727,9732,`N`],[9733,9734,`A`],[9735,9736,`N`],[9737,9737,`A`],[9738,9741,`N`],[9742,9743,`A`],[9744,9747,`N`],[9748,9749,`W`],[9750,9755,`N`],[9756,9756,`A`],[9757,9757,`N`],[9758,9758,`A`],[9759,9791,`N`],[9792,9792,`A`],[9793,9793,`N`],[9794,9794,`A`],[9795,9799,`N`],[9800,9811,`W`],[9812,9823,`N`],[9824,9825,`A`],[9826,9826,`N`],[9827,9829,`A`],[9830,9830,`N`],[9831,9834,`A`],[9835,9835,`N`],[9836,9837,`A`],[9838,9838,`N`],[9839,9839,`A`],[9840,9854,`N`],[9855,9855,`W`],[9856,9874,`N`],[9875,9875,`W`],[9876,9885,`N`],[9886,9887,`A`],[9888,9888,`N`],[9889,9889,`W`],[9890,9897,`N`],[9898,9899,`W`],[9900,9916,`N`],[9917,9918,`W`],[9919,9919,`A`],[9920,9923,`N`],[9924,9925,`W`],[9926,9933,`A`],[9934,9934,`W`],[9935,9939,`A`],[9940,9940,`W`],[9941,9953,`A`],[9954,9954,`N`],[9955,9955,`A`],[9956,9959,`N`],[9960,9961,`A`],[9962,9962,`W`],[9963,9969,`A`],[9970,9971,`W`],[9972,9972,`A`],[9973,9973,`W`],[9974,9977,`A`],[9978,9978,`W`],[9979,9980,`A`],[9981,9981,`W`],[9982,9983,`A`],[9984,9988,`N`],[9989,9989,`W`],[9990,9993,`N`],[9994,9995,`W`],[9996,10023,`N`],[10024,10024,`W`],[10025,10044,`N`],[10045,10045,`A`],[10046,10059,`N`],[10060,10060,`W`],[10061,10061,`N`],[10062,10062,`W`],[10063,10066,`N`],[10067,10069,`W`],[10070,10070,`N`],[10071,10071,`W`],[10072,10101,`N`],[10102,10111,`A`],[10112,10132,`N`],[10133,10135,`W`],[10136,10159,`N`],[10160,10160,`W`],[10161,10174,`N`],[10175,10175,`W`],[10176,10213,`N`],[10214,10221,`Na`],[10222,10628,`N`],[10629,10630,`Na`],[10631,11034,`N`],[11035,11036,`W`],[11037,11087,`N`],[11088,11088,`W`],[11089,11092,`N`],[11093,11093,`W`],[11094,11097,`A`],[11098,11903,`N`],[11904,11929,`W`],[11930,11930,`N`],[11931,12019,`W`],[12020,12031,`N`],[12032,12245,`W`],[12246,12271,`N`],[12272,12287,`W`],[12288,12288,`F`],[12289,12350,`W`],[12351,12352,`N`],[12353,12438,`W`],[12439,12440,`N`],[12441,12543,`W`],[12544,12548,`N`],[12549,12591,`W`],[12592,12592,`N`],[12593,12686,`W`],[12687,12687,`N`],[12688,12771,`W`],[12772,12782,`N`],[12783,12830,`W`],[12831,12831,`N`],[12832,12871,`W`],[12872,12879,`A`],[12880,19903,`W`],[19904,19967,`N`],[19968,42124,`W`],[42125,42127,`N`],[42128,42182,`W`],[42183,43359,`N`],[43360,43388,`W`],[43389,44031,`N`],[44032,55203,`W`],[55204,57343,`N`],[57344,63743,`A`],[63744,64255,`W`],[64256,65023,`N`],[65024,65039,`A`],[65040,65049,`W`],[65050,65071,`N`],[65072,65106,`W`],[65107,65107,`N`],[65108,65126,`W`],[65127,65127,`N`],[65128,65131,`W`],[65132,65280,`N`],[65281,65376,`F`],[65377,65470,`H`],[65471,65473,`N`],[65474,65479,`H`],[65480,65481,`N`],[65482,65487,`H`],[65488,65489,`N`],[65490,65495,`H`],[65496,65497,`N`],[65498,65500,`H`],[65501,65503,`N`],[65504,65510,`F`],[65511,65511,`N`],[65512,65518,`H`],[65519,65532,`N`],[65533,65533,`A`],[65534,94175,`N`],[94176,94180,`W`],[94181,94191,`N`],[94192,94193,`W`],[94194,94207,`N`],[94208,100343,`W`],[100344,100351,`N`],[100352,101589,`W`],[101590,101631,`N`],[101632,101640,`W`],[101641,110575,`N`],[110576,110579,`W`],[110580,110580,`N`],[110581,110587,`W`],[110588,110588,`N`],[110589,110590,`W`],[110591,110591,`N`],[110592,110882,`W`],[110883,110897,`N`],[110898,110898,`W`],[110899,110927,`N`],[110928,110930,`W`],[110931,110932,`N`],[110933,110933,`W`],[110934,110947,`N`],[110948,110951,`W`],[110952,110959,`N`],[110960,111355,`W`],[111356,126979,`N`],[126980,126980,`W`],[126981,127182,`N`],[127183,127183,`W`],[127184,127231,`N`],[127232,127242,`A`],[127243,127247,`N`],[127248,127277,`A`],[127278,127279,`N`],[127280,127337,`A`],[127338,127343,`N`],[127344,127373,`A`],[127374,127374,`W`],[127375,127376,`A`],[127377,127386,`W`],[127387,127404,`A`],[127405,127487,`N`],[127488,127490,`W`],[127491,127503,`N`],[127504,127547,`W`],[127548,127551,`N`],[127552,127560,`W`],[127561,127567,`N`],[127568,127569,`W`],[127570,127583,`N`],[127584,127589,`W`],[127590,127743,`N`],[127744,127776,`W`],[127777,127788,`N`],[127789,127797,`W`],[127798,127798,`N`],[127799,127868,`W`],[127869,127869,`N`],[127870,127891,`W`],[127892,127903,`N`],[127904,127946,`W`],[127947,127950,`N`],[127951,127955,`W`],[127956,127967,`N`],[127968,127984,`W`],[127985,127987,`N`],[127988,127988,`W`],[127989,127991,`N`],[127992,128062,`W`],[128063,128063,`N`],[128064,128064,`W`],[128065,128065,`N`],[128066,128252,`W`],[128253,128254,`N`],[128255,128317,`W`],[128318,128330,`N`],[128331,128334,`W`],[128335,128335,`N`],[128336,128359,`W`],[128360,128377,`N`],[128378,128378,`W`],[128379,128404,`N`],[128405,128406,`W`],[128407,128419,`N`],[128420,128420,`W`],[128421,128506,`N`],[128507,128591,`W`],[128592,128639,`N`],[128640,128709,`W`],[128710,128715,`N`],[128716,128716,`W`],[128717,128719,`N`],[128720,128722,`W`],[128723,128724,`N`],[128725,128727,`W`],[128728,128731,`N`],[128732,128735,`W`],[128736,128746,`N`],[128747,128748,`W`],[128749,128755,`N`],[128756,128764,`W`],[128765,128991,`N`],[128992,129003,`W`],[129004,129007,`N`],[129008,129008,`W`],[129009,129291,`N`],[129292,129338,`W`],[129339,129339,`N`],[129340,129349,`W`],[129350,129350,`N`],[129351,129535,`W`],[129536,129647,`N`],[129648,129660,`W`],[129661,129663,`N`],[129664,129672,`W`],[129673,129679,`N`],[129680,129725,`W`],[129726,129726,`N`],[129727,129733,`W`],[129734,129741,`N`],[129742,129755,`W`],[129756,129759,`N`],[129760,129768,`W`],[129769,129775,`N`],[129776,129784,`W`],[129785,131071,`N`],[131072,196605,`W`],[196606,196607,`N`],[196608,262141,`W`],[262142,917759,`N`],[917760,917999,`A`],[918e3,983039,`N`],[983040,1048573,`A`],[1048574,1048575,`N`],[1048576,1114109,`A`],[1114110,1114111,`N`]],version=`15.1.0`;function getEAWOfCodePoint(e){let t=0,n=defs.length-1;for(;t!==n;){let r=t+(n-t>>1),[i,a,o]=defs[r];if(ea)t=r+1;else return o}return defs[t][2]}function getEAW(e,t=0){let n=e.codePointAt(t);if(n!==void 0)return getEAWOfCodePoint(n)}var defaultWidths={N:1,Na:1,W:2,F:2,H:1,A:1};function computeWidth(e,t){let n=0;for(let r of e){let e=getEAW(r);n+=t&&t[e]||defaultWidths[e]}return n}var textOffsetY=5,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);function isWideChar(e){switch(getEAW(e)){case`F`:case`W`:return!0;default:return!1}}function isMacOS(){return window.navigator.userAgent.indexOf(`Mac OS X`)!==-1}function computeFontSize(e){let t=document.createElement(`canvas`).getContext(`2d`);t.font=e;let n=t.measureText(`W`);return[Math.floor(n.width),Math.round(n.fontBoundingBoxAscent+textOffsetY+(n.emHeightDescent||0)),Math.round(n.fontBoundingBoxAscent+textOffsetY)]}function drawBlock({ctx:e,x:t,y:n,width:r,height:i,style:a}){e.fillStyle=a,e.fillRect(t,n,r,i)}function drawText({ctx:e,x:t,y:n,text:r,font:i,style:a,option:o}){n+=Math.round(textOffsetY),e.fillStyle=a,e.font=i,e.textBaseline=`top`;for(let i of r)isWideChar(i)?(e.fillText(i,t,n,o.fontWidth*2),t+=o.fontWidth*2):(e.fillText(i,t,n,o.fontWidth),t+=o.fontWidth)}function drawHorizontalLine({ctx:e,x:t,y:n,width:r,style:i,lineWidth:a=1}){e.strokeStyle=i,e.lineWidth=a,e.setLineDash=[],e.beginPath(),e.moveTo(t,n),e.lineTo(t+r,n),e.stroke()}var Option=class{constructor({fontName:e,fontSize:t}){this.setFont(e,t),this.foreground=`#cccccc`,this.background=`#2d2d2d`}setFont(e,t){let n=t+`px `+e,[r,i,a]=computeFontSize(n);this.fontName=e,this.fontSize=t,this.fontWidth=r,this.fontHeight=i,this.fontAscent=a,this.font=n}};function getLemEditorElement(){return document.getElementById(`lem-editor`)}function normalizeWheelDelta(e,t,n,r){switch(n){case 0:return{dx:e/r,dy:t/r};case 2:return{dx:e*20,dy:t*20};default:return{dx:e,dy:t}}}function extractWholeLines(e,t){let n=Math.trunc(e),r=Math.trunc(t);return{scrollX:n,scrollY:r,remainderX:e-n,remainderY:t-r}}function cursorPosition(e,t){let[n,r]=t.getDisplayRectangle(),i=e.clientX-n,a=e.clientY-r;return{pixelX:i,pixelY:a,x:Math.floor(i/t.option.fontWidth),y:Math.floor(a/t.option.fontHeight)}}function makeWheelHandler(e){let t={x:0,y:0},n=!1,r={pixelX:0,pixelY:0,x:0,y:0};return i=>{i.preventDefault(),r=cursorPosition(i,e);let{dx:a,dy:o}=normalizeWheelDelta(i.deltaX,i.deltaY,i.deltaMode,e.option.fontHeight);t={x:t.x+a,y:t.y+o},n||(n=!0,requestAnimationFrame(()=>{n=!1;let{scrollX:i,scrollY:a,remainderX:o,remainderY:s}=extractWholeLines(t.x,t.y);t={x:o,y:s},(i!==0||a!==0)&&e.jsonrpc.notify(`input`,{kind:`wheel`,value:{...r,wheelX:-i,wheelY:-a}})}))}}function addMouseEventListeners({dom:e,editor:t,isDraggable:n,draggableStyle:r}){e.addEventListener(`contextmenu`,e=>{e.preventDefault()});let i=(e,n)=>{e.preventDefault();let[r,i]=t.getDisplayRectangle(),a=e.clientX-r,o=e.clientY-i,s=Math.floor(a/t.option.fontWidth),c=Math.floor(o/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:n,value:{x:s,y:c,pixelX:a,pixelY:o,button:e.button,clicks:e.detail}})};e.addEventListener(`mousedown`,e=>{n&&(document.body.style.cursor=r),t.focusHiddenInput(),i(e,`mousedown`)}),e.addEventListener(`mouseup`,e=>{n&&(document.body.style.cursor=`default`),i(e,`mouseup`)});let a=0;e.addEventListener(`mousemove`,e=>{e.preventDefault();let n=Date.now();if(n-a>50){a=n;let[r,i]=t.getDisplayRectangle(),o=e.clientX-r,s=e.clientY-i,c=Math.floor(o/t.option.fontWidth),l=Math.floor(s/t.option.fontHeight);t.jsonrpc.notify(`input`,{kind:`mousemove`,value:{x:c,y:l,pixelX:o,pixelY:s,button:e.buttons===0?null:e.buttons-1}})}}),n&&(e.addEventListener(`mouseover`,()=>{document.body.style.cursor=r}),e.addEventListener(`mouseout`,e=>{e.buttons!==1&&(document.body.style.cursor=`default`)})),e.addEventListener(`wheel`,makeWheelHandler(t))}var zIndexTable={"floating-window":200,modeline:100,"vertical-border":100,"horizontal-border":101};function zindex(e){return zIndexTable[e]||0}var borderOffsetX=5,borderOffsetY=10,BaseSurface=class{constructor({editor:e}){this.editor=e,this.mainDOM=null,this.wrapper=null}delete(){this.wrapper?getLemEditorElement().removeChild(this.wrapper):getLemEditorElement().removeChild(this.mainDOM)}setupDOM({dom:e,isFloating:t,border:n,cssClassName:r}){this.mainDOM=e,t&&n?(this.wrapper=document.createElement(`div`),r&&(this.wrapper.className=r),this.wrapper.style.position=`absolute`,this.wrapper.style.backgroundColor=this.editor.option.background,this.wrapper.style.zIndex=zindex(`floating-window`),this.wrapper.appendChild(e),getLemEditorElement().appendChild(this.wrapper)):(r&&(e.className=r),getLemEditorElement().appendChild(e))}move(e,t){let[n,r]=this.editor.getDisplayRectangle(),i=Math.floor(n+e),a=Math.floor(r+t);this.wrapper?(this.wrapper.style.left=i-borderOffsetX+`px`,this.wrapper.style.top=a-borderOffsetY+`px`,this.mainDOM.style.left=borderOffsetX+`px`,this.mainDOM.style.top=borderOffsetY+`px`):(this.mainDOM.style.left=i+`px`,this.mainDOM.style.top=a+`px`)}_resize(e,t){let n=window.devicePixelRatio||1;this.mainDOM.width=e*n,this.mainDOM.height=t*n,this.mainDOM.style.width=e+`px`,this.mainDOM.style.height=t+`px`,this.wrapper&&(this.wrapper.style.width=e+borderOffsetX*2+`px`,this.wrapper.style.height=t+borderOffsetY*2+`px`)}drawBlock(e,t,n,r,i){}drawText(e,t,n,r,i,a,o,s){}drawImage(e,t,n,r,i,a,o){}clearImages(e,t){}clearAllImages(){}touch(){}evalIn(code){return eval(code)}},CanvasSurface=class extends BaseSurface{constructor({editor:e,view:t,pixelX:n,pixelY:r,pixelWidth:i,pixelHeight:a,styles:o,isFloating:s,border:c,cssClassName:l}){super({editor:e});let u=this.setupCanvas(o);this.setupDOM({dom:u,isFloating:s,border:c,cssClassName:l}),this.move(n,r),this.resize(i,a),this.drawingQueue=[],addMouseEventListeners({dom:u,editor:e})}setupCanvas(e){let t=document.createElement(`canvas`);if(t.style.position=`absolute`,e)for(let n in e)t.style[n]=e[n];return t}resize(e,t){this._resize(e,t);let n=window.devicePixelRatio||1;this.mainDOM.getContext(`2d`).scale(n,n)}move(e,t){if(super.move(e,t),this.imageEls)for(let[,e]of this.imageEls)this.positionImage(e)}delete(){this.clearAllImages(),super.delete()}drawBlock(e,t,n,r,i){this.drawingQueue.push(function(a){drawBlock({ctx:a,x:e,y:t,width:n,height:r,style:i})})}drawText(e,t,n,r,i,a,o,s){let c=this.editor.option,l=o??t,u=s??c.fontHeight;this.drawingQueue.push(function(o){if(a=a?`${c.fontSize}px ${a}`:c.font,!i)drawBlock({ctx:o,x:e,y:l,width:r,height:u,style:c.background}),drawText({ctx:o,x:e,y:t,text:n,style:c.foreground,font:a,option:c});else{let{foreground:s,background:d,bold:f,reverse:p,underline:m,cursor:h}=i;if(s||=c.foreground,d||=c.background,p){let e=d;d=s,s=e}h&&(d=c.background),drawBlock({ctx:o,x:e,y:l,width:r,height:u,style:d}),drawText({ctx:o,x:e,y:t,text:n,style:s,font:f?`bold `+a:a,option:c}),m&&drawHorizontalLine({ctx:o,x:e,y:t+c.fontHeight-2,width:r,style:typeof m==`string`?m:s,lineWidth:2})}})}imageBaseLeft(){return parseFloat(this.mainDOM.style.left)||0}imageBaseTop(){return parseFloat(this.mainDOM.style.top)||0}drawImage(e,t,n,r,i,a,o){this.imageEls||=new Map;let s=e+`,`+t,c=this.imageEls.get(s);if(c&&c.url!==o&&(c.el.remove(),this.imageEls.delete(s),c=null),!c){let e=document.createElement(`img`);e.style.position=`absolute`,e.style.pointerEvents=`none`,e.style.zIndex=`1`,e.src=o,this.mainDOM.parentNode.appendChild(e),c={el:e,url:o},this.imageEls.set(s,c)}c.x=e,c.y=t,c.width=n,c.height=r,c.clipWidth=i,c.clipHeight=a,this.positionImage(c)}positionImage(e){e.el.style.left=this.imageBaseLeft()+e.x+`px`,e.el.style.top=this.imageBaseTop()+e.y+`px`,e.el.style.width=e.width+`px`,e.el.style.height=e.height+`px`;let t=e.clipWidth==null?0:Math.max(0,e.width-e.clipWidth),n=e.clipHeight==null?0:Math.max(0,e.height-e.clipHeight);e.el.style.clipPath=t>0||n>0?`inset(0px ${t}px ${n}px 0px)`:``}clearImages(e,t){if(this.imageEls)for(let[n,r]of this.imageEls){let i=r.y+(r.height||0);r.ye&&(r.el.remove(),this.imageEls.delete(n))}}clearAllImages(){if(this.imageEls){for(let[,e]of this.imageEls)e.el.remove();this.imageEls.clear()}}touch(){let e=this.mainDOM.getContext(`2d`);for(let t of this.drawingQueue)t(e);this.drawingQueue=[]}activate(){this.mainDOM.dataset.store=`active`}deactivate(){this.mainDOM.dataset.store=`inactive`}},HTMLSurface=class extends BaseSurface{constructor({editor:e,pixelX:t,pixelY:n,pixelWidth:r,pixelHeight:i,styles:a,option:o,isFloating:s,border:c,html:l}){super({editor:e});let u=document.createElement(`iframe`);this.setupDOM({dom:u,isFloating:s,border:c}),u.style.position=`absolute`,u.style.backgroundColor=o.background,u.setAttribute(`sandbox`,`allow-scripts allow-same-origin`),u.srcdoc=l,u.addEventListener(`load`,()=>{let e=u.contentWindow;e.invokeLem=(e,t)=>parent.postMessage({type:`invoke-lem`,method:e,args:t})}),this.iframe=u,this.move(t,n),this.resize(r,i)}resize(e,t){this._resize(e,t)}update(e){let t=this.iframe.contentWindow.scrollY;this.iframe.srcdoc=e,this.iframe.onload=()=>{this.iframe.onload=null,this.iframe.contentWindow.scrollTo(0,t)}}evalIn(e){return this.iframe.contentWindow.eval(e)}},VerticalBorder=class{constructor({x:e,y:t,height:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__vertical-border`,this.line.style.height=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`vertical-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`col-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=Math.floor(n+e-this.option.fontWidth/2)+`px`,this.line.style.top=r+t+`px`}resize(e){this.line.style.height=e+`px`}},HorizontalBorder=class{constructor({x:e,y:t,width:n,option:r,editor:i}){this.option=r,this.editor=i,this.line=document.createElement(`div`),this.line.className=`lem-editor__horizontal-border`,this.line.style.width=n+`px`,this.line.style.position=`absolute`,this.line.style.zIndex=zindex(`horizontal-border`),getLemEditorElement().appendChild(this.line),this.move(e,t),addMouseEventListeners({dom:this.line,editor:i,isDraggable:!0,draggableStyle:`row-resize`})}delete(){this.line.parentNode.removeChild(this.line)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.line.style.left=n+e+`px`,this.line.style.top=Math.floor(r+t-4)+`px`}resize(e){this.line.style.width=e+`px`}},viewStyles={header:()=>{},tile:()=>{},floating:e=>({boxSizing:`border-box`,borderColor:e.foreground,backgroundColor:e.background})};function getViewStyle(e,t){return viewStyles[e](t)||{}}var View=class{constructor({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,option:h,editor:g}){switch(this.option=h,this.id=e,this.x=t,this.y=n,this.width=r,this.height=i,this.pixelX=a,this.pixelY=o,this.pixelWidth=s,this.pixelHeight=c,this.useModeline=l,this.kind=u,this.type=d,this.border=p,this.borderShape=m,this.editor=g,this.bottomBar=null,this.leftsideBar=null,u){case`tile`:this.mainSurface=this.makeSurface(d,f),this.leftSideBar=new VerticalBorder({x:a,y:o,height:c+(l?h.fontHeight:0),option:h,editor:g}),l||(this.bottomBar=new HorizontalBorder({x:a,y:o+c-h.fontHeight,width:s,option:h,editor:g}));break;case`header`:this.mainSurface=this.makeSurface(d,f);break;case`floating`:this.mainSurface=this.makeSurface(d,f),m===`left-border`&&(this.leftSideBar=new VerticalBorder({x:a,y:o,height:c,option:h,editor:g}));break}this.modelineSurface=l?this.makeModelineSurface():null}delete(){this.mainSurface.delete(),this.modelineSurface&&this.modelineSurface.delete(),this.leftSideBar&&this.leftSideBar.delete(),this.bottomBar&&this.bottomBar.delete()}move(e,t,n,r){this.x=e,this.y=t,this.pixelX=n,this.pixelY=r,this.mainSurface.move(n,r),this.modelineSurface&&this.modelineSurface.move(n,r+this.pixelHeight),this.leftSideBar&&this.leftSideBar.move(n,r),this.bottomBar&&this.bottomBar.move(n,r+this.pixelHeight)}resize(e,t,n,r){this.width=e,this.height=t,this.pixelWidth=n,this.pixelHeight=r,this.mainSurface.resize(n,r),this.modelineSurface&&(this.modelineSurface.move(this.pixelX,this.pixelY+r),this.modelineSurface.resize(n,this.option.fontHeight)),this.leftSideBar&&this.leftSideBar.resize(r+(this.modelineSurface?this.option.fontHeight:0)),this.bottomBar&&this.bottomBar.resize(n)}clear(){this.mainSurface.drawBlock(0,0,this.pixelWidth,this.pixelHeight,this.option.background),this.mainSurface.clearImages(0,this.pixelHeight)}clearEol(e,t,n){n??=this.option.fontHeight,this.mainSurface.drawBlock(e,t,this.pixelWidth-e,n,this.option.background),this.mainSurface.clearImages(t,t+n)}clearEob(e,t){this.mainSurface.drawBlock(e,t,this.pixelWidth,this.pixelHeight-t,this.option.background),this.mainSurface.clearImages(t,this.pixelHeight)}print(e,t,n,r,i,a,o,s){this.mainSurface.drawText(e,t,n,r,i,a,o,s)}drawBlock(e,t,n,r,i){this.mainSurface.drawBlock(e,t,n,r,i||this.option.background)}drawBlockOnModeline(e,t,n,r,i){this.modelineSurface&&this.modelineSurface.drawBlock(e,t,n,r,i||this.option.background)}printImage(e,t,n,r,i,a,o){this.mainSurface.drawImage(e,t,n,r,i,a,o)}printToModeline(e,t,n,r,i,a,o){this.modelineSurface&&this.modelineSurface.drawText(e,t,n,r,i,null,a,o)}touch(e){this.mainSurface.touch(),this.modelineSurface&&(this.modelineSurface.touch(),e?this.modelineSurface.activate():this.modelineSurface.deactivate())}makeSurface(e,t){switch(e){case`html`:return this.makeHTMLSurface(t);case`editor`:return this.makeEditorSurface();default:console.error(`unknown type: ${e}`)}}makeHTMLSurface(e){return new HTMLSurface({editor:this.editor,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),option:this.option,isFloating:this.kind===`floating`,border:this.border,html:e})}makeEditorSurface(){let e=this.borderShape===`left-border`?0:this.border,t=this.kind===`floating`;return new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY,pixelWidth:this.pixelWidth,pixelHeight:this.pixelHeight,styles:getViewStyle(this.kind,this.option),editor:this.editor,border:e,isFloating:t,view:this,cssClassName:t&&e?`lem-editor__floating-window--bordered`:null})}makeModelineSurface(){let e=new CanvasSurface({option:this.editor.option,pixelX:this.pixelX,pixelY:this.pixelY+this.pixelHeight,pixelWidth:this.pixelWidth,pixelHeight:this.option.fontHeight,editor:this.editor,view:this,styles:{zIndex:zindex(`modeline`)},cssClassName:`lem-editor__mode-line`});return addMouseEventListeners({dom:e.mainDOM,editor:this.editor,isDraggable:!0,draggableStyle:`row-resize`}),e}changeToHTMLContent(e){this.mainSurface.constructor.name===`HTMLSurface`?this.mainSurface.update(e):(this.mainSurface.delete(),this.mainSurface=this.makeHTMLSurface(e))}changeToEditorContent(){this.mainSurface.delete(),this.mainSurface=this.makeEditorSurface()}evalIn(e){return this.mainSurface.evalIn(e)}};function isPasteKeyEvent(e){return isMacOS()?e.metaKey&&e.key===`v`:e.ctrlKey&&e.shiftKey&&e.key===`V`}var Input=class{constructor(e){let t=e.option;this.editor=e,this.composition=!1,this.ignoreKeydownAfterCompositionend=!1,this.span=document.createElement(`span`),this.span.style.color=t.foreground,this.span.style.backgroundColor=t.background,this.span.style.position=`absolute`,this.span.style.zIndex=1e6,this.span.style.top=`0`,this.span.style.left=`0`,this.span.style.font=t.font,this.input=document.createElement(`input`),this.input.style.backgroundColor=`transparent`,this.input.style.color=`transparent`,this.input.style.width=`0`,this.input.style.padding=`0`,this.input.style.margin=`0`,this.input.style.border=`none`,this.input.style.position=`absolute`,this.input.style.zIndex=`-10`,this.input.style.top=`0`,this.input.style.left=`0`,this.input.style.font=t.font,this.input.addEventListener(`blur`,e=>{this.input.focus()}),this.input.addEventListener(`input`,e=>{this.composition===!1&&(this.input.value=``,this.span.innerHTML=``,this.input.style.width=`0`,isMacOS()||this.editor.emitInputString(e.data))}),this.input.addEventListener(`paste`,async e=>{e.preventDefault();let t=e.clipboardData||window.Clipboard.data,n=t?.getData(`text`)??t?.getData(`text/plain`);if(n&&n.length>0){this.editor.emitInputString(n);return}try{if(navigator.clipboard?.readText){let e=await navigator.clipboard.readText();if(e&&e.length>0){this.editor.emitInputString(e);return}}}catch(e){console.warn(`clipboard.readText() failed:`,e)}alert(`Paste failed (permission/environment restriction`)}),this.input.addEventListener(`keydown`,e=>{if(!isPasteKeyEvent(e)&&!(e.isComposing||this.composition)&&e.key!==`Process`){if(this.ignoreKeydownAfterCompositionend&&(isSafari||isMacOS())){e.preventDefault(),this.ignoreKeydownAfterCompositionend=!1;return}if(!(!isMacOS()&&!e.ctrlKey&&!e.altKey&&e.key.length===1)&&(e.preventDefault(),e.isComposing!==!0&&e.code!==``))return setTimeout(()=>{this.composition||(this.editor.emitInput(e),this.input.value=``)},0),!1}}),this.input.addEventListener(`compositionstart`,e=>{this.composition=!0,this.span.innerHTML=this.input.value,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionupdate`,e=>{this.span.innerHTML=e.data,this.input.style.width=this.span.offsetWidth+`px`}),this.input.addEventListener(`compositionend`,e=>{this.composition=!1,this.editor.emitInputString(this.input.value),this.input.value=``,this.span.innerHTML=this.input.value,this.input.style.width=`0`,this.ignoreKeydownAfterCompositionend=!0}),document.body.appendChild(this.input),document.body.appendChild(this.span),this.input.focus()}finalize(){document.body.removeChild(this.input),document.body.removeChild(this.span)}move(e,t){let[n,r]=this.editor.getDisplayRectangle();this.span.style.top=r+t+`px`,this.span.style.left=n+e+`px`,this.input.style.top=this.span.offsetTop+`px`,this.input.style.left=this.span.offsetLeft+`px`}updateForeground(e){this.span.style.color=e}updateBackground(e){this.span.style.backgroundColor=e}},MessageTable=class{constructor(){this.map=new Map}register(e,t){for(let n in t){let r=t[n];this.map.set(n,r),e.on(n,r)}}get(e){return this.map.get(e)}};function getDisplayRectangleDefault(){return[0,0,window.innerWidth,window.innerHeight]}var Editor=class{constructor({getDisplayRectangle:e=getDisplayRectangleDefault,fontName:t,fontSize:n,url:r,onExit:i,onClosed:a}){this.getDisplayRectangle=e,this.option=new Option({fontName:t,fontSize:n}),this.onExit=i,this.input=new Input(this),this.cursors=new Map,this.cursorOverlay=document.createElement(`div`),this.cursorOverlay.className=`lem-cursor`,this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.cursorOverlay.style.backgroundColor=`#ffffff`,this.cursorType=`box`,this.viewMap=new Map,this.jsonrpc=new JSONRPC(r,{onClosed:()=>{a()}}),this.messageTable=new MessageTable,this.messageTable.register(this.jsonrpc,{"update-foreground":this.updateForeground.bind(this),"update-background":this.updateBackground.bind(this),"make-view":this.makeView.bind(this),"delete-view":this.deleteView.bind(this),"resize-view":this.resize.bind(this),"move-view":this.move.bind(this),"redraw-view-after":this.redrawViewAfter.bind(this),clear:this.clear.bind(this),"clear-eol":this.clearEol.bind(this),"clear-eob":this.clearEob.bind(this),put:this.put.bind(this),"put-image":this.putImage.bind(this),"modeline-put":this.modelinePut.bind(this),"draw-block":this.drawBlock.bind(this),"modeline-draw-block":this.modelineDrawBlock.bind(this),"update-display":this.updateDisplay.bind(this),"move-cursor":this.moveCursor.bind(this),"change-view":this.changeView.bind(this),"resize-display":this.resizeDisplay.bind(this),bulk:this.bulk.bind(this),exit:this.exitEditor.bind(this),"get-clipboard-text":this.getClipboardText.bind(this),"set-clipboard-text":this.setClipboardText.bind(this),"js-eval":this.jsEval.bind(this),"set-font":this.setFont.bind(this),"get-font":this.getFont.bind(this),"get-display-size":this.getDisplaySize.bind(this),"load-css":this.loadCSS.bind(this),"update-cursor-shape":this.updateCursorShape.bind(this)}),this.login(),this.boundedHandleResize=this.handleResize.bind(this),this.focusHiddenInput=this.focusHiddenInput.bind(this)}init(){window.addEventListener(`resize`,this.boundedHandleResize),document.getElementsByTagName(`html`)[0].style[`background-color`]=`#333`,getLemEditorElement().appendChild(this.cursorOverlay)}finalize(){window.removeEventListener(`resize`,this.boundedHandleResize),this.input.finalize(),this.cursorOverlay.parentNode&&this.cursorOverlay.parentNode.removeChild(this.cursorOverlay)}closeConnection(){this.jsonrpc.close()}emitInput(e){let t=convertKeyEvent(e);if(t){if(t.key===`]`&&t.ctrl&&!t.meta&&!t.super&&!t.shift){this.jsonrpc.notify(`input`,{kind:`abort`});return}t.key!==`Unidentified`&&this.jsonrpc.notify(`input`,{kind:`key`,value:t})}}emitInputString(e){e?this.jsonrpc.notify(`input`,{kind:`input-string`,value:e}):console.error(`unexpected argument`,e)}redrawParams(){return{size:this.getDisplaySize(),fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent,fontSize:this.option.fontSize}}handleResize(e){this.jsonrpc.notify(`redraw`,this.redrawParams())}focusHiddenInput(){let e=this.input?.input;if(e){try{window.focus()}catch{}requestAnimationFrame(()=>{setTimeout(()=>{e.focus({preventScroll:!0})},0)})}}sendNotification(e,t){this.jsonrpc.notify(e,t)}request(e,t,n){this.jsonrpc.request(e,t,n)}getDisplaySize(){let[e,t,n,r]=this.getDisplayRectangle();return{width:Math.floor(n/this.option.fontWidth),height:Math.floor(r/this.option.fontHeight)}}callMessage(e,t){this.messageTable.get(e)(t)}findViewById(e){return this.viewMap.get(e)}login(){this.jsonrpc.request(`login`,{size:this.getDisplaySize(),foreground:this.option.foreground,background:this.option.background,fontWidth:this.option.fontWidth,fontHeight:this.option.fontHeight,fontAscent:this.option.fontAscent,fontSize:this.option.fontSize},e=>{if(this.updateForeground(e.foreground),this.updateBackground(e.background),e.views)for(let t of e.views)this.makeView(t);this.jsonrpc.notify(`redraw`,this.redrawParams())})}updateForeground(e){e!=null&&(this.option.foreground=e,this.input.updateForeground(e))}updateBackground(e){if(e==null)return;this.option.background=e,this.input.updateBackground(e);let t=getLemEditorElement();t.style.backgroundColor=e}makeView({id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,use_modeline:l,kind:u,type:d,content:f,border:p,border_shape:m}){let h=new View({option:this.option,id:e,x:t,y:n,width:r,height:i,pixelX:a,pixelY:o,pixelWidth:s,pixelHeight:c,useModeline:l,kind:u,type:d,content:f,border:p,borderShape:m,editor:this});this.viewMap.set(e,h)}deleteView({viewInfo:{id:e}}){this.findViewById(e).delete(),this.viewMap.delete(e)}resize({viewInfo:{id:e},width:t,height:n,pixelWidth:r,pixelHeight:i}){let a=this.findViewById(e);a?a.resize(t,n,r,i):console.warn(`resize: view not found for id ${e}`)}move({viewInfo:{id:e},x:t,y:n,pixelX:r,pixelY:i}){let a=this.findViewById(e);a?a.move(t,n,r,i):console.warn(`move: view not found for id ${e}`)}redrawViewAfter({viewInfo:{id:e},isActive:t}){this.findViewById(e).touch(t)}clear({viewInfo:{id:e}}){this.findViewById(e).clear()}clearEol({viewInfo:{id:e},x:t,y:n,height:r}){this.findViewById(e).clearEol(t,n,r)}clearEob({viewInfo:{id:e},x:t,y:n}){this.findViewById(e).clearEob(t,n)}put({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,font:o,backgroundY:s,backgroundHeight:c}){this.findViewById(e).print(t,n,r,i,a,o,s,c)}drawBlock({viewInfo:{id:e},x:t,y:n,width:r,height:i,color:a}){this.findViewById(e).drawBlock(t,n,r,i,a)}modelineDrawBlock({viewInfo:{id:e},x:t,y:n,width:r,height:i,color:a}){this.findViewById(e).drawBlockOnModeline(t,n,r,i,a)}putImage({viewInfo:{id:e},x:t,y:n,pixelWidth:r,pixelHeight:i,clipWidth:a,clipHeight:o,url:s}){this.findViewById(e).printImage(t,n,r,i,a,o,s)}modelinePut({viewInfo:{id:e},x:t,y:n,text:r,textWidth:i,attribute:a,backgroundY:o,backgroundHeight:s}){this.findViewById(e).printToModeline(t,n,r,i,a,o,s)}updateDisplay(){}moveCursor({viewInfo:{id:e},x:t,y:n,color:r,cursorText:i,cursorForeground:a}){let o=this.findViewById(e),[s,c]=this.getDisplayRectangle(),l=o.pixelX+t,u=o.pixelY+n;this.input.move(l,u);let d=r||this.option.foreground,f=a||this.option.background,p=this.cursorOverlay;switch(this.cursorType){case`bar`:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=`2px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;case`underline`:p.style.left=s+l+`px`,p.style.top=c+u+this.option.fontHeight-2+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=`2px`,p.style.backgroundColor=d,p.textContent=``,p.style.color=``,p.style.font=``,p.style.paddingTop=``;break;default:p.style.left=s+l+`px`,p.style.top=c+u+`px`,p.style.width=this.option.fontWidth+`px`,p.style.height=this.option.fontHeight+`px`,p.style.backgroundColor=d,p.style.font=this.option.font,p.style.paddingTop=textOffsetY+`px`,p.textContent=i||``,p.style.color=f;break}p.style.animation=`none`,p.offsetHeight,p.style.animation=``}updateCursorShape({cursorType:e}){this.cursorType=e||`box`}changeView({viewInfo:{id:e},type:t,content:n}){let r=this.findViewById(e);switch(t){case`html`:r.changeToHTMLContent(n);break;case`editor`:r.changeToEditorContent();break}}resizeDisplay({width:e,height:t}){let n=getLemEditorElement();n.style.width=Math.floor(e*this.option.fontWidth)+`px`,n.style.height=Math.floor(t*this.option.fontHeight)+`px`}bulk(e){for(let{method:t,argument:n}of e)this.callMessage(t,n)}exitEditor(){this.onExit&&this.onExit()}getClipboardText(){navigator.clipboard?.readText().then(e=>{this.jsonrpc.notify(`got-clipboard-text`,{text:e})})}setClipboardText({text:e}){navigator.clipboard&&navigator.clipboard.writeText(e)}jsEval({viewInfo:{id:e},code:t}){let n=this.findViewById(e).evalIn(t);return n&&n.toString()}setFont({fontName:e,fontSize:t}){this.option.setFont(e||this.option.fontName,t||this.option.fontSize),this.cursorOverlay.style.width=this.option.fontWidth+`px`,this.cursorOverlay.style.height=this.option.fontHeight+`px`,this.jsonrpc.notify(`redraw`,this.redrawParams())}getFont(){return{name:this.option.fontName,size:this.option.fontSize}}loadCSS({content:e}){let t=document.createElement(`style`);t.textContent=e,document.head.appendChild(t)}notifyToServer(e,t){this.jsonrpc.notify(`invoke`,{method:e,args:t})}},canvas=document.querySelector(`#editor`);async function main(){await Promise.all([document.fonts.load(`19px file-icons`),document.fonts.load(`19px AllTheIcons`),document.fonts.load(`19px fontawesome`),document.fonts.load(`19px material-design-icons`),document.fonts.load(`19px octicons`)]),await document.fonts.ready;let e=new Editor({canvas,fontName:`Monospace`,fontSize:18,url:`${window.location.protocol===`https:`?`wss`:`ws`}://${window.location.hostname}:${window.location.port}`,onExit:null,onClosed:null});window.addEventListener(`message`,t=>{t.data.type===`invoke-lem`&&e.notifyToServer(t.data.method,t.data.args)}),e.init()}main(); \ No newline at end of file diff --git a/frontends/server/frontend/editor.js b/frontends/server/frontend/editor.js index 1eaf87557..bda811abd 100644 --- a/frontends/server/frontend/editor.js +++ b/frontends/server/frontend/editor.js @@ -1332,6 +1332,7 @@ export class Editor { fontWidth: this.option.fontWidth, fontHeight: this.option.fontHeight, fontAscent: this.option.fontAscent, + fontSize: this.option.fontSize, }; } @@ -1383,6 +1384,7 @@ export class Editor { fontWidth: this.option.fontWidth, fontHeight: this.option.fontHeight, fontAscent: this.option.fontAscent, + fontSize: this.option.fontSize, }, (response) => { this.updateForeground(response.foreground); this.updateBackground(response.background); diff --git a/frontends/server/main.lisp b/frontends/server/main.lisp index ec1de4e26..26ee0226f 100644 --- a/frontends/server/main.lisp +++ b/frontends/server/main.lisp @@ -118,7 +118,10 @@ quits by itself afterwards.") :accessor jsonrpc-cell-height) ;; how far below a cell's top the client puts the text baseline. (cell-ascent :initform nil - :accessor jsonrpc-cell-ascent)) + :accessor jsonrpc-cell-ascent) + ;; the font's own size. the cell height is measured from the glyph bounding box, so it is larger. + (font-em :initform nil + :accessor jsonrpc-font-em)) (:default-initargs :name :jsonrpc :redraw-after-modifying-floating-window t @@ -181,7 +184,8 @@ returns true when one of them changed, since nothing already measured survives a (setf changed t))))) (update "fontWidth" 'jsonrpc-cell-width) (update "fontHeight" 'jsonrpc-cell-height) - (update "fontAscent" 'jsonrpc-cell-ascent)) + (update "fontAscent" 'jsonrpc-cell-ascent) + (update "fontSize" 'jsonrpc-font-em)) changed)) (defun handle-login (jsonrpc logged-in-callback params) @@ -517,6 +521,9 @@ returns true when one of them changed, since nothing already measured survives a (jsonrpc-cell-height jsonrpc) (jsonrpc-cell-ascent jsonrpc))) +(defmethod lem-if:font-em-pixels ((jsonrpc jsonrpc)) + (jsonrpc-font-em jsonrpc)) + (defun call (method params) (let ((mailbox (sb-concurrency:make-mailbox :name "lem-server-call-async"))) (loop :for connection diff --git a/src/interface.lisp b/src/interface.lisp index 9be5c1305..2a059935d 100644 --- a/src/interface.lisp +++ b/src/interface.lisp @@ -192,6 +192,12 @@ Always pixels, unlike `cell-width' / `cell-height', which are 1 on a cell-based (:method (implementation) (values nil nil nil))) +(defgeneric lem-if:font-em-pixels (implementation) + (:documentation "Pixels one em of the editor font takes, or NIL when the frontend cannot say. +In the same units as `cell-pixel-size'. +The em is smaller than `cell-height', which is measured from the glyph bounding box.") + (:method (implementation) nil)) + (defgeneric lem-if:render-row (implementation view row) (:documentation "Draw ROW, one screen row of VIEW, replacing whatever it held before. ROW is a `lem-core/display:row'. Its height, background and the position of every object on it were diff --git a/src/internal-packages.lisp b/src/internal-packages.lisp index 9d6c5d09a..672695778 100644 --- a/src/internal-packages.lisp +++ b/src/internal-packages.lisp @@ -844,6 +844,7 @@ :cell-width :cell-height :cell-pixel-size + :font-em-pixels :clear-to-end-of-window :js-eval :render-row From 302c0da28044d1cbf0644a2264aabeac1a3d7d55 Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Tue, 4 Aug 2026 20:20:04 +0300 Subject: [PATCH 16/18] fix theme colors not reaching get-foreground-color/get-background-color --- frontends/server/main.lisp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontends/server/main.lisp b/frontends/server/main.lisp index 26ee0226f..67679b698 100644 --- a/frontends/server/main.lisp +++ b/frontends/server/main.lisp @@ -289,10 +289,14 @@ returns true when one of them changed, since nothing already measured survives a (defmethod lem-if:update-foreground ((jsonrpc jsonrpc) color-name) (with-error-handler () + (alexandria:when-let (color (lem:parse-color color-name)) + (setf (jsonrpc-foreground-color jsonrpc) color)) (notify jsonrpc "update-foreground" color-name))) (defmethod lem-if:update-background ((jsonrpc jsonrpc) color-name) (with-error-handler () + (alexandria:when-let (color (lem:parse-color color-name)) + (setf (jsonrpc-background-color jsonrpc) color)) (notify jsonrpc "update-background" color-name))) (defmethod lem-if:update-cursor-shape ((jsonrpc jsonrpc) cursor-type) From 504fec3227758179ec5f0c25c1aeeb1125b4cb6f Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Wed, 5 Aug 2026 00:34:34 +0300 Subject: [PATCH 17/18] let virtual text carry an attribute per run --- src/display/logical-line.lisp | 62 +++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/display/logical-line.lisp b/src/display/logical-line.lisp index 70e7553eb..8b2d12ae3 100644 --- a/src/display/logical-line.lisp +++ b/src/display/logical-line.lisp @@ -6,8 +6,17 @@ "a display-only string fragment injected at a character position within a logical line." ;; 0-based position in the line's string where this fragment is inserted charpos - string - attribute) + ;; list of (string attribute) runs, drawn in order. see `virtual-text-runs'. + runs) + +(defun virtual-text-runs (spec) + "an overlay's :before-string / :after-string as a list of (string attribute) runs. +SPEC is a bare string, a single (string attribute) pair, or a list of such pairs" + (cond ((stringp spec) (list (list spec nil))) + ((not (consp spec)) nil) + ((stringp (first spec)) (list (list (first spec) (second spec)))) + (t (loop :for (run-string run-attribute) :in spec + :collect (list run-string run-attribute))))) (defstruct logical-line string @@ -378,18 +387,14 @@ several folds that each hide arbitrary character ranges across multiple buffer l :for before-str := (overlay-get overlay :before-string) :for after-str := (overlay-get overlay :after-string) :do (when (and before-str (start-in-line-p overlay)) - (let ((bs (alexandria:ensure-list before-str))) - (push (make-virtual-item :charpos (overlay-start-charpos overlay) - :string (first bs) - :attribute (second bs)) - virtual-items))) + (push (make-virtual-item :charpos (overlay-start-charpos overlay) + :runs (virtual-text-runs before-str)) + virtual-items)) (when (and after-str (end-in-line-p overlay)) - (let ((as (alexandria:ensure-list after-str))) - (push (make-virtual-item :charpos (or (overlay-end-charpos overlay) - (length string)) - :string (first as) - :attribute (second as)) - virtual-items)))) + (push (make-virtual-item :charpos (or (overlay-end-charpos overlay) + (length string)) + :runs (virtual-text-runs after-str)) + virtual-items))) ;; markers were positioned in raw coordinates; remap them into the ;; spliced string so several folds on one visual line stay anchored. (dolist (vi virtual-items) @@ -409,8 +414,7 @@ several folds that each hide arbitrary character ranges across multiple buffer l :when (>= (virtual-item-charpos vi) charpos) :collect (make-virtual-item :charpos (- (virtual-item-charpos vi) charpos) - :string (virtual-item-string vi) - :attribute (virtual-item-attribute vi)))))) + :runs (virtual-item-runs vi)))))) (make-logical-line :string string :attributes attributes @@ -522,19 +526,21 @@ VIRTUAL-ITEMS arrive in draw order (from `create-logical-line')." (items)) (flet ((add-virtuals-at (pos) (loop :while (and pending (= (virtual-item-charpos (first pending)) pos)) - :do (let ((vi (pop pending))) - ;; a newline ends the screen row rather than being drawn, so the segments - ;; around it become items with a break between them. - (loop :for segment :in (uiop:split-string (virtual-item-string vi) - :separator '(#\newline)) - :for firstp := t :then nil - :do (unless firstp - (setf items (cons (make-line-break-item) items))) - (setf items (add-or-merge-item - (make-string-with-attribute-item - :string segment - :attribute (virtual-item-attribute vi)) - items))))))) + ;; runs follow one another on the same row, each keeping its own attribute. + :do (loop :for (run-string run-attribute) :in (virtual-item-runs (pop pending)) + ;; a newline ends the screen row rather than being drawn, so the + ;; segments around it become items with a break between them. + :do (loop :for segment :in (uiop:split-string + run-string + :separator '(#\newline)) + :for firstp := t :then nil + :do (unless firstp + (setf items (cons (make-line-break-item) items))) + (setf items (add-or-merge-item + (make-string-with-attribute-item + :string segment + :attribute run-attribute) + items))))))) ;; walk segments between break positions, injecting virtual items at each boundary (loop :for (pos . rest) :on positions :while rest From 81784ec54448e5a79a6f30746ef937bb79e29d56 Mon Sep 17 00:00:00 2001 From: mahmoodsheikh36 Date: Mon, 10 Aug 2026 12:33:56 +0300 Subject: [PATCH 18/18] add image-support-p field to frontend definitions --- frontends/sdl2/sdl2.lisp | 3 ++- frontends/server/main.lisp | 3 ++- src/interface.lisp | 7 ++++++- src/internal-packages.lisp | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/frontends/sdl2/sdl2.lisp b/frontends/sdl2/sdl2.lisp index 0ed1b3333..50bf770c5 100644 --- a/frontends/sdl2/sdl2.lisp +++ b/frontends/sdl2/sdl2.lisp @@ -8,6 +8,7 @@ (:default-initargs :name :sdl2 :redraw-after-modifying-floating-window nil - :underline-color-support t)) + :underline-color-support t + :image-support t)) (pushnew :lem-sdl2 *features*) diff --git a/frontends/server/main.lisp b/frontends/server/main.lisp index 67679b698..b1b376ed2 100644 --- a/frontends/server/main.lisp +++ b/frontends/server/main.lisp @@ -130,7 +130,8 @@ quits by itself afterwards.") :html-support t :underline-color-support t :no-force-needed t - :support-pixel-positioning t)) + :support-pixel-positioning t + :image-support t)) (defun view-id-hash (view) "Return a minimal hash table containing only the view ID. diff --git a/src/interface.lisp b/src/interface.lisp index 2a059935d..8a7f5d7bf 100644 --- a/src/interface.lisp +++ b/src/interface.lisp @@ -44,7 +44,12 @@ When rendering the DOM and a window in a one-to-one manner, no redraw is require :initform nil :initarg :support-pixel-positioning :reader support-pixel-positioning-p - :documentation "When true, the frontend supports pixel-based floating window positioning."))) + :documentation "When true, the frontend supports pixel-based floating window positioning.") + (image-support + :initform nil + :initarg :image-support + :reader image-support-p + :documentation "When true, the frontend can draw an image object."))) (defun get-default-implementation (&key implementation) (let ((classes (c2mop:class-direct-subclasses (find-class 'implementation))) diff --git a/src/internal-packages.lisp b/src/internal-packages.lisp index 672695778..32cbad0db 100644 --- a/src/internal-packages.lisp +++ b/src/internal-packages.lisp @@ -702,6 +702,7 @@ :support-pixel-positioning-p :html-support-p :underline-color-support-p + :image-support-p :no-force-needed-p :set-foreground :set-background