From 3587cfe009a96f1818f1f4fc032d88ebe6a55a83 Mon Sep 17 00:00:00 2001 From: ngc2207 Date: Fri, 10 Jan 2025 22:47:29 +0800 Subject: [PATCH] feat: add tooltip, button components and editor utility functions for enhanced code editing experience --- code-editor/bun.lockb | Bin 164170 -> 165081 bytes code-editor/package.json | 2 + code-editor/src/App.tsx | 195 ++++++++++++++++------ code-editor/src/components/ui/button.tsx | 57 +++++++ code-editor/src/components/ui/tooltip.tsx | 30 ++++ code-editor/src/lib/editor.ts | 46 +++++ 6 files changed, 282 insertions(+), 48 deletions(-) create mode 100644 code-editor/src/components/ui/button.tsx create mode 100644 code-editor/src/components/ui/tooltip.tsx create mode 100644 code-editor/src/lib/editor.ts diff --git a/code-editor/bun.lockb b/code-editor/bun.lockb index 27939335c4dda921192c51acf4c615c23238da38..19e2a6491d38744aa88ea8d5847cb7ef48a95dfc 100755 GIT binary patch delta 28787 zcmeHwcYGDa*Z0nn8?u3rLV#34sG$T%LUO@CE=5Xm0qFsi5<-ALAdo^85}G7n#4zH( zk0vO+C?W(!lp-bcE=8&$AcUs$_I}UKZi0x9KF|An-p~7otKU6y&YU@OX6DRnyBT(m zcRrcz{6X#NPYzd0sgmXN9p8YL_8a#9qkEUkaS;KaTo6~*97fVx2LhjQdZ zzog{eRN^jbApJp!gA<3urKUD>mX)4^ye#CV6UV`mGh3nTrYISi>yRLW>r2XvY*3WV zOoWhV7x4H$Q-#arK<`6N6_q#WeaNYN44Ovze`m)m{}F00g?=hDv;%HImbnwnq6)s@ zOf8qu#Y1*lcxhS9khrw|!2=UUmPY%j9ZwvkTbbxYZ}17A)cMyz$=!CKG&m^GU~J8uU69joz;y$EHuxFlvi(j~^-)kTJ57tf^&X8H;g) zM-GZhi|-$o(ofg=#Ue|s#RSnk0;RfB65`_1pmDy6tR=ImlwSu=`E#L1U6Tb$W4F7S zqWFQf3zFV62GwJCw4s;`O76yiQbqAesUygPXz&=m%urAYhW$0=;7_as_=Rp*@EMs zRL}`M4$m_aK@r%QT|sFUH-J9zUZ7ObvM@zK*JmDvV-!T?4M%^hCmr1e>Yag%4&jR8 z1Nu8!OBEcBkOfk$GHB9LlM-otxCdVE8BlVdEhu$uDXn--+@iKv#fLmwy0C z(<#m1`+!pUld$Pe8QYPdE;NV2r=c`_nKQ?78Fd;%4Y{R3$=pMmboWP4l5Yd0fmj4e zOXoOH1XE@lXa&$l1|MMLKZ#Nl1YPDSQ0kwJpaGzB3_2FHJow(As4pY4nUPUV3NlNA zlH1Q4$q-9O?VX;O)JOR(S`NT@Q0nl#pwz6d4f$e&{{XZsRbzzI+?@I5FM_yUv+%rp2bP^u^$l=OOmQbnze{0JkzqQSd? zQu!}29u!f_L7g*@NI(P(PE(Yco#a9=9h62eDPh=P=qOo+Jl&ufpc?Y~BqR(8PE1w& zz|&RBynvWjv4Sqro*VLM?p^DsD44&Q=Rqlg68jBK?w*pMD18$L_X$oPqI}*}W-K!3 zkl>``cwF;969*-xDeJn){DUx{hv=KK0xb5!$kDyv$#CDKxU{r{KFSt8)Tvwp_qU~1 zLh6u|1k|<~rAtHWL&&Kaaq-D1)Xs&Flbd_GOZoeJi&KEA_T(3xs&>23Qx3vTP?}Be zK$$wTKd2{Y3}|`KMxeAXHN%u5YUbB8^x>Yq*!qH}CVa}{v~n3Uan+!z&*G{;^bjbO zPJ_GTB3;7cl2R2{l%o8{9b~N;edUl}1W%LXdr#jT)fT^W6u@3OvBm zYBvCs?7eO1H3g;ayMhjp+$Jan~2c&$qyQz_F0$jIC@w6r_-x^wEkFhlh|eLhsHN|y*HUVc?3Dl zE0uI8D`w+#Ue_b2@uRB!?+zW+LRt7}pCLOoj_^30{>kglcZE-ko4C!sB&BEB4I=%w zPtMLCw%LL0IG^74#Hh}Fi|6)qfA8`X-?v%Ms%7|6_jX=&rZnGg?VK}l;xBF$W)yc< zm#m9#ysgy!Wot)xd{Er-h$%{2-lk$C>%yabY?gVdqIBVHd?HofVtltxlx2P~MTzJ8 zAaHfyF}_i(CC~P?u@8AZ&eyr-XJhqvG|r#!Y@E07e4Lwb&ELj8;?X!CDo(7w~MH!+1W#t#Kp*+EnjSJf>olmWoJesvDtV>kQ6;w=ZwCI3NsL@O{3KtP_u}WV3t-K8iX@JB$>W zM`b=%%>z*+D+6cg0Pc0}655bwSGH-tfNKR!g}0BW&$TKxZHT*~w1%V@)u9~*NA;sd zSn@>t5(m5fRxJZu1UQwu2iA8gWXREL;9~SFaF(W6fm+arYFS7%guEEfMFYME7sYeR zN2;nPpHeM~&EomhY-+JG+&L&p>xO`CD|G{`+7fVNk#YAbR`!JF2ide_ERh3r8P#$U zTw~tGFH-d`$EQ?}(t2b1*GD$|!vHJ+*Fsm$g}DN7xXfYzz^R?RxU*lBWeHZm`nsRz zkfLtE_*Ay4)x3F3%_uDymjG!2E@&picZe1 zYturo_`Rmrm0QQErGq1{RK4^%a81EEQajmwo*iOioq2wUP0Ohub1c-q>;R7rwW(DC z`IOKo_BPKCrJ1OO*|ckc2u2vdT&ir1 zSw&Hr>m2#m4V<(qP5@b^s|ksVIiMgXNr%5uFNduwI6` ziq*!0ejyhRj^Z1dm`lgO^(oAI4cDu-I(G;Il~u^moUzrF@x}D+9|KNWp&AbSfeQ>N z^dFuL1!r^vxJ}@2n?Ny$x$70mcQ=hvM~8CfW>M<5p**Hpl=d9MC#NczZXRYjNG|OG z*SFB!5Of`lr)=~{a7KrqVGqE)S(ulEi*%>La+|@?*vWEbBMKv_l2yGF!DFJLv@a10 zO?4Git2)%@yCHlHtAwnNJR1+rXc%I3KRB|9>5BLdZeVs6T_Xm9BVW+yYF0}DxTbtx z`ADq}=BD(K>}7-NTIkhvD=X8aBw-NI&RjhWb!w`mb+S%Fk{J>}FyQM&1=IHY9m zW~5?uSvmL-r>90BH3+GO4oD>EqL^k<6luvrN~(Fit|$Zb+zCh}>Z$8U#p|gz;JQqG zfs`y!8pAJL8G@9|JyIyE+fq^9qO#glq-X{sBr(H|@oc-zVnGPB;yLz6OB@17nUczeCdK;X) zU@zoaC!2O2GQ=d^ZB(*ad=Tp~6kl2&r0BYXt0%4&(Cuu~?n6dSz&66)8Y?dpxDSc4 zYNNpoL!N#MrridI=#f^{u&z9&OO!Sc!A(`64VX(C!I27zgL`Ul2x4%yZu06OHAjP^ za=87$EZGdsFbz(9Q#Rg7FV__uIjCR8*-W0@)u#Ob8R_Fb5Keo)RcNb=)zT4MjDCHY zYsfK|>sT#65XblVM{2%r7xp{m>s#P3%`=_#Oa5GNv{<4xT=H*%!>wMINVQ#e?)+Ai zHo3d(A6!^4osWW}{?zXiHIE+V-2yeYFSrPqhf$gX4ht{Fla|K4g?Y5DyY)m^Ag{P? zvn#lUvRp+gZnmSl+qAoo)z@V-{=vPZhJLr9C4!^nQpUz6aQL6%#>cAq$MGpWqO^W- za@CP4E5V_=<)EsT-aMvfl-91dY>C3%J6N^%!O=1W4jps^9QlXhxbXSL^C<|>PVurM zFaqd^JaE)&7|qD~PJQHX==ZXg_TX^2$5k)~sn?|vto~|nGE{0Om=_Wn&@temq$a{) zBe+O#r6?TOJ)Ym&riJ3lg1Ji`cCcDL1lN|kghjH8JUiZ|)#)b}cnl)?>tk@zxkCX~ z%N=kr+@(XLWoCa|Ybm8wNtB+U*KmWI2(GKHu>~oqTVeo~e_fVxt`X0v6R9mmibm2|zh8X> zu8Ur>-C(_Be;eycJnsLrMBKn6!#8N-&JVr0!Qk{;EKMCEV^8MQ2WMOg(Yj1;~6{+bm5c;$lDw>=4fezkiaV^e0~H`>yOZ z3_L<{9ypr3GWdQ3_Zm3)BwBW|KIMi*T1Fs+RXRP=vK6U5JZE^MrD+z08P)JH&mU=H zKXYxA%~By7lT&xBPd1-2D$24F0zAp3M{19eqBT~(h*(0Vkjb3zhE7OO@XG1D2V7IK zuewa-&hJENZKujo`t6@(A~?)!xO5h&6uqK$?{VibQS=sLjE$Zb#@H-%a`dZ5tw@&0 zwXrt#1&_uVk78pZGb$_k`%;C0RsrZBS_}vRRG0J{TwqGy{qQ zF#sJeQnKF$?_>1>n8`ZDy@-CiiaH_(w+6aHxR~q5t0*~u*wyvklxlSIOP~6bUI0}b z50G9T)UO{{&-ILcl2u-$q=?m4FMu^wKZuectc$uF>z#fOB{^0n{dg6n9>q$eA1PEn z6~I!V8^S`MA4I8QECBlPDoW)rQT3K$66(jRDCrsP`~xNXmQ0)&Ka*Kb*O&l~4x;2I zritzzf?GdcMIDgyo{|3|rSk6^a-yU+9iVDCK*tMIdia7scVLFpQ;1T*j|?gdIun$R z7b)q@(xs9T{~y2t%s1pjN&YcFjxMC0A;BjA9YiT(5kT_A03H7obwd7XT}x6b_ZdL+ zb3;y)?0#YJg;cg*W)wr_I)DnUH)tLx9YjgKffyV_Nq?h3zXhe^Rg}to2N2y1(6JdH zK4S|`Zonacy6U(=PlHkgX94p3JV5+U0P&XqN8p;l7a06+prrst)(uMK9KaJT4oc-U zP}G;9lrl2hjf~QubP%PaCr(tb9H<6b!Qd-VCJv${LF<6JfHnlB3Zg)1Xj*`JgZ2ca zWvMSH1?2!xeTK+{6i`Kj427Y(f}#+m0_mV68io^9FaneeW*Gc9%EUpG9C;s9kA6cw z9hAy_Xz)Z`Y5YGyq73K;Bjf)i)#LBKQz3QbA;Z!C1uEnJf58yk`ky$4`t_(cT67$= z5)3^ArRaWc$cfU}F`P)G67x5d^ol``R4s=7pQr<6aF@w)AubM%ia8lnGpI9Z;UG%+ zB|u5!V(_Ji!SP>FD(7nG5v5S~FnCaTNiJ;&h*Gi)PE@e0Aty?FIfExkNpC~$W5|h8 z?3Xv>0fzjqX=!NVcu_&+1?U&5uA)(#D6IiC4W20F*D`pbl&o#=L@B?H!M{jJUKeue zhcF}mMM|P@>K8hY(BmNzlpJ^+lngWn#s5l6IvJFb(KylC&<>Oqr?-uKq7+xXL1}Rs z07`ZSg5rN=kiico2FGAk){lf#7-A?41trhZ3_9G%9|=kaQ8GNr;E7VjnV=;=ry6pi zl*}>sKhcaAGN|Pr83kq<^gp0f(QHt1h`!0;f8}FCzQCXhNr;0e=`Aw&7b%IB7;>Uy zm%B~z)MH?okwKI)mK*%5DCMs(^j3n>P^>ldUqvZY^N>%DeQoHyK;;;afVyzAp+J<@ zj_sgS;SNyB+C`_AD2aCCM0$G+x)+q>`*CswJp)SiE|Soor2mr{13wuVFH-XSGUSwX z6(?%xEklnewdgm4-UFoy9vk^YDM>%tq=P6WpBsE3HDiDTl*eF|JX1l5cc5BcqLgnj zaO>FH*ACA0V0t=r<{ppaMw%WzZuB9Yjg~sz(mW zCpkG*_~?N&>8Ar^hn_g-AWHmjVsQL{wlf4&@c;JFBNI0MeezKLee(GC$-{UA`S;1= zpFR5g`{Y3jv`VY_-%!%~_sK(E&;pG9`fK{{lLvLtzfT_jK6(8A_vF#Un7#k=Cy%v{ zM5W-ytv?^>`hAJgp6fO=c>I_>9~@G(#jpE98tz+tYGcKS=@(mFT$s@&FS4|c{m|tr z8}kngIMVUriBC$N+%`O8yW{z(H{a&nw|nvK`|NBIAG#x!d+l)H$9CA+WFELPmhS?W zzTM8U`Ihame8f%{J|o}G5AIChF8l2)hj-f_%TMfb;hVrsQUHEozoVy>4R9m_X>y9@3U-egZK z?|;yRFWO^gi}-DDUWZ(G=e>5egfG~OmVvXN)yw#@eQ4QX7d{5Qtl;^FVtLRJ7k&o5 ztm4&=pnc$Sj@a2}{3N)nqwwsgovq>7N724xF1!HTTHfFo+6Qj#F*`o!T|E}d*7GLE zWAROK7S0>^ZJfX2(LcnpulWL;H}Z!#f5Y3Kh-I7jvJ+_6Nf+*N($2o)-A=}`&3p~c zTex;AmTl#6IB(-$;ru;!KOM`q^F*9?@GUs+Uj1w=+t0`0e1MLhb1XZ@yWxDEufh2O*DhgHE+Hl^ z+1XG0D{%dPapC^I*x4nX_zOnmvJ2k_?lSkjj8OqM=CYk#<@w-7TtQ4+v9oJ@qs$GCP2?E^RHmYo&jUxDj?8|}MoXBM7#8|}M;_JJ$Tz3-rX;KtmsGmYni z8}S?3_nV!S;3I!S`+i6Jz`5}1zoUKNa(=fnSAG&))?KvkuARB_?7L{+J+u#8Y2M%- z+6Qj#Jv%GIuY#L-AMLwuXXW^;`)J<-v=5v&kA8smfm`*!&V2bpa7!PeeGl!-pD%le z_B}%T9@$v{@Ae4odyMvh3*_2kv=7{%$97hUe+91p6SVJ%omJt9Ptd-nXdk$0-1{lo z2X4$$JFCv~!Hsx^_C2$+ntbFlwC_3E2QHXbe~$Kn%Xw~Rb@<8Wu`{w*sTol$hK0Xb6692XV465df~-IY z8U;d-E3yM2s9zC+0upf1pdyQ9ABxatA6&gc2pV#0wR^!A+Y z;}AG3k^Z_(QJUaaH+bcqNw+d7$w^80J3u85GFPf~THfcCnFE8q7!t~y)ZHzmMM&Ra zBC8&&U>V!N@KEZiuw zl^;hjC(AeZ^?)1c*dX#Y{~9YkDY5o|RQd8y|H~{9Sc_d2w`|P8GHU|93{i=<$jIB3 zV5G1cr;+h?kZa~&Io%QMo3MDxEWCPl)?Fcuu6Z9fWtH1dGQ`;_m!4P^<>+*=e;SLT z*X_@q%Y(%4B9{~@5`)9!sYA`T^pg!8dPPYe@#vtxou(v4SUF|LvJDxWQO+2$DTa*R z_|^gR*ZorsA-zx!1?YIskkOYLdS^}La|{`M8~M?=Tct0*l;;c_H)PWc8GU?d4$wi{ zDv%z1A+j5K=nDBMjy@sd*J%3J8v1lhiu7R}zgN=_Zpi4_+0rdPl$B>mpy0;;t zKVirJ_=KaMl@YVV*<7|frXoa@fZ`Y{M}WQ#&=-Va0DV!QA>9ak18f4m1?VHrDquD6 z8SpuS;SIV+dZ1j(iVece6`90923 zX_P(!C`{~1&#p60E*eez)9c`Z~&kuu&uy0;CtXpU>&d? zs0&mBf`A%8AW(t6TKOX32lxZ@sn`ohffHC)6#Sr4|EydZGEcx2a08qH3*ZRMgbuy% zqCfn52GD2uC%|JM1#)_6u^2i_fMvi+fPV8c8<*FfK9-+z;{5E%{XlVwgTIL z?}6>W4qzv+3&YX}!U0GF z(t%;X3@CjDd<-lArUNvp^l@qg@CMKh=m2yCIsx=+Lp#tKD23Jy2KoZ;!`?LD10WZe z4shT@U`7T`Q-SvY`oMJ&v^GGW;aouJ_Zaj={Uh+70t6IcwTSpa?B8w?}>NkA3gAmm{{6@cDq zE`@9kKp#mjfWHaQg@Y~%v7ns+qJ02b!{dQOAP(p)`O9hiN%pQ_b69EIF1DG&%30_}AzdWSWtBwI zT;_z^%5e}^;V4M~W7a^{XbG4Kd;rk0@V;0xmj#r0A4%QH3v`lRM>s7Y6su_fjXs4W zfvlKC%yyVH%+iaB%sI?K)SAPbyh(u?ITxTtnvI(y+~KJ|WzPdlPfa!5o~}X-E2)tQ zy-#%e?N@?*RZ;576~J=f#V*y0LPnjC1yB=~0TTg=p^tU5gO(t<2v`Vw3M>H3mVRQ$ zO`ddKOfPFiG{!2;OEe!WxyPVH3q*6lwxkJ zSTm1>X*-dmIkH1sorl}}3nF|zi_Zu}K!yM{0SZ_OOu9e@0abx2fFD4C?gNwq$^vBo zvgirw3X}xsqVEi<0mT6apcuday486O@(7?+mu50n;0)ys5;VPU1Gj(z;5u*#p#HcD zdJXs$xB^@TegQ~MJkc9~2HXVh0e6A>zyshRK+F3x;0f>)P~nUtU}0D;$xC9K0Lmbg z04hV#1(a4v^1L)CEnaQ_Eo9z+7eEeC4^YdgwUq(7wp0M6O?jw6{-6OsMIaEU1W?aa zqo3|jK~ky#N<%>1Ul*tY)G}l=EX3CaNWUj|>NOw05eSBibWA;Jl&SxsEwj8i)EP9+ zq)-o_7$Ai(fLcJqK!zzk%mU;P>5&tZXUbngx<1ehXaqC_A^|H9VNg@20eDIyFGE)# zhJKGq%1wbLfX$$dK?!Ez*O8_QNS7+0O37d^fG*uVfbM`DhykL37C>{L70?o(GH(NK z(fD^mq7%>&=m5L{v(_E#DBw!$r2n+xyp9+lta)9ALGB6mR>j&Mm32bSes@oqrk7N3I9f%mHf2_%>jUp1&rFj6GGw-98q&GI2LJ~sUMNN= zARjEk3CFJAC3SB2R%k@`^!ia1@}_^vs;Z^U?LAc1BcwL|!^{qRuEU6(q?1vv}8U3sv{xrFH| zt6MuPf~v?8ZI&=^yff*y1csK2+2DNFLcJ8!S0{*4Pje0j!cb`Kh}u|Mw}=CzepJ}< zpm!B|?$Fy4dBpzn>&wflEUb22Qd3$9|E19TU09dG>{BrioNp^tnmygj_i3r9I^$GU zAMGUdiDEvfPZIW3AZNvqrL3m*u0?-t&HP0aU&h+7d!q9)7UoAQ4VKx=5Zk9!-kIR; z1K+}Ght&>+)KT~yW8PvDshQi@jqpo6cpY>Hx$KGNKl}Q(; ziA)f8m$Np0=B9tM%jEs)GwGXwP)EO$uceEN9xGU=>Q`J$U%^_lU~z5*^Nyh3o0dT1 z7Tp`sr(>xdE+~KwqAoJ`Q|yp^e0BM*G0sIbdpU{PD_M<72`EdW|JOElh|w$22y<)2 z%|2BeH}>px9;U)D4)E%C@!3ii=4;L+&* zTf2U^NM*etp_tDW`%u((DOifgKHau$o#* z_r915RbLf8kXI{{L%vM95kC(KM#SqzyxDzm4SIg&CXzHnIs+vd)d6FyHkP@};cU+K2%*2dD= zPBd8qkNzXlL43`PD;I_xZ##d{L#v^Ou$dsXt%1vO9YB6HPoE2jJIu@o@ za}-C{VU5rm=Zz0Ek?YaDf4zLkPH@E1kH>vc0t+>}EvX_URgTD_4si| zg!vFi+|XBsy0Loet9;E$3#;kB`Yqf#(Y%Pbv9ZQgq_N1MTH1*vd90>oe0AuHp?g>v zaXpV!WQT?81`OP#8sgbk%u8i8#o2F}m!G+Zq`4QB%4mw9SCs}eMX&Fe*Bf&CO3b#F zU%q~&T8Ukx5lRE7#MRXQj4|_vWdT2Js<+}%QCV{1!5w zg*UoQ%~X(0Fp70GrLQPvbcVS@sQ09<&HODrjvCVh3xc_aXi4XUD8K#z_hrx1XuUM@ z`23@fgwY(-9qWb;xS&x4(FuKX+g&l{2 zy>}G$=Syw>r^DwIDnfU%P`^L-O;n?hh}yW+bqy7nJDFFwxohgl;yIUNC+93hAJLlK z02depq6b3h&pFcLLf8H{XI|-};x?=k_}ylvx!GG$hZ_^o z_ircFkM+dL4TY0RoZY}${DV=Fjr243hBY^t`^&)b`&&<6>L_E9>;C-hlqigrzX;cV zK7IQ{h+FySjsI@@BL2F4f4x|yMTlBhEd9(KaLrx$ih9u)#qj^ha{9+bQ#GfoTs+O0 zyCOo=-ORiqUS3O!Trjum-Q#nsa&j55M8AaU*W$wwV(jLB6v|fXM_X|DXloTdTX4;d zw~DsJr&>k-E$nsYvAD6o6H(?pt60B<^>8wIv40C|@dwUFt=vGoyY+=Kuz7SV%529J z4T255%**lcQf$#G?4w^O{&{5mF)&`fB8LC<@c-=uGzUg5|Ly*M9XIzsKGNoNYo+H; zYxNPqeX)Fye(_n+jn!!=2JgZ3xM4%NUFn}!Kr`nuH0UmLXq(nE(;H9Ou3N2J8{_iw z6Q~=zBaZFCEnB9D-OD1`Ji+(k4rRI6xtGmm&qe$`+>@ERAaC?6>(PDMtnm)4UhOdb zCfVF4dEN8tcbt88S1HPA7A5xX!wt5vwQ}b1(2dV??!@Bzy;*jwc)ky}w&q^UYpXbP zuX|-u=^_Plx90k{M!!+YZStX_oKvFBemtg`+dDt#F>7qSIlG@1DVQ5T|I(z2)7@sT ze_xc-$R_6OhhOHF(bj6K>W4l)*rG^doHzjE;pQIGoz8x@VDj(de2Nsd+2lfPE8f0u zN>+ZKqMRRv{{i@AZd*OxK7Zh~WzMaO6iPRi+n>5#JQPyv$(|=gIdvL~qytz#%#E4P zp8am_iqK6B9Po-Dv>x66R%|6chDL{d5*4Xkw%sXJcxV8c_I?T*W6w@@vDYQ>p2ekrAY64kqm_hb3f{Z z%f=44;Z)^tk%GBn^@0S$; zAJ6@&Nl{MIXi@SIJ+DQ}EBED(((Wv<-P>5C(O=jOVc5)_wzC{o_V4Nb+K3_rb1&{t z_c2{AeBGgUQO;tKgQC9X=G|K^sbU(D`hjw}*41QYvOICL3NKVasQ69_3Wuj^fc_EWR~6irPnTr(^dA9I`U zE9bnUsS(aCo%6BuFk)U=cjPn>DNiDJcp*$>?E!qW1)D16L1_)rRMhHn@e3@ z)^cs1+j{v>dVI?ggP_2siv`C~yRPo-Ywk{7|D)g!1GjmgIy@Wc%c)cdH@742_T3H3 zoU;W%y1fv38aDr#jo9`_+jPH^f5Gq+D{+Bn^aFaz+=#qO`#o*r+`ili1-y%+rTTL* z^au157JcZcZQm59eqgQr%nir~RWILr`G>vVkZT7N~KJ&xI-yhx3 z70+aN5u?ACGWvJv3Fc8b7#}ILba!8agv3GZ|R6n6ENewD_1)+>GKsRPOlK)kGYNcMB7o{n1j1oB8MK4Vfcbr zbrKEhFCL#n!%Z>*Ln2zi50G&3L=NNcs`sk|u)B zBl70`$UMwxoQM_{=&u$CPFb|7fPPm@O z6Y~Bu_(7RjUiN+=tDEyyU+oEdBy!HO=B6)|OKVo40LSV#ScG7gmY(avSmDZAT9uQvF8Lq8!7Opn+nqGVZuG>7ljyE9RDZW^?)Sd^#ERKd2i~b%lruosFCZo+hy_1^<)L!~y>-_|0&ljc zVzp_qn0FD~*)CZe24%}c0Qn<{X~t->104BQ3_`x|U$@w3kZhhT=%scaByRnL2UptU zy(}VQ`0#hSrRUr$UNqgphKi`4(Us=5@FlMG>^QnnNm`1G*PG@J_WgRh_1=4V)JEil z$gF{4>d)}W-15GAr(YsI-MQyVk?|SgyPvTjn|tHGIgnKj4ISUBNTFqlD0RskS}#9y zkNPh^>Nw;3^?U0;(U{4V(!|@B&|R;ki4Ra9+}su4+jT~dk^`oYrs1x+Z~hHic>V~> zx;W&7%atWXoVkQBlYQdFHi(+PU?2=uEs-vI{Q_4^-c&m!Rzc10a=HxawN=ZNd2e<+ zUDS+~_>YP&mk&4h=il<+@|I7ZZkvIE#!6@I;2+WQ{wF^?446}tvsH|_j9@UxIkDz4 zdhxGAQJ)yEJCArr?m6f&MzpJ6Xf7+W#*o>0Wr1#(Gz4&INq-G69rWHG$?pL;oayc`zOC=;kWcul-|595P`q4 zn$D}CK-aZy<3zigjM`^a`i>Jrenm*7jFT_;{c~dm$A8R+7ftnSx8Vn4%{v*JdqFyEZDQ zuWRTp)nTJCGz?pwAKhXOlqMO=6FJvVO+=CW#)` zVJc{n*nb1mI!Ux9+G3JeN%Ag}MCJ`vwpd;C+qvtwfi?f31Eue`-xqu^^hbCVD!(+C z|As=hQJ-$QTjuO)*&?cBl?X1tO}Y7xE$r|s{cP@4SGu1tnr!}a4A)j9ESh(C{`#UE z1n4^jXjU_UKagls=w8(<@eE?s?5mdp!HrDo_XuW#%nqO)mW}fAYk|&jL+4x@F#28X zwTStq$6+sYQJ7+OjbVX$`=gtzp3ya)j$~1GY2k?IGQ&4Ky3W0c8L9`fXK~%Bq7eu) zVoD!G-@o`0h}+3b5pWCloBx#peTgwcLLXKF#m~(P4E5Q!t>_H9YrC! zSTwo~8-Ki9sm2x5+3POeaN{^}SFFCxnwFt-T3lk%aQurnE#Ep^^+wG#)$n_%J1l_B z5`iFr|G`ICdd@%HdGx2TD=K&|0*}vand8cJF7@2A-q|%G?hdp0gyLR=#1rd>?`0!O zJ#)GzD{3+^@9R6PF{_iBl$_Q$C9Y56h~V_ZI{Lr26`U5=JM~YpMWX6RLhAK{;G#~SW9&k-}|eTL_l@bB5GGws|s5s z)k)kS4gw#qJw&g{YJi9?uXYzhDx*Y|Aho@C=C5j^P6gFZJQ;x8%|WW0c)x=B zX<@PJWU7+5R9^KI-2>H+^9}~7mzii^QEiu(S3`ZDiO@he@>*51^ubE1yKo9tkBO;d z`%y);x#;V!RuMPLtB&GnAY|~>twc)lu*AXrg8L@Nr;FU0YM`iF2~K?!0QChyY8}$- zB0j08wiUhnQ82fXY7=v7sU^kJN@`8rJtzEIL&Fl2(^K;@DyyQHba_+|in&x)ONe&0 N)CGBGg4IDC{|}Pt*yaEL delta 28014 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 diff --git a/code-editor/package.json b/code-editor/package.json index ba41223..5b9c7f9 100644 --- a/code-editor/package.json +++ b/code-editor/package.json @@ -13,7 +13,9 @@ "@monaco-editor/react": "^4.6.0", "@radix-ui/react-scroll-area": "^1.2.2", "@radix-ui/react-select": "^2.1.4", + "@radix-ui/react-slot": "^1.1.1", "@radix-ui/react-tabs": "^1.1.2", + "@radix-ui/react-tooltip": "^1.1.6", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "devicons-react": "^1.4.0", diff --git a/code-editor/src/App.tsx b/code-editor/src/App.tsx index 85eac0b..7641025 100644 --- a/code-editor/src/App.tsx +++ b/code-editor/src/App.tsx @@ -10,7 +10,14 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { Palette } from "lucide-react"; +import { + Copy, + FileDown, + Paintbrush, + Palette, + Redo2, + Undo2, +} from "lucide-react"; import * as monaco from "monaco-editor"; import { highlighter } from "@/lib/shiki"; import { Bot, CodeXml } from "lucide-react"; @@ -23,6 +30,21 @@ import { SUPPORTED_EDITOR_LANGUAGES_CONFIG } from "@/constants/languages"; import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker"; import { connectToLanguageServer, SUPPORTED_LSP_LANGUAGES } from "@/lib/lsp"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Button } from "@/components/ui/button"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { + redoChange, + undoChange, + formatCode, + downloadCode, + copyCode, + moveCursorToEnd, +} from "@/lib/editor"; self.MonacoEnvironment = { getWorker(_, _label) { @@ -37,23 +59,42 @@ function App() { const [theme, setTheme] = useState(DEFAULT_EDITOR_THEME); const file = DEFAULT_FILES[language]; const webSocketRef = useRef(null); + const editorRef = useRef(null); useEffect(() => { - if (webSocketRef.current) { - webSocketRef.current.close(); - } - - if (language in SUPPORTED_LSP_LANGUAGES) { - connectToLanguageServer(language).then((webSocket) => { - webSocketRef.current = webSocket; - }); - } - - return () => { + const closeWebSocket = () => { if (webSocketRef.current) { - webSocketRef.current.close(); + if ( + webSocketRef.current.readyState === WebSocket.OPEN || + webSocketRef.current.readyState === WebSocket.CONNECTING + ) { + webSocketRef.current.onclose = () => { + webSocketRef.current = null; + }; + webSocketRef.current.close(); + } else { + webSocketRef.current = null; + } } }; + + const connectWebSocket = async () => { + closeWebSocket(); + + if (editorRef.current && language in SUPPORTED_LSP_LANGUAGES) { + try { + const webSocket = await connectToLanguageServer(language); + webSocket.onopen = () => { + webSocketRef.current = webSocket; + }; + } catch (error) { + console.error("Failed to connect to language server", error); + } + } + }; + + connectWebSocket(); + return closeWebSocket; }, [language]); return ( @@ -74,18 +115,6 @@ function App() { /> 代码 - -