From b46319c4e2b5f7bd8cb4b01acb3c7cb415b4da8c Mon Sep 17 00:00:00 2001 From: Matthew Breedlove Date: Sun, 24 Aug 2025 00:22:22 -0400 Subject: [PATCH] Adding powerline widget auto-alignment toggle --- README.md | 6 ++ package.json | 2 +- screenshots/autoAlign.png | Bin 0 -> 23929 bytes src/ccstatusline.ts | 7 +- src/tui/components/PowerlineSetup.tsx | 28 ++++++-- src/tui/components/StatusLinePreview.tsx | 12 +++- src/types/PowerlineConfig.ts | 3 +- src/types/Settings.ts | 3 +- src/utils/renderer.ts | 83 +++++++++++++++++++++-- 9 files changed, 123 insertions(+), 21 deletions(-) create mode 100644 screenshots/autoAlign.png diff --git a/README.md b/README.md index 3460019..943398b 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,12 @@ ## 🆕 Recent Updates +### v2.0.8 - Powerline Auto-Alignment + +![Powerline Auto-Alignment](https://raw.githubusercontent.com/sirmalloc/ccstatusline/main/screenshots/autoAlign.png) + +- **🎯 Widget Alignment** - Auto-align widgets across multiple status lines in Powerline mode for a clean, columnar layout (toggle with 'a' in Powerline Setup) + ### v2.0.7 - Current Working Directory & Session Cost ![Current Working Directory and Session Cost](https://raw.githubusercontent.com/sirmalloc/ccstatusline/main/screenshots/cwdAndSessionCost.png) diff --git a/package.json b/package.json index ece0603..f89a9ed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ccstatusline", - "version": "2.0.7", + "version": "2.0.8", "description": "A customizable status line formatter for Claude Code CLI", "module": "src/ccstatusline.ts", "type": "module", diff --git a/screenshots/autoAlign.png b/screenshots/autoAlign.png new file mode 100644 index 0000000000000000000000000000000000000000..8b230bffb7f218c9635f745c45f9ad2a5c6a454e GIT binary patch literal 23929 zcmce-b9g1e@&I~boj99~Hg-12iEZ1qu`xEbZEkFBys>R_W83!2y}zsPz5m~-Z)SR? zyBbwp)!kKf!sKPe5aDs)0RRA^gt)LG000jDnf?I_{dtEXI(7j7;Oi}fgybcJgb3vw zY)vh!OaK7!u%r|iWu+rD-w%&jA#gu_N<~3ie-WLA_6*J5%PSm>Fi+7J8sswY|qoUHqyrUK3*NqeI_6Q zjF}{8gyIAzC#snt)49~IaD4iR@94~ zAMbi1S%Y#1;Gg}*8m*xv$KX}_^)G&?rTx5Aq4{+QGQCu$m|fUhF7DakqEj{ z^O2mla>MzIVpEI{Z;^_-?SG&3e?TdSP-HLvnEd%_DjcdKqp#;kwL!CjKlBiRiPna?6C5%8fA{nb^%2on3WT4TT1 zBY2{gomRNTwk@?k!z9|Z5?aEcX)b%nOzOsrELdd1p@@)}UsKDWWJ4P$b^KLIu)u5! zp?&S({x1HWh~=%d4q<8L4|bRV?+mZq{_z1qnj^<-e!-usNBk^DhOHS_h2T~vdIiZ? z=B(^(+Ph-2V97;OLV|(p<)E+u>e)wphw67 zBG?`Q<52igLCsiRV|Wb#;1JYx;A<`lB~Ew{8X*y>Uu|xbJdrXmNgzp{_7=ejx&>Az zq$M{*o`4y$J!C*1L)!m~0pb!s7r>-XehL%PEwu&d3Y7tM(5(`}D z(^qfAm>hs4w1|*J{+K)v1K~?(xIlk?Ux{-GxH4QByh@Cvz@L1Ze0K#~dA%uh<}Wg0 zzj8CDcn|HEzqW(7Bk2Uv2@#00<es) zh-&t4j==8n>@loit{_^#KM9B$AU9alkEnjBMqE<0VrwAa^6%YJwl88g(>@ncbppd*G&^nnb~>>+9r)#cg*Jq2G0Nl5ZZb_mhGlf(|kQ6+KEIm#5t?ITF| z84DW5CC8E$&=%k*(i{;TL8M8u61K(}4Po!n?rL6>T{B&qX_Qqof7eQ;Xw_}dZcu0t zyZ?R_K}IS>_q{iu!bN z9RSY`1py@ol_i+fBM>A7|E7$gk}{I#P>Nd`QleG@5w0#GB+_6QZKn6vI zTL@dIBDp7dkmznfnGO~uBb94in3=PdA4T7@$1GLG_j zS!C&q3Xe*HN@F=|DX)r9d0Gin`ETWws-Gff0%jkf^{5tvU|*Y$URSX%;>b^>~h?2gmhwYL_0IOP(JHXAU9=pNO63z zV7o}b0%8tjUNW9C2AP)_4zZ3gRxo)Q3bQ(}Xc{P+I1OU`7z4?&uA8lzfd5)bCrwZM zwaOSIb0!T{^djAQV6@LQ_I08v-De}xcz}77xt!^QsW|QB*Fid4TBlA-cLMr z>a(!R-4cB75kh#$bk5+INSbJ;b4pQ9fuL)z{9B2)NWFMq(_+KjXxW$|ZDfjeLwWPN zHK=vzt^S2_H11FG{ITElt!v*8S!hEv(M#wE}b5$UWSiP!fa7E!89Md_vxxtyW8ZxEmWI7ZV+Y=SrEF&Y9211#=G+K z>~8WSZKl>)!}&(=8u{u^+t!o&-u~-;js7<-%ro;UJ93a$uPx zk|DAwzNbCqw*1RvWcH8p`7(s^&IQ;X?#Ll{9oj$iv^<30h88%RWEI(*oQ9_>jqnH4 zPsWdFaLo~e2D|NtuhcsG-W@IiH^LecA`|Y4Z{^N-WO#I@U|A|{@N6Wlj;*6@&Utq{ zihlQ(?%h`HcP?bi^J;m^9<46i^xe1}P|zFeU|D?m)6tx2SJP?jwz4CokaDh#)UoQ; ze=+i>Tvv_$57P?0wqwW7`<9(MCN?a#beq3xR;Sfx>~Fu$Y>TJbR9~#N;o3F6=svc?Jfy5%cy)Pz9zlCstzv000|W=$-P}~Jl5U#U z(r+5`7XzJaw}0=lPHqlQT=Ab@?fDu%?g);2q=CEbgq@UbrFXSIrz|f|V;AKY%loUK zbt80RI)^`$-Y45_qt>&YN6)IFw@SABT((^jE+TkKyi1E%_!`TfdZYg~QF`{E&HoXuTDTE>T&%k|~ zTunQ&FwOV*x|#hx`k0s=>zBaf=fkDxL!pT^x1fE&w#g3wD1mmVxW2!C7jkkT$W5Lp z339-9`B@_P_x0Mwsp zSO8dv1px9h1@?L2d|m(mM0_v+=JSd6c?su$|2r2PJO|?6X~2(v6ckVrl92d(Dj7ML znAkX)+d8$=dt7{0wP2yF?xZdw&1qz7O=nKhyvCOixVs&mvAgc!#t#anjSfxVX@{FwxmMn9(zEaB$Fr80i@qX+KNQI=b078MxBgIFkHdCI7BR z*u>Gu!NShT!q$fHAN3j-+B!S&5EK8Sq5u5;ub(Ea7XNL@#_?an`WztrKXT|9=s@)U zsrwU^`yXF9iQ7<^Ml9|84PqFxCHy$-=<=znK4%^Z&+F zaWrudvbFwf(uw!KocR~>|7QLRk(>S>BmW;t{2!VB`Sp{|yzt!g|KS-gJY#&H834c! zkPsG7b_F}jgjvP-gVq&tE_Tr#z$}nRu7V*ftnhilsaQIxODQJK%kxL%LKdmO7-H<**}5i^Mq0OQ%$PQ2JQT~ZS7Ofo6OMbyM+)pe z;5X|Fjx86!`j=c2Uj0ANB;UmdP8V3yoechOD29OgPGZN|X0jssA7rqv@am#nK_J#8 z#jbzBrc)08zALVq!R&xylYF=9^wKLu82I=vwv-mvvLlLZ#qHjh4OumxnAK z#Y(FqSNXooMw8LxcoH!rjZW`&ib}^x9<}4SQj#QUm6>l2qsg>cM>|o{5!bH`Yrknf zUlY*CB*i;CpH}0SEnOwpzG zm}Bd3JeY7&Ykj&okXo)aDbyEeMUil!KTr>vVBY~!Y1W6%akmD~aTXUzXLCqB6yIuY z%>L1}X95SJi9@{aYxo%HfY(_UGtf3R@ISZ>yIkx zCL|@@CfuK_Tbbkz-||Ev3Iv1T)6?LiB5tME3A`T#I-ZYdG}>HitTsAyMpEdj>a5pV zRAxDTrvkBBk$E5aRV%fr=F8QPRlR15WUg0iJBQ7(y^2l}Xth{35?~U>a|8kkY&SZt z-(N09?-uo{t~wsKBhvk-m5QXRGsM}j8I5C~?@mS&sg#^LV-nZpUJs}9_dcl>FGk>{ z{E!R ztJMYp73pJIZ*z)ZfFA*b5C#cptSI* z7je5?!zSo6jz|e-3fW&Oct5PUxL?9Y-MD9QI2Li=P6^d|JlI$)R%V)dV$}mt_?(ZG zZ&K%Iq}P<>c*uZ}xtIN4^M&m@^>rgMR1GW&hh+wc_jY=}V!Oyk9x2>ImZDAE?(rZ?Iuf{@cTwxR=@9{y^X=j* zG%rRQX>h)16sG_tYq^WyV>pADR zo#)%#qQEPNg>A#L&eVa`W)%y_x6B5GfEjyI^~0yO++Y+rmw%NLd~>DAKEX=9)7%Ma zOgJ(X9|ZJ+qt|U~T6LP0Q7n}F(jIP<$4CGX@MPV%R>Y^Ts)o&E3S>m7;C%w9qh5n~ ze)a%OLNSLX=RF*gwhZRTw&O|kaq5jf1nFBKT$NU%jdwiEETIVhv%m}LB$IDI2y&_l z1p!L{;PSE;`3JO7Unr_Ov6Scv>YMk++k<9V+$Z()dD?BBZ;$e4N!ILp_Q!uYuYEin z5Ev91`gUW&plE+<0_;DfnT5wyw5-b#p)H9upOHJ+`Fb5;Jd!Ap%1#1y7L4sXe5r)Y=2_M8T!zPP$G^y+o&Iv( zDpv(N4Uq;i@Hh1?App)!Au_f z@m3|B&MaZmv<3Zk)@^>(A&W_<^7^Nbc+Sucn8j$DT2y~Htdz^-elLYaCvsli>j?%SCGYxv; z9zo%-SrTUZJVoWbo!=@J&UWC##liCTs~3Rp8u{RSa?e}dC$x=5wW5TJ0iB12kp$D@ zdYA$#?z^EB7L>3Zbe8KjT&YfLLnHy8Zq=9@bPNH1To4?Uqp8p9^s-s@?@>_139Uxso3^6scOJwmX-fJC;6I?-Z4Wb@6v{YjP7lMQrGdAcU`y0nmujEOJdf z+MuKE-76u>9xmg%0cs?E<9~?o2**JN`dExG6#3!hR&RH;I2)~Iy16p<@{Zz+em_JK zV_pPCo@@(zr9fXgHu4y$VoYDAGwg|mKAioIaj0~w#HPPZ&WleDSiL)*M<^dds6zzl zV(E{;nqWOv>i;cqaRd5qMxt1lgALpBB{1F;-^MIP+6AZyBT8&pxL~c;F7!e z(f&D!+-;MGVh#KNAhFBhFJ z68IPw?qMivDD9th2(EoRpU{t=UfK))&6hS^k>SxedyETCr3DDD7Tzod-i3*vB{-E~`)CXSp8;C%*5Byx;>7lvhXY~MM-cE6 z?0H}B4nMo?4#f%j7!sjXR>i@FVWRP-1_=vLI!2Si+DYczJ2*8q2sNR_V8L;dH9k3j zrfw30T_9d2u;S76m595gYQKel^ln|D53KVVDv}G|vQME4Z0|x9=}>N`J+HYPWNMN| zGQ;S{1LTP#zhpo(>)}ZYi$lZ;yMo0t-?9Ox^p3<#8O=tIK9|zPc$@@sMK9^~Pb>0@ zF)F!AF(eI^J(|s!M}+cicL0oYyu4`g7uE}G&RpE-4lfU{yx@5r3f`p@pUZ9-7NOzB zkp=L`93>)5xUUh|q`}^Rwh5Oo48nNI4RPAcGZDWyC=tr8Rfgnb8Z|oR5ne5Lb9mB3 zRFI}l@wp~JZtvz5En-Vp)Rkwbs(HP`?P`+T*CXXE&;rdzVnC#DPT+nzYc_T z#>-Gqt(YlLQ0|zz2r2J<|6{nU&prz>6(H-64Oo7}z)yS(>u4->^EAfl zh5exc_Csb=h8v=#e<=yoRcI1i9V_!~sSP=X z+BXsb?+ID`+`;HOki-FyedoIPYgeLo3!G0D1l-dddUev86h@3Y(^Sv^?U`bWIqgas zQ=5KZf(-Ezu;hR%cS;b|Z{2oIX7*z2f^q>~*t!D=tn{AOu84S4K%M>j)4@r1x2Ha5&rZxdHVw_ePe=m%$S5th zx$I}VQxtu@8EIH)Z|Qgt=4-~8QC?Kx*%T`pp@Bi?;-qEYreK*L^Uj||-C4dK1zEui zB>ftct4@U??~6`!n3huoxa5u8E?tf$#(R}UlAbW15d-gaO|{MuKMHffM+^uS z#n}W>e0#=xd%oLIeW04H63jLL#O|l^jx79goLm_WtO@FhxwrT4+MHoKj$zE$OTDab z>8bA?5}tJ_#ns{#4_+0198YJFnujETV)Bbr`_8BixRf1#+~sD4P1rnDie#&)m>74p z7}*csMS_xhCeUwSxb3as8$j!#^utHsElsiCp@1Z7rT9bKa7hToXgrjG#y&+qNY`Dm zWDEa=8cRV9fRuzBHjf=Z6A#8qsY-3SCxy5fJw;m1RVx`ngW`)e4wJQn4F-Rkc_vb`0!7W%!jZh;QJ5iN3+ffP zmYcYUpxWHkHc#4993i0_*Rr+XU$ac4%(1M^s?)#|*hiX$qFRjVPY@@-0Oh^iD*Wo3 zBVNT6Gz5u-1Q`_#Knq1#CgqJYE1VPi@15OoU7X2qAlqmt|_@l`EUjeZW~NR@Sgs5 zOgvG(<~^Lx5+2As4cXRVc8AW`bCvFK}^4s?mGM03Zq8pJ-}w>g?MVsDY798On~ z^FAJW5x8QW+s@5yD|W;w&{-;GcvkT?_v?^su+kuNslfAv0q(MlO@&|!y`*?qJ>{Et1m@)41);iOrV0co{74B@YWaxhYoYXd}o(mHffKgxe~~H zaZRHw(j}Nt>k<36_6%ab41Q75&OH&zv}@RgVdos#?AZ;*?3@q8jY^D4?2cXo?E{ha6t(4cUg1g9rg21ixNB}aJF*?t zX6*iwYF-4Sst>pmLeTqWLuQQ!9;hb6nJEh4pdu0m^$ByvhB6?TLV7?_vOA0=b$~e< zb&WFRN}!*Q6oktFjZ(mhMX$ht@M5@`(%}RdOUzq=P-7g$1oE{a4i==%-#N#w9QYo$ zB?7?cqJx5s{7Xn8bz<;&m?65C1y+jekp(P^1CWDoE&}k@9Pu}Lotm+IC=rGs6TX{W9`)YR zJac#@yWb#`ak^c#) zj}jWOn>H0T>K0=}_x$UZabM)*t^khT8d8BuoG&NQaL+lIWTdxm5VTlx)HpC9gm=^> zdJQ=hp@R(YJUwZEq^^Mrhqcb?rZ?~abVP`k2Bu-JAmjKA5;TxMo@cxbkcM#Vdk7JL zD{uoN35sBX(>+0VTU}2)T~?Q;#`isYaEPNRY>gGVt-6ae%o9%;c458*7QS`h!H$eT zzp%P>nAye$ft#!zowQZ<_#iMMXd!4;Ue)5J$eZU1-i%BhJUX+~ln{Xic=qD)&2bh? zUod@s3PvupPlyMb;YKK%|bCgzqrJu3wA{;!G9F`ikZt>wek6`EmLD|cI!gzSe zL_@vZJ<7jdUvGZxrbG1$4sA3%^zR!8EL8qezgYM^IV^N1_Tp0jdV_v@7b}1g2F^yf zVg_DvaPfO!knl=YAkd+_P++(ono#Y9n6O~IMO*wj5Z}^aLF2fA4p!`;hPuiC%LLyOO26?Kp z1O^y|i-HW%j|s<@O8CsS0r>{(GRO5Awh}-U#mzxf#OU-*4E)_}*R>7SYmQYCU>`&j zQ*R9u5NaI$+`DNsz3?=y82yBw`nn9=@8n(I^%&0-Y1Aao{Z56N&NNo1XTfi-TKph@ z5ghp-P;qb2^HravSGWtG7=ncW`vHiv57jN*)qOL=a0eFx%{J6!9{C!WeCElz4s#^$ z-6f5+1^q|-DM~^U8jTZT2Kl}XXhuNCR~~8nXDxBicjBFpIpV8&O?nd4Mc6zBdJdRT z%_R3rJEMAfOy916FueD@;T3+EAE|JWw_i8To?LqjMVeohJfWubr$$lX{a-8o3!86#}Ad*A( z>N2BWgBEMCkK$d%{Cp9EWQ=bx+yjTmG;-t`9S8$tSai^CU^)8N@YDU4lKK%i}5e!Q4jY64F(?ZkhVBTMsc8hia)=f_2k#PRQ$=x_%fc@O% z`>XiA>SF_y0Kp`Uv+g-!RkpE?GY z0*L*$)B|BX1N={WimE)R*QbdxfJTRcR)0w_?O>`U6)xHqZU9W50ou_R3#^Ws#WYID z{?YAz_5g7fT<8mJHK8wDmlUZMw`@Oe01YO2*Dhi^qiC0W@8(PhL$<8X!*gXMM%a8u zX|_QZkVOABBerN@1Tt`8{*1#QlD}dG(DWnG$(3Q>i0N-3(0f0qoANTQCph%CnOM@(|)@L5tyLA&o;ww!O`eA_7j)W5QJ&kVc&a%>AlI{wb!7< zy@lOQoF5jUilYw=BB^CFRf7v@-P>W(Y^XSPO+!iZV()S%kZwB=;jGuY2zVyzdrF~1 z4p0tIi2x({DNHrwYk!M=EC#+urfLt$_cWh~iTZ*;;9h|bEwj8;36!oN9dkjUi-I#k zM&mCAY<{cZo9r`!#xRmvXRmeGCX1TxXQ1JUI$R<^r!O*p18m!4>G=-Bh)Dxzh#}as z1l0l(NTHj=!u7qSrOg}iK~VB~9k$yX@Md^^X|HjWb3tc0u4!@wcp!kOw&1O_kAq}# z;NrOJY?#KxJTba+kTccdhrH2I{x`c-Y`cP)`8$$)HR74x$sC|*)rvv0<_za zn(6l5w`nBDxws2IFY9N5u_A&!MYFZ127SU;z_vrfPYr`!yROR|njP+CffwvLz`;Gj z24I7i0{?NM$GRERJR`RQwR1V)iSDTfN-*t)_r?->t}_UR6RJrh0Mh$nBzTLpB3|M@ z?sw1s`Jsl6H=lH2c~H5AdP6Eqj1s}zRiO_oh6dXdhZCz09_srf_{KU+4M~>*D?sPd zmZdTTuwLgl!n#}r=#$`f}tM%jxT0w^)j5YhptjU-Q? zF|--<=$|#utmg&8JJ8aJ6;5NV!n={;e>X`8G}nNu6$8MoRW3iU#Njb31T4>jEmF8K z?7W%s%9fEd+EbnuG-*t4;Ryp&cJMS{w+L<&7M|%~=}J#dj4^}+tS>s1lUJ+_)?|Qm z$tL3_Mjmeg3q`H4_3EXi+74D&;Bx-=?EQl9GZVFb0`uvEnb}ZoFrwb4KZD47T1Iq+Z z>LIly)g#Y%p5j&V!K9kF7%Ct^w7}lU^1PNnKRs!2UP0(WD&@vr87v0f56ex9)jIR1OaUaku7e<7q9pF&n=%Ay^=gw-XAl_)yFQmBfC?qm$?szfHDJ80-OYZZ=d$MP?y~@To?t(> zfT8(@K6xDZZrlJ7tAB|vc!Coi(t-PVgtF^q$Nn^E*$hCN>A^*@jW|!d1~Nd$PNr=X zIB(nSlVm`}I+~nFpZrAD#Ud;gUrxgegWfSV*C^O}$(Lit#!N_oOR-%^i@Bh?UCHw_ z!%5h1+vDkN3clAc!>RHxA71J{7 z`$c$aGuem&Ecok+z^pYI;g>IOrNC4T?P@Ewzmukb1BVt~^bIW{4Ydv>X==#St*+#K zc_%S@7zc?d@I6_p_~1{M>(r7f)xCNI$7x+wwIHUCp_^3tg0u19tJzG_eCu<0h_}o| z;w+TvlA-9)^!*p`w-ouBK+fEq)FjpY(}3_#BLdxLKtQbav*zi) zLj;n+kJ7=DQN^6&tJx|VHJQS=H*$O|^I_I9mc{WFSf)Ew5j6IT zOKRb_j)!0d;y-%+ZwQt4%Ms48db++|oI84E``Lr>^f)`YS5{sX7D*&QHIhtEfr!Hr z4}OOd z0kzkwurci44Ezo?6Aw-S0yh%|gVptx$Hh=Jkr21V)caqgnQ956Ow%Sw zuHBUEJFkApq`eLpg2bcQ_c&JT6>4bW{8!MX$J6c3I%kJ|E^(!^Jx#UUR$e@j5cJX0 zJ}%?)WE=&lW3PnHai&Wav(=pX_3k){ZTmyVgp|(x>2mqW(>vG2P#)Bc^CJzX3J)CBxOv0+OEmw6m zbRh(pfcObvKVfmhO>LqK73EH?L|);%>45jHRcas_pG4{7{gWumIF;0;J*waJ=#(hr zrcF}5YfxjQ(5T6N`}y+CWw-zi-FUt%$>E^=0Y>CT*BOo&t~rg#qsVHbR>Y?DO_rsG z4L0n{NKAhgXPn7Q4bngY62ro5R8M-B>1<3yR(wG-83(vO_$Ln$5SxqXsVH zxon>yFp=J3E-Tg z(0Jc|e=X(y$H#tD3WMp7O2_;54dIMG6avh}nvL$+ef;b7j=sTTm7b{uO<_YJGv~*ycJjiKpu?#zklb zz3hbWA6qZ)4l1ob_J|Ad8eJafs1#}oWPR46*kJh}`lS*k?v`Y?J|7}wEX|+b&F9m6yMjhbwZ=F?*5t;xlAWHZtmpJn& zUJ&Iv6ze*zKTif@Cs#$e^5H#b}eV{rC?0HXc^o7l^a1(KOM4D`^S(N1I@7)B=D|5bX^7?*RX zpdgtvZV4m;Zc^(No!PyACF4=li9^-zP&I=mi8a@7D{AfVzOjZskuqu z4>bKvn$9OBUf0&O-fNu0+4NPrV`-x~vUN1@;WcxG=`#^cB_dJ+8fYaOIk~$u^70JA zTAqJwe_6Ur_w+mIlE5vuu;jofXjp3i*j!q4^kVQ;YQgUy{!(flsO{BvY)cL&vP2jb zyf19sPyV;RaTu_YkkNREq0KRPzd|#DDzs~)v)oTn-M02p{v2jERq=gjLwkQ%gO>Sb zA!xko*Kn!!y4)NOj+@k4+bJh`H&i-sZ;e1_2$S5uWicor1j;Jx(7>3ld~klgHm!Mm zxCuWh?6=x>=30NlGR{12lX^tNxy+2jVwHyZ^@R=D-9d%erK^sPvp>v7dY!)GS+flG zmiYPMMKnaDhhuZ)V)qZ*2K>TPuE)jnGhzb8I~g+XbJKfnWYdqAdu5Z)xG52Dg?JeK zAvr#1Ine@1V}k!tcLn^xz%-@k;r$p(>vy|PKbeWL{4*fpEB@jaLZqmB9WIv<%fdor zJL;~mV)d(SOJ`hp^3^|%t>5(;q>E`ZS|WFcvUK(*5kQEXmrL0k8k@kCTDN>o|0Z(R z<1Xw*nX`N)Z}Vl9NlvM$IkRj6yYdKhwL`BXMia7>nOm4>JPuMvvq{+`QnU%QV`HIp z&nIVm3Y{_)KCSzU6`F{zw8{<8Bg5SgFa^S4iq{ij?Yot-Y@-doSLTKzyflv(Rs8P% zXJQFpi1)*i!WN65!$7g;4IKrx+O~=;3#DShkpG(hFFzTfJda?7MU9k5!@)(xy0p=Q z7Po8uv--n|fzhDCiX|oBVYal}$Cn#LH2y2^@vGARg&V#`thh+BTJHqk6&trF=p6aa zr;9(CW)|4pAsAoWM>*&Z+Vi37+E34wYu~JpDK%g$w^HR?pvkPyGMsVzv6M)nHlu3A zNlPld^!+k38;3M(!{jc?Fve?xu5NQ4M@f?>Xz85*}u`bBBii;K9wIOAzi!;P`2@SrS?tj?`?QQ;3Br(@3Vwj%WcAC zZrcndc7umSZJ+jC`N1EVmoc0;oHA*Pyz`q2T<3|O8;&0$TLB?R89Bmu)*jdUG=w7I z7)a&Zc(j#Dv|a@bdP{9--!+@W$s^@tJAs92nkip3y&1Dfra7@qDB`m;>Wr0&4jm=0 z;>nC3Ds@IIZC()u6GmWn)d=2^oWnPFV&176}9 zK0`ogb+Ua_!!c;dosZ{}L?SR@q@tiG(u~Hxet#t0h;%PEU2)Xdar2Lpv;?WQ1d>PI~bR_{CO1=XwSIP#Ar7_W{N4SkpE|x-P zJPsF(h3;g0SFoFCK9IC==A>Aq$`ekC)4dY5d`aeek??dFPfG2ZLCgG8QX4(>2Wa^XKe?Wj}#$si-e6*zB-om z?~TaDr14=@=b^FJi)TeuoSm-MnX`k$sH&psw~v+l3}&y@@|0KRN0`Z$)7567PYn{Y z>b&y1*5*u8XX54Kgcg19gY0wjC)Rj%Rh+GGRzm#pKoA>rT*#OEcQbH9EJ`H{k1y8t z#p?`s@0^`4?$*57OvLD+@1ntaoe=7FZ=+c`d%Ds>m&&TOo;UMYb74GPja+!W7c-3d zhgkbo>w=JX`-k?52)vp#G0gpGBCS->&|J*L*O5v$B^N5i-=zcd+w;TEobP8ywH|B4 zR2m zY4zYrtF|35X=!jxW1_(vZ#8~WMr3S}`xHPqnvSc^RN(mY#5|2)4)P&IWYB8;iT5w7 z!sm2QZ?O7XacT84yVuxmn*@kvbS=?Alc~+3YD!WF5Q)x$Mo{ZL+ zz2nBa*Y#r4Rjs8+&PUT9dcAl55r*ZbGHWPj?*PZg*jxdrA{*;PZ0&b;PVE{)GG`~Y zYzJI#{vz2lVuXFD0YBrZ{&Maz^@p}+OYIU$4Mwwhn&vR{_n9p5_P@GH3}Ty5?`fPe zcfWiwDpb!}{#tPwMS=ZQu5e{|(s-f-GjwaT+4Gw`dqX{do-1u)Wcf(w^{_POS$me^ ze&f{kdc9?0OK-kQ$s2)@gC{?gN|HBv;&jII%tl*IiM!evIKCiKbr(IB+WPxdPQ8VP zW$NPPB1yg7KN5>qIU1jX*tYE^OSx24#)106)2YJa;v+^ni&^6{*0_=fm`tmutM!8W zd{R~GF-f=FW|H7}wQTl$&=1MqHg1Uvz=cBQc`ng*I5H_c41*G&&rnHB>VJcIkm6$@ zVzS`7y7h7PuJWwUt&Zp1wNqEGP;4%9SXWj!ID1+TQOtKoJo*@C8)3N;9aWd{q8 z(x@|0dU9kB@Y>LOe1%=Evv9VXxzC)A1KnVAkm@x%7N{0yStjuc|E$O&aklZ$l0p_= zxXi6899kYXnb=%3S-Z`RCnHOlX!m$S(_kpdKHd1E@$$`SAD(hOi={(MGo~KT# zCx_!c1~do6=ZP@+bubG7lbTSaTum*ytBg_$=f^Eut&vAp-@~78oYWa2^^O&hX^g{r z)_<`uveY_?=gU=3n3;-XzIq44H61OiDC=C8T7%#5COutB(ODN_BUas8t85(S1tIKp zbqCa%ZQw^CXAERCYpw9mloH#YJFBPRX0tf9)JD3irIKMgT~S~7BhbgEA7qh) zAmPOa-5iwH7*_iWud9|qmO+&?5rWIg$(^{nE_ z2L~}y*PIx#u;UB|GA$QHofJyEwM-ChJRI;$sWE29DZL-gjJe=f1>ShOEA1lz+d|Ns z=~5VFIEUH@bm!6hf!IvL6MqnlmkF|q1ZymN9u$veUQ9M7#(Ub)P46zyJXc#DZJQ7K z72?$-U>a!CaDXxU&~U=*jPoWVgCB8!K7a`(;c!%%bwSEDH-TenW1?A#Dkd{xF2f`C zZ^~RP60KF>3C7GO!oM2i;{!5&KNSo0RwB()Afx8-_+Iv~ztCf&-@!Tiq|A|A_}XFv4VT0CWGk>7v+{4s_# zssFCQL{mCpJdQE&Y_m4PWYXHshfd%gbnfAD5y$B~IU7H-bC;3#EVuiP7C!lecmBq) z)4SF>{de+VQx#wO#g-&^*n00mbw%^Wq>2$uO^x9ex~IKUKV$Uad_F~bU07F+lcZXy z`S5N3WM}*AXtr45WI^qi6(?noyF%q#nd?=2cf$woYvbmdH<|y~p1Kaq=UybY_h(x} zrh|sI2)@rY)!DY|)AimzY#3SU=WQ>#djYxayP~fp& zmQu>1ot}f>ku2KsJzEyks%&rW-^1wczn8A@OXrTkB&g&CkUDFb~Bt;-9oFByUIN(1WpV}mu8&K= zBC`GbgGgG3SS^IApc0iByFg&87k_J%9QKjK16+UpAh5SV`LW_ArjmqvYjx})T#7nW zK`IE1CiAuGn$dKEax{gWL4;zr#c3F=eICGg-~Mp6TweI=(H{)$$%aMn?(68wulxok z%Xzr(+9ec`V2bLb9lmNl({S4FJ?(rc1*idUp2#+P-;}*wee=ULHi{~iOvh3MqG+PQ z*7BX$+}-cUkewLBGMz;A%eRYoUkY5xpeuAbRr&JmJB_adz4UVUy)~MNt49a{lOe;t zL6WC#2iA>4C07XrFy;~M5J>;V5JvW5SLzR@mYWW=f3~#))Di~QKZq=c*wM|a<*q*u2lb^=5G5l{U6Qaec2K) z-eX9J3Yypt5eV!NAEIYE#Vzme`R70TxilP|)f+QbP-R}a>H{BLxb|pcJ%ksfN62*r zWG%JVUY!wr9P-xeF$SugbdU?e32tnW%z!dtkNoA15*dJ+jwGN>z^c1lWX{ zR`SP{B>)23y_I^|Q~KCSjiB0>4n`?>*3-j2e-$%?2Bsi^IlB4L_j*u*dOF!J3E{Oh}sowTaTA70Ww~0?M zt3eKFJXBn_ z4Ws%kn#~ObY6oQO4H57^SHFDWCtFXg# znuhprAaY5mw{v<}{#MGaw_d#lDKS>SJ);0YdS$dvLtUl~<9=3Ev4{CORxC2SMCDbf zqFBfC+-SAKO6^yptT-p8(c#GA}(nmt~o=xL*^ zYetSz1B>@|b<)x1`<3_yp*yXCes7tBP;U*`4{^r35yAr*gl% zcFj32-}zC6(1nYAv&#n|_TsUu%@b=Gg-_j&?w|A2KV-%YYNG!j0G56%wa(>QHfPx2 z9<0*j#)@^@GQVgUN&BRCAbAx+8GkybxydXSe!_458Y}*!^txWzp3Z>&j+f(BfkjJI z()jdf0`x6V(PA)tBg3mNU`4y@Y<^ezw`tW7)38gbi^?FQSNgT~)Sd8G=hlICey&*? z4=>!GAGEcf+dX6H<(b%*?$MBGk`Ls9$|3VReTN1M0uJU3u>EPW;& zTxUSt4&#rKi)TA4VseA~-9+}TG97MKnb&C~DuHgHUy2sUBRuj6gIh;_%rClD44eq% z&ymGt_SU5%-grReasV!z62?veDcjTeCs2d6vjRB8W{t@g+(BNsPl?ZP}lTVZP-{v&#_0 zFUHn+Po=8V@0Gf@vvOB#rfY@1^KCM6eWT3p!P*N9Y;qd+E>;M`d@4u*uSdmA|6V-X z9la{s2t?!oAx{jeanh#$ykbT=Gx3dyVS}q5qx1ox!GoLx4U?iqw#u03PhE;Noh>M& zbPGa4TvU*e3cdVQI3HJR;lUKla%oiQXVH>ZKT5wDI8k|Xu=c64sn%DQRzNTEy8z1| zM?W;?NLyRGwQycFa?mQpuKr!}@)KasdLzV5QHsyX+L$bZEFRTAP;N^1FczmR{qk@2 ziB*a^+>lA$@AJn`RYN=jcJJR2pz|qXOAW=7{zoXgEWE`FDP0|3$Y4_wXhy7hWi0=$;-zQa?y7vcF7Mo~T-t^+K$b^S>V45+GS_>N3eh zZ($bFduB`<=@;RSw{Y@M6Mcx4sz_AF?IN@f_oyTE0+uMI|d<5w@sksF5=h2S%4 z9<$>1W=~&eW7HhC`*WLLbGpod>qGTEab&6&MA^+A0lE)3PcF8WBH*B22_|X3S%#Ug znR3(4Eur@_3>VI*9NUWoOkxN47nw=N`cxs$x`FDq1XdTaJOqc>B39Jq_KP{U4Vh3& zPSuV1YsshaHL)l6KSm7vtf!K^vhL9CGfxxEy~>gKDTqj7N+ZX6E6={5p%Z+9^pf~1 zp3NFBpoYIx8~WyjQ@;SwG!s$C9;t)jhZkXwB^AvojtgmRUsuRp&d%)KJvQ^Od{zT| zXU`gjmlk{lIvtP6tv4Rhq$ohbhH{@*iJ8RWf>}=! zqW=h)X9~QyxxdVHxn*+5M(5TgbtdX{X0`866=QZUN6hG{7M5f5vwrpI>yg2do)=7B z{?ZC;HJK!BkTRUW_HzS`#q`s5XT59inqQS|$$`VFAD<|_%^GsJ5wAkTm4th#hbx!k zh>BW_K==UD4X&6~# zeYNTY$Az53yOd;h1Ah7zG``CR0$p8~i{Cvq+%gM>U0NPoS2I%5wJ)}k=T7}zDo@HU z)EarFDpB{2I1^~C6VlG-#K~tWZLER!3>q*hi=dG^${|`UcHsR}iBf|#Wf8!_LyC8r z{#q|Ekur1q$%r(g7gCa*+o(|CR9blBc0hXLdl~MTIugg$MxqDt3hB&SQgVTmV*c@G zoo{|xdc=}q!q2Hb7n{wQWBaR}tMduEVaI_3fe2jVNS(oy1`(kxvE%>F8df@ym3w@e!***5IbkamNH){{MCp`0@9uwS(4tb>x{}+3t8^;XgWH1B+O*lt*-0%!(K&r@x34i7~5}? zP2XpsCgn)Q3d-Nu3SdWY)^t;Bahn?*0X!dE8~)K;CSebxtoB=oYz%RSNHu$vi=FG+ z8mLE|Y^e#`y$j{|UdVCVJcbY{3*SGbyLIb<@ZVYhxs=-|`mqt20>EQ%_buQ0kxT)7 zC`T%ZL>hSdYuw__oikB3C5~KA=3Usqx5%^_c{)EUZhIIyu^Pm!U;dBryp4~|>0uDW z=E6ORtg2<4cRU?0V{Kj(r?Q}1_ zV5>2EWW3~KENUdPBJ}3r^d1h|OqhY`-4|N9|Cqn+Gw!=Y&~5(HXPR%EAuU2I=xB4g z2kY1a`!!v3^s(i6fA~L?dv*sgHUSubl9}Y1^YeiDX#P^bmFLF1Q+nL!ow3A z(i9^PShDUUs$pdl{GgiId?p{;)`QQXkmSf;qoa3mn3)OBWs;vTQfB$W>SdmfpGt0# z$H2IJiF-HzkOpgQiB3H;Zi;ZvWae(tPQ-H~@Vx=yFSoXZ%oTxYk0qS^gkMNffT}&a zVMBp|+sE$uKS}I9Z*&~F5ZOgV&y1-2#EU(f{6|q& z=001-VY*H?qShVi`9gTPOH&Rd=M%}$d#kRUir1T;b^6M81oSr~#S<7lBe)>jH13%O zj4XMbkj5kVOe>4`7{-lR!$$Z_YpczqiBK^Sgs8Kw--cWAKyHk2SBWbkym%@PyUcZc z*TnzF>`KLWeyuI-`7PZL7+~ANY@=mT-x@ZoHoMe$N@J<;GUBz$9rjf>ftM6!8Kw?}pZrJ=b?9H+K&X(GwFhLHj{{8i(w$MCk8SF!S zbyf?T+mX=NBjRUa)p&Z0u0tgdb>)VXbd(NyQ<>TyD4DSNpA~0S`BsIw5j0Vxvfg0R z0m#}F{A?vSNJta{7E62t;mG|_TxZo1pGy2VgLk(xbg%U#rHv0<^@&8vvaROpD`%eM zE$Y~K%JbE{d@eBj_=sB4B926cXHXh%XU?=m+%RMx{yMF(>M_zih+v206$DM2t{oIE zD(Hzt9b4{{3)-B16m=`J3JP>vXmp8OG&F53qXADjwrW$DnCYZGi%3j;^1#blEL9ld zvj1;{vQpz6&LE=l*KOM3c>ap z+cdPb_oL`J6(nYUcwXeL@qipMt+nkQQG9HTIX0l>Th^2uOrozkVHAWm(hT!e^eH=X zDXfmh9KqI+yY|D!NABAh^U*-E5+WkIIZ9#Z-yu4k6lkZL8QkZ2m*ej?&r8CXP?~r| zCh0rp*Rn0HWKN`T{+)d>fq99T3F>jneW(2SS74@({ou}i%7r$=%f19bXJd>}t%X!Zv>N-0mhciovjzTVtlOqBh0ZGj2_Q)d&!Y2xAKDrD?JWJR z_xdR|Q@9FJBNQkoVNBB96zY{PEQ44|m^k;WDD{Que+I8s$4#5$ zx=EQ$<+~{MmpC&|b4x{Qv(F=6%Qh>o6lmMrPHL0B2(ZbYg8eW!tmTX~h9tq3Iv`M(JmC4Zc<}>IqT!rzC%i7hR%{u!rwxJvLp+vcI`D{;_)- zxekMU3GD9G^r%0~AQ&oBRMx#axWOa5a8EAlynE;Eph^kn)R&6&P~pWl13Ak`<{ssJfe5+sa z&Z-J|G#_MH^`(KnaC)YMcJ^&5G%+TDyg@3LG7{GAA78QFfoAu75| z;+s}zfr)k?sJcG|s#xxW@#H0CM=h{!Vt$_a=b zz79!_UiRLod5d0ka{U59mDa*r%W3r^eql}P3{`|>cBAmH%gEMy#z-ZXwU$ZhH^((? z+C!S_tX}8X#8Bbunxt$-jWr6aq&DQ%XO0*(fISb5{`APFHaS}?2nRQ( znV^5)n4HOzKC9x@QXhziHdCbFC1q}&6>1A%A@6Vb;JwfXyt$2B*+ICo`79%+d$ZoL*@dmO)m1$1hXOZVFIWXqU&C$@N=zdEPVE) zULT!6aOc%+>1FRvPPY!~dfpwe`5Yw;U#zY=jwV~2gPS%l7=!ky;38- zcW%?@sDGz+T`PtbUYl0{CBbw6fkN&9V=d#qxRC6++(soIn>%)0r9PW2wCv8Nz8((Y z#fAf{y$3JhS8}DnZJw{ysxm6PyAU&A%4;j#Be2=8;@u#VeUc4pO4^DQ$dZ05AImm= zN6unp86~|}!>57YKmVE%O3&2+cGGzWhd z+=i#*<&b3%AIk3#eY;v6y|H#&_!xE+P!NNP%}(TP3seS;7*|&6;7%yBWa@M7LW)~y zE7O=`uy8(81y$QyBN=NjiW{jTiBJcRrMWRX*gQ_uqjD9wSFS|ZayU$Uk8mYxrhoOL zAtZK&uK z5i`ufCTQ*AUw!t?0w)0JpUF!hzT$U)$WzVRB_wwkc%+vJ!FR|-*1&aM)Ni6{E9 zXZ5)&zm#3VD7omxV@h;zJ1CyybkEbo!30(y&Hj>AEs}mddEDAIeO$;tA%_wlGK_oY z!3BCCyccvKPa&XIo++yA8Vazb$;icTx^RAc^W*m`!Wl}U^<{?k!!lsAbAB3uZRj%K z&lWGsp63$KWN=QC!p~=bFCrIoLEio55nYBhR)jMc~mj<)>1h&7XEk2E8aV5!~>VUct zlc$LJlAKiG(E zxz<$~&G@8gme^r?ogWp;Z+zag%NySFr5dYb>!9t*CWP^~VJ7ZgXET+|#lqh+&bi@L z$b@Y2-kO}Yp%fLa-E(tHrQz+ppx=%G@CpNrl3cozl=^z2fp?Sw(AZQJzPj+Y`LTT%^T&ejH!<5<->9v9^k zP?=5`m5#VNs(~)J=^8ReUD+Ogt%{_)zuo&}6mO6D1#Dg>slmd(o^dA#$QiL-9L>;K zcHbGX8&0KPMEu}rZ?)H0v@G5oihF0U>JY(5rD%x{#_4tuAbcll zZFjHb-%pueeHaVaHDI;YzRkL_gn<+`U+?jHY>p0p9=Gx5KV%8q=?R`;a@2w{5MAkHt{ukThCkipd zQ~N#N9jGk+m+rro`Ah9Xwu4)0{$uC=%Z47PMf@QgA^&BS!T!qpZ#_sYH9gf@<(F^& EAH#GJW&i*H literal 0 HcmV?d00001 diff --git a/src/ccstatusline.ts b/src/ccstatusline.ts index 7e09139..831fe82 100644 --- a/src/ccstatusline.ts +++ b/src/ccstatusline.ts @@ -93,13 +93,18 @@ async function renderMultipleLines(data: StatusJSON) { isPreview: false }; + // Check if powerline mode is enabled and autoAlign is on + const isPowerlineMode = settings.powerline.enabled; + const autoAlign = settings.powerline.autoAlign; + const allLinesWidgets = (isPowerlineMode && autoAlign) ? lines : undefined; + // Render each line let globalSeparatorIndex = 0; for (let i = 0; i < lines.length; i++) { const lineItems = lines[i]; if (lineItems && lineItems.length > 0) { const lineContext = { ...context, lineIndex: i, globalSeparatorIndex }; - const line = renderStatusLine(lineItems, settings, lineContext); + const line = renderStatusLine(lineItems, settings, lineContext, allLinesWidgets); // Only output the line if it has content (not just ANSI codes) // Strip ANSI codes to check if there's actual text diff --git a/src/tui/components/PowerlineSetup.tsx b/src/tui/components/PowerlineSetup.tsx index 8571573..24e56c3 100644 --- a/src/tui/components/PowerlineSetup.tsx +++ b/src/tui/components/PowerlineSetup.tsx @@ -183,6 +183,10 @@ export const PowerlineSetup: React.FC = ({ } else if (input === 'i' || input === 'I') { // Show font installation consent prompt setConfirmingFontInstall(true); + } else if ((input === 'a' || input === 'A') && powerlineConfig.enabled) { + // Toggle autoAlign when powerline is enabled + const newConfig = { ...powerlineConfig, autoAlign: !powerlineConfig.autoAlign }; + onUpdate({ ...settings, powerline: newConfig }); } } }); @@ -367,7 +371,7 @@ export const PowerlineSetup: React.FC = ({ <> - {' Font Status: '} + {' Font Status: '} {powerlineFontStatus.installed ? ( <> ✓ Installed @@ -383,7 +387,7 @@ export const PowerlineSetup: React.FC = ({ - Powerline Mode: + Powerline Mode: {powerlineConfig.enabled ? '✓ Enabled ' : '✗ Disabled '} @@ -391,11 +395,21 @@ export const PowerlineSetup: React.FC = ({ {powerlineConfig.enabled && ( - - - When enabled, global overrides are disabled and powerline separators are used - - + <> + + Align Widgets: + + {powerlineConfig.autoAlign ? '✓ Enabled ' : '✗ Disabled '} + + - Press (a) to toggle + + + + + When enabled, global overrides are disabled and powerline separators are used + + + )} diff --git a/src/tui/components/StatusLinePreview.tsx b/src/tui/components/StatusLinePreview.tsx index d0b6366..bef731e 100644 --- a/src/tui/components/StatusLinePreview.tsx +++ b/src/tui/components/StatusLinePreview.tsx @@ -27,7 +27,8 @@ const renderSingleLine = ( widthDetectionAvailable: boolean, settings: Settings, lineIndex: number, - globalSeparatorIndex: number + globalSeparatorIndex: number, + allLinesWidgets?: WidgetItem[][] ): RenderResult => { // Create render context for preview const context: RenderContext = { @@ -37,7 +38,7 @@ const renderSingleLine = ( globalSeparatorIndex }; - return renderStatusLineWithInfo(widgets, settings, context); + return renderStatusLineWithInfo(widgets, settings, context, allLinesWidgets); }; export const StatusLinePreview: React.FC = ({ lines, terminalWidth, settings, onTruncationChange }) => { @@ -49,6 +50,11 @@ export const StatusLinePreview: React.FC = ({ lines, ter if (!settings) return { renderedLines: [], anyTruncated: false }; + // Check if powerline mode is enabled and autoAlign is on + const isPowerlineMode = settings.powerline.enabled; + const autoAlign = settings.powerline.autoAlign; + const allLinesWidgets = (isPowerlineMode && autoAlign) ? lines : undefined; + let globalSeparatorIndex = 0; const result: string[] = []; let truncated = false; @@ -56,7 +62,7 @@ export const StatusLinePreview: React.FC = ({ lines, ter for (let i = 0; i < lines.length; i++) { const lineItems = lines[i]; if (lineItems && lineItems.length > 0) { - const renderResult = renderSingleLine(lineItems, terminalWidth, widthDetectionAvailable, settings, i, globalSeparatorIndex); + const renderResult = renderSingleLine(lineItems, terminalWidth, widthDetectionAvailable, settings, i, globalSeparatorIndex, allLinesWidgets); result.push(renderResult.line); if (renderResult.wasTruncated) { truncated = true; diff --git a/src/types/PowerlineConfig.ts b/src/types/PowerlineConfig.ts index 34883dd..d089b01 100644 --- a/src/types/PowerlineConfig.ts +++ b/src/types/PowerlineConfig.ts @@ -7,7 +7,8 @@ export const PowerlineConfigSchema = z.object({ separatorInvertBackground: z.array(z.boolean()).default([false]), startCaps: z.array(z.string()).default([]), endCaps: z.array(z.string()).default([]), - theme: z.string().optional() + theme: z.string().optional(), + autoAlign: z.boolean().default(false) }); // Inferred type from schema diff --git a/src/types/Settings.ts b/src/types/Settings.ts index 05e2d45..889143e 100644 --- a/src/types/Settings.ts +++ b/src/types/Settings.ts @@ -55,7 +55,8 @@ export const SettingsSchema = z.object({ separatorInvertBackground: [false], startCaps: [], endCaps: [], - theme: undefined + theme: undefined, + autoAlign: false }), updatemessage: z.object({ message: z.string().nullable().optional(), diff --git a/src/utils/renderer.ts b/src/utils/renderer.ts index 92dc48b..7336068 100644 --- a/src/utils/renderer.ts +++ b/src/utils/renderer.ts @@ -45,7 +45,8 @@ function renderPowerlineStatusLine( settings: Settings, context: RenderContext, lineIndex = 0, // Which line we're rendering (for theme color cycling) - globalSeparatorOffset = 0 // Starting separator index for this line + globalSeparatorOffset = 0, // Starting separator index for this line + allLinesWidgets?: WidgetItem[][] // All lines widgets for alignment calculation ): string { const powerlineConfig = settings.powerline as Record | undefined; const config = powerlineConfig ?? {}; @@ -209,6 +210,72 @@ function renderPowerlineStatusLine( if (widgetElements.length === 0) return ''; + // Apply auto-alignment if enabled + const autoAlign = config.autoAlign as boolean | undefined; + if (autoAlign && allLinesWidgets) { + // Calculate max width for each widget position across all lines + const maxWidths: number[] = []; + + // First, collect all widget contents for each line + const allLinesElements: { content: string; bgColor?: string; fgColor?: string; widget: WidgetItem }[][] = []; + + for (const lineWidgets of allLinesWidgets) { + const filteredLineWidgets = lineWidgets.filter(w => w.type !== 'separator' && w.type !== 'flex-separator'); + const lineElements: { content: string; bgColor?: string; fgColor?: string; widget: WidgetItem }[] = []; + + for (const widget of filteredLineWidgets) { + let widgetText = ''; + + try { + const widgetImpl = getWidget(widget.type); + widgetText = widgetImpl.render(widget, context, settings) ?? ''; + } catch { + continue; + } + + if (widgetText) { + const padding = settings.defaultPadding ?? ''; + const paddedText = `${padding}${widgetText}${padding}`; + lineElements.push({ + content: paddedText, + bgColor: widget.backgroundColor, + fgColor: widget.color, + widget: widget + }); + } + } + allLinesElements.push(lineElements); + } + + // Calculate max width for each position + for (let pos = 0; pos < Math.max(...allLinesElements.map(line => line.length)); pos++) { + let maxWidth = 0; + for (const lineElements of allLinesElements) { + const element = lineElements[pos]; + if (element) { + // Get the plain text length (without ANSI codes) + const plainLength = element.content.replace(ANSI_REGEX, '').length; + maxWidth = Math.max(maxWidth, plainLength); + } + } + maxWidths.push(maxWidth); + } + + // Apply padding to current line's widgets + for (let i = 0; i < widgetElements.length; i++) { + const element = widgetElements[i]; + const maxWidth = maxWidths[i]; + if (element && maxWidth !== undefined) { + const currentLength = element.content.replace(ANSI_REGEX, '').length; + const paddingNeeded = maxWidth - currentLength; + if (paddingNeeded > 0) { + // Add spaces to the right of the content + element.content += ' '.repeat(paddingNeeded); + } + } + } + } + // Build the final powerline string let result = ''; @@ -444,9 +511,10 @@ export interface RenderResult { export function renderStatusLineWithInfo( widgets: WidgetItem[], settings: Settings, - context: RenderContext + context: RenderContext, + allLinesWidgets?: WidgetItem[][] ): RenderResult { - const line = renderStatusLine(widgets, settings, context); + const line = renderStatusLine(widgets, settings, context, allLinesWidgets); // Check if line contains the truncation ellipsis const wasTruncated = line.includes('...'); return { line, wasTruncated }; @@ -455,7 +523,8 @@ export function renderStatusLineWithInfo( export function renderStatusLine( widgets: WidgetItem[], settings: Settings, - context: RenderContext + context: RenderContext, + allLinesWidgets?: WidgetItem[][] ): string { // Force 24-bit color for non-preview statusline rendering // Chalk level is now set globally in ccstatusline.ts and tui.tsx @@ -469,9 +538,9 @@ export function renderStatusLine( const isPowerlineMode = Boolean(powerlineSettings?.enabled); // If powerline mode is enabled, use powerline renderer - if (isPowerlineMode) { - return renderPowerlineStatusLine(widgets, settings, context, context.lineIndex ?? 0, context.globalSeparatorIndex ?? 0); - } + if (isPowerlineMode) + return renderPowerlineStatusLine(widgets, settings, context, context.lineIndex ?? 0, context.globalSeparatorIndex ?? 0, allLinesWidgets); + // Helper to apply colors with optional background and bold override const applyColorsWithOverride = (text: string, foregroundColor?: string, backgroundColor?: string, bold?: boolean): string => { // Override foreground color takes precedence over EVERYTHING, including passed foreground color