diffstalker 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/App.js +1 -1
- package/dist/components/BottomPane.js +1 -1
- package/dist/components/ExplorerContentView.js +3 -0
- package/dist/components/ExplorerView.js +1 -0
- package/dist/components/Footer.js +1 -1
- package/dist/components/HotkeysModal.js +1 -1
- package/dist/components/ScrollableList.js +1 -1
- package/dist/components/TopPane.js +1 -1
- package/dist/components/UnifiedDiffView.js +1 -0
- package/dist/hooks/useCompareState.js +1 -1
- package/dist/hooks/useExplorerState.js +9 -0
- package/dist/hooks/useHistoryState.js +1 -1
- package/dist/hooks/useKeymap.js +1 -1
- package/dist/hooks/useLayout.js +1 -1
- package/dist/utils/diffRowCalculations.js +1 -0
- package/dist/utils/displayRows.js +2 -0
- package/dist/utils/lineBreaking.js +5 -0
- package/dist/utils/mouseCoordinates.js +1 -1
- package/dist/utils/rowCalculations.js +4 -3
- package/package.json +1 -1
- package/dist/components/CompareView.js +0 -1
- package/dist/components/DiffView.js +0 -1
- package/dist/components/HistoryDiffView.js +0 -1
package/dist/App.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as l,jsxs as X}from"react/jsx-runtime";import{useState as f,useCallback as m,useMemo as Ke,useEffect as k,useRef as Y}from"react";import{Box as M,Text as W,useApp as qt,useInput as Jt}from"ink";import{Header as Vt,getHeaderHeight as Zt}from"./components/Header.js";import{getFileAtIndex as Qe,getTotalFileCount as $t}from"./components/FileList.js";import{getCommitIndexFromRow as eo}from"./components/HistoryView.js";import{Footer as to}from"./components/Footer.js";import{TopPane as oo}from"./components/TopPane.js";import{BottomPane as ro}from"./components/BottomPane.js";import{useWatcher as io}from"./hooks/useWatcher.js";import{useGit as lo}from"./hooks/useGit.js";import{useKeymap as so}from"./hooks/useKeymap.js";import{useMouse as no}from"./hooks/useMouse.js";import{useTerminalSize as ao}from"./hooks/useTerminalSize.js";import{useLayout as co,SPLIT_RATIO_STEP as Xe}from"./hooks/useLayout.js";import{useHistoryState as fo}from"./hooks/useHistoryState.js";import{useCompareState as mo}from"./hooks/useCompareState.js";import{useExplorerState as po}from"./hooks/useExplorerState.js";import{getClickedFileIndex as uo,getClickedTab as ho,getFooterLeftClick as go,isButtonAreaClick as xo,isInPane as fe}from"./utils/mouseCoordinates.js";import{saveConfig as Ye}from"./config.js";import{ThemePicker as So}from"./components/ThemePicker.js";import{HotkeysModal as yo}from"./components/HotkeysModal.js";import{BaseBranchPicker as wo}from"./components/BaseBranchPicker.js";import{buildDiffDisplayRows as Co,getDisplayRowsLineNumWidth as To,getWrappedRowCount as bo}from"./utils/displayRows.js";export function App({config:x,initialPath:qe}){const{exit:Je}=qt(),{rows:O,columns:i}=ao(),{state:q,setEnabled:Ve}=io(x.watcherEnabled,x.targetFile,x.debug),P=qe??q.path??process.cwd(),{status:H,diff:N,selectedFile:Ze,isLoading:me,error:de,selectFile:pe,stage:S,unstage:y,discard:$e,stageAll:et,unstageAll:tt,commit:ot,refresh:rt,getHeadCommitMessage:it,compareDiff:R,compareLoading:lt,compareError:st,refreshCompareDiff:nt,getCandidateBaseBranches:at,setCompareBaseBranch:ct,historySelectedCommit:ue,historyCommitDiff:he,selectHistoryCommit:ft,compareSelectionDiff:mt,selectCompareCommit:dt}=lo(P),u=H?.files??[],n=$t(u),ge=u.filter(e=>e.staged).length,[s,c]=f("files"),[t,xe]=f("diff"),[w,j]=f(0),[L,J]=f(null),[Se,pt]=f(!1),[ye,ut]=f(x.theme),[A,C]=f(null),[V,we]=f(!1),[T,Ce]=f(!1),[_,Z]=f(0),[Te,$]=f(0),be=Zt(P,H?.branch??null,q,i,de,me),ht=be-1,{topPaneHeight:v,bottomPaneHeight:gt,paneBoundaries:Ie,splitRatio:ee,adjustSplitRatio:Pe,fileListScrollOffset:te,diffScrollOffset:xt,historyScrollOffset:G,compareScrollOffset:z,setDiffScrollOffset:h,setHistoryScrollOffset:oe,setCompareScrollOffset:St,scrollDiff:D,scrollFileList:Re,scrollHistory:ve,scrollCompare:De}=co(O,i,u,w,N,t,void 0,x.splitRatio,ht),E=Ke(()=>{const e=Co(N);if(!T)return e.length;const d=To(e),p=i-d-5;return bo(e,p,!0)},[N,T,i]),{commits:K,historySelectedIndex:yt,setHistorySelectedIndex:U,historyDiffTotalRows:Ee,navigateHistoryUp:Be,navigateHistoryDown:Fe,historyTotalRows:ke}=fo({repoPath:P,isActive:t==="history",selectHistoryCommit:ft,historyCommitDiff:he,historySelectedCommit:ue,topPaneHeight:v,historyScrollOffset:G,setHistoryScrollOffset:oe,setDiffScrollOffset:h,status:H,wrapMode:T,terminalWidth:i}),{includeUncommitted:wt,compareListSelection:g,baseBranchCandidates:Ct,showBaseBranchPicker:re,compareTotalItems:ie,compareDiffTotalRows:B,setCompareSelectedIndex:Me,toggleIncludeUncommitted:Tt,openBaseBranchPicker:bt,closeBaseBranchPicker:It,selectBaseBranch:Pt,navigateCompareUp:Oe,navigateCompareDown:He,markSelectionInitialized:Le,getItemIndexFromRow:Ae}=mo({repoPath:P,isActive:t==="compare",compareDiff:R,refreshCompareDiff:nt,getCandidateBaseBranches:at,setCompareBaseBranch:ct,selectCompareCommit:dt,topPaneHeight:v,compareScrollOffset:z,setCompareScrollOffset:St,setDiffScrollOffset:h,status:H,wrapMode:T,terminalWidth:i}),{currentPath:Rt,items:le,selectedIndex:vt,setSelectedIndex:Ue,selectedFile:Dt,navigateUp:We,navigateDown:Ne,enterDirectory:Et,goUp:Bt,isLoading:Ft,error:kt,explorerTotalRows:je}=po({repoPath:P,isActive:t==="explorer",topPaneHeight:v,explorerScrollOffset:_,setExplorerScrollOffset:Z,fileScrollOffset:Te,setFileScrollOffset:$}),_e=Y(Ie);_e.current=Ie;const Mt=Y(x.splitRatio);k(()=>{if(ee!==Mt.current){const e=setTimeout(()=>Ye({splitRatio:ee}),500);return()=>clearTimeout(e)}},[ee]);const a=Ke(()=>Qe(u,w),[u,w]);k(()=>{n>0&&w>=n&&j(Math.max(0,n-1))},[n,w]),k(()=>{pe(a)},[a,pe]),k(()=>{(t==="diff"||t==="commit")&&h(0)},[w,t,h]),k(()=>{h(0)},[T,h]);const b=m(e=>{xe(e),c({diff:"files",commit:"commit",history:"history",compare:"compare",explorer:"explorer"}[e])},[]),Ge=Y(()=>{}),Ot=m(e=>{const{x:d,y:p,type:Q,button:ae}=e,{stagingPaneStart:F,fileListEnd:ce,diffPaneStart:Qt,diffPaneEnd:Xt,footerRow:Yt}=_e.current;if(Q==="click"){if(A!==null){C(null);return}if(p===Yt&&ae==="left"){const r=ho(d,i);if(r){b(r);return}const o=go(d);if(o==="hotkeys"){C("hotkeys");return}else if(o==="mouse-mode"){Ge.current();return}else if(o==="auto-tab"){we(I=>!I);return}else if(o==="wrap"){Ce(I=>!I);return}}if(fe(p,F+1,ce)){if(t==="diff"||t==="commit"){const r=uo(p,te,u,F,ce);if(r>=0&&r<n){j(r),c("files");const o=Qe(u,r);o&&(ae==="right"&&!o.staged&&o.status!=="untracked"?J(o):ae==="left"&&xo(d)&&(o.staged?y(o):S(o)));return}}else if(t==="history"){const r=p-F-1,o=eo(r,K,i,G);if(o>=0&&o<K.length){U(o),c("history"),h(0);return}}else if(t==="compare"&&R){const r=p-F-1+z,o=Ae(r);if(o>=0&&o<ie){Le(),Me(o),c("compare");return}}else if(t==="explorer"){const r=p-F-1+_;if(r>=0&&r<le.length){Ue(r),c("explorer");return}}}fe(p,Qt,Xt)&&c(t)}else if(Q==="scroll-up"||Q==="scroll-down"){const r=Q==="scroll-up"?"up":"down";if(fe(p,F,ce)){if(t==="diff"||t==="commit")Re(r);else if(t==="history")ve(r,ke);else if(t==="compare")De(r,ie);else if(t==="explorer"){const o=r==="up"?-3:3;Z(I=>Math.max(0,Math.min(I+o,Math.max(0,je-v+2))))}}else if(t==="explorer"){const o=r==="up"?-3:3;$(I=>Math.max(0,I+o))}else{let o;t==="compare"&&g?.type!=="commit"?o=B:t==="history"?o=Ee:t==="diff"&&(o=E),D(r,3,o)}}},[i,te,u,n,t,K,R,ie,S,y,D,Re,ve,De,G,z,h,U,Me,Le,Ae,g?.type,B,E,Ee,ke,A,le,_,je,v,Ue,Z,$]),Ht=Se||re,{mouseEnabled:Lt,toggleMouse:ze}=no(Ot,Ht);Ge.current=ze;const se=Y(n);k(()=>{if(!V){se.current=n;return}const e=se.current;e===0&&n>0?b("diff"):e>0&&n===0&&(U(0),oe(0),b("history")),se.current=n},[n,V,b,U,oe]);const At=m(()=>{if(s==="files")j(e=>Math.max(0,e-1));else if(s==="diff"){let e;t==="compare"&&g?.type!=="commit"?e=B:t==="diff"&&(e=E),D("up",3,e)}else s==="history"?Be():s==="compare"?Oe():s==="explorer"&&We()},[s,t,g?.type,B,E,D,Be,Oe,We]),Ut=m(()=>{if(s==="files")j(e=>Math.min(n-1,e+1));else if(s==="diff"){let e;t==="compare"&&g?.type!=="commit"?e=B:t==="diff"&&(e=E),D("down",3,e)}else s==="history"?Fe():s==="compare"?He():s==="explorer"&&Ne()},[s,t,g?.type,B,E,n,D,Fe,He,Ne]),Wt=m(()=>{t==="diff"||t==="commit"?c(e=>e==="files"?"diff":"files"):t==="history"?c(e=>e==="history"?"diff":"history"):t==="compare"?c(e=>e==="compare"?"diff":"compare"):t==="explorer"&&c(e=>e==="explorer"?"diff":"explorer")},[t]),Nt=m(async()=>{a&&!a.staged&&await S(a)},[a,S]),jt=m(async()=>{a?.staged&&await y(a)},[a,y]),_t=m(async()=>{a&&(a.staged?await y(a):await S(a))},[a,S,y]),Gt=m(()=>b("commit"),[b]),zt=m(()=>{xe("diff"),c("files")},[]),Kt=m(e=>{ut(e),C(null),Ye({theme:e})},[]);so({onStage:Nt,onUnstage:jt,onStageAll:et,onUnstageAll:tt,onCommit:Gt,onQuit:Je,onRefresh:rt,onNavigateUp:At,onNavigateDown:Ut,onTogglePane:Wt,onSwitchTab:b,onSelect:_t,onToggleIncludeUncommitted:Tt,onCycleBaseBranch:bt,onOpenThemePicker:()=>C("theme"),onShrinkTopPane:()=>Pe(-Xe),onGrowTopPane:()=>Pe(Xe),onOpenHotkeysModal:()=>C("hotkeys"),onToggleMouse:ze,onToggleFollow:()=>Ve(e=>!e),onToggleAutoTab:()=>we(e=>!e),onToggleWrap:()=>Ce(e=>!e),onExplorerEnter:t==="explorer"?Et:void 0,onExplorerBack:t==="explorer"?Bt:void 0},s,Se||A!==null||re),Jt((e,d)=>{L&&(e==="y"||e==="Y"?($e(L),J(null)):(e==="n"||e==="N"||d.escape)&&J(null))},{isActive:!!L});const ne=()=>l(W,{dimColor:!0,children:"\u2500".repeat(i)});return X(M,{flexDirection:"column",height:O,width:i,overflowX:"hidden",children:[l(M,{height:be,width:i,children:l(Vt,{repoPath:P,branch:H?.branch??null,isLoading:me,error:de,debug:x.debug,watcherState:q,width:i})}),l(ne,{}),l(oo,{bottomTab:t,currentPane:s,terminalWidth:i,topPaneHeight:v,files:u,selectedIndex:w,fileListScrollOffset:te,stagedCount:ge,onStage:S,onUnstage:y,commits:K,historySelectedIndex:yt,historyScrollOffset:G,onSelectHistoryCommit:(e,d)=>U(d),compareDiff:R,compareListSelection:g,compareScrollOffset:z,includeUncommitted:wt,explorerCurrentPath:Rt,explorerItems:le,explorerSelectedIndex:vt,explorerScrollOffset:_,explorerIsLoading:Ft,explorerError:kt}),l(ne,{}),l(ro,{bottomTab:t,currentPane:s,terminalWidth:i,bottomPaneHeight:gt,diffScrollOffset:xt,currentTheme:ye,diff:N,selectedFile:Ze,stagedCount:ge,onCommit:ot,onCommitCancel:zt,getHeadCommitMessage:it,onCommitInputFocusChange:pt,historySelectedCommit:ue,historyCommitDiff:he,compareDiff:R,compareLoading:lt,compareError:st,compareListSelection:g,compareSelectionDiff:mt,wrapMode:T,explorerSelectedFile:Dt,explorerFileScrollOffset:Te}),l(ne,{}),L?X(M,{children:[X(W,{color:"yellow",bold:!0,children:["Discard changes to"," "]}),l(W,{color:"cyan",children:L.path}),X(W,{color:"yellow",bold:!0,children:["?"," "]}),l(W,{dimColor:!0,children:"(y/n)"})]}):l(to,{activeTab:t,mouseEnabled:Lt,autoTabEnabled:V,wrapMode:T}),A==="theme"&&l(M,{position:"absolute",marginTop:0,marginLeft:0,children:l(So,{currentTheme:ye,onSelect:Kt,onCancel:()=>C(null),width:i,height:O})}),A==="hotkeys"&&l(M,{position:"absolute",marginTop:0,marginLeft:0,children:l(yo,{onClose:()=>C(null),width:i,height:O})}),re&&l(M,{position:"absolute",marginTop:0,marginLeft:0,children:l(wo,{candidates:Ct,currentBranch:R?.baseBranch??null,onSelect:Pt,onCancel:It,width:i,height:O})})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as r,jsxs as
|
|
1
|
+
import{jsx as r,jsxs as s}from"react/jsx-runtime";import{useMemo as v}from"react";import{Box as l,Text as i}from"ink";import{UnifiedDiffView as U}from"./UnifiedDiffView.js";import{CommitPanel as X}from"./CommitPanel.js";import{ExplorerContentView as k}from"./ExplorerContentView.js";import{shortenPath as g}from"../utils/formatPath.js";import{buildDiffDisplayRows as H,buildHistoryDisplayRows as q,buildCompareDisplayRows as z,getDisplayRowsLineNumWidth as F,wrapDisplayRows as J}from"../utils/displayRows.js";export function BottomPane({bottomTab:n,currentPane:t,terminalWidth:o,bottomPaneHeight:w,diffScrollOffset:I,currentTheme:N,diff:m,selectedFile:C,stagedCount:B,onCommit:O,onCommitCancel:D,getHeadCommitMessage:G,onCommitInputFocusChange:M,historySelectedCommit:f,historyCommitDiff:y,compareDiff:e,compareLoading:V,compareError:R,compareListSelection:u,compareSelectionDiff:x,wrapMode:p,explorerSelectedFile:h=null,explorerFileScrollOffset:Y=0}){const a=t!=="files"&&t!=="history"&&t!=="compare"&&t!=="explorer",c=v(()=>n==="diff"?H(m):n==="history"?q(f,y):n==="compare"?u?.type==="commit"&&x?H(x):z(e):[],[n,m,f,y,u,x,e]),_=v(()=>{if(!p||c.length===0)return c;const d=F(c),E=o-d-5;return J(c,E,p)},[c,o,p]),j=()=>{if(C&&n==="diff")return r(i,{dimColor:!0,children:g(C.path,o-10)});if(n==="history"&&f)return s(i,{dimColor:!0,children:[f.shortHash," - ",f.message.slice(0,50)]});if(n==="compare"&&u)if(u.type==="commit"){const d=e?.commits[u.index];return s(i,{dimColor:!0,children:[d?.shortHash??""," - ",d?.message.slice(0,40)??""]})}else{const d=e?.files[u.index]?.path??"";return r(i,{dimColor:!0,children:g(d,o-10)})}return n==="explorer"&&h?r(i,{dimColor:!0,children:g(h.path,o-10)}):null},A=()=>{if(n==="commit")return r(X,{isActive:t==="commit",stagedCount:B,onCommit:O,onCancel:D,getHeadMessage:G,onInputFocusChange:M});if(n==="compare"){if(V)return r(i,{dimColor:!0,children:"Loading compare diff..."});if(R)return r(i,{color:"red",children:R});if(!e)return r(i,{dimColor:!0,children:"No base branch found (no origin/main or origin/master)"});if(e.files.length===0)return s(i,{dimColor:!0,children:["No changes compared to ",e.baseBranch]})}return r(U,{rows:_,maxHeight:w-1,scrollOffset:I,theme:N,width:o,wrapMode:p})};return n==="explorer"?s(l,{flexDirection:"column",height:w,width:o,overflowY:"hidden",children:[s(l,{width:o,children:[r(i,{bold:!0,color:a?"cyan":void 0,children:"FILE"}),r(l,{flexGrow:1,justifyContent:"flex-end",children:j()})]}),r(k,{filePath:h?.path??null,content:h?.content??null,maxHeight:w-1,scrollOffset:Y,truncated:h?.truncated})]}):s(l,{flexDirection:"column",height:w,width:o,overflowX:"hidden",overflowY:"hidden",children:[s(l,{width:o,children:[r(i,{bold:!0,color:a?"cyan":void 0,children:n==="commit"?"COMMIT":"DIFF"}),r(l,{flexGrow:1,justifyContent:"flex-end",children:j()})]}),A()]})}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{jsx as e,jsxs as m}from"react/jsx-runtime";import{useMemo as u}from"react";import{Box as t,Text as n}from"ink";import{ScrollableList as f}from"./ScrollableList.js";export function ExplorerContentView({filePath:i,content:l,maxHeight:c,scrollOffset:s,truncated:h=!1}){const o=u(()=>l?l.split(`
|
|
2
|
+
`).map((r,d)=>({lineNum:d+1,content:r})):[],[l]),a=u(()=>{const r=o.length;return Math.max(3,String(r).length)},[o.length]);return i?l?o.length===0?e(t,{paddingX:1,children:e(n,{dimColor:!0,children:"(empty file)"})}):m(t,{flexDirection:"column",paddingX:1,children:[e(f,{items:o,maxHeight:c,scrollOffset:s,getKey:r=>`${r.lineNum}`,renderItem:r=>{const d=String(r.lineNum).padStart(a," ");return m(t,{children:[m(n,{dimColor:!0,children:[d," "]}),e(n,{children:r.content||" "})]})}}),h&&e(t,{children:e(n,{color:"yellow",dimColor:!0,children:"(file truncated)"})})]}):e(t,{paddingX:1,children:e(n,{dimColor:!0,children:"Loading..."})}):e(t,{paddingX:1,children:e(n,{dimColor:!0,children:"Select a file to view its contents"})})}export function getExplorerContentTotalRows(i){return i?i.split(`
|
|
3
|
+
`).length:0}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsxs as y,jsx as e}from"react/jsx-runtime";import{Box as t,Text as n}from"ink";import{ScrollableList as g}from"./ScrollableList.js";export function ExplorerView({currentPath:o,items:i,selectedIndex:a,scrollOffset:s,maxHeight:u,isActive:m,width:f,isLoading:h=!1,error:c=null}){if(c)return e(t,{flexDirection:"column",children:y(n,{color:"red",children:["Error: ",c]})});if(h)return e(t,{flexDirection:"column",children:e(n,{dimColor:!0,children:"Loading..."})});if(i.length===0)return e(t,{flexDirection:"column",children:e(n,{dimColor:!0,children:"(empty directory)"})});const x=Math.min(Math.max(...i.map(r=>r.name.length+(r.isDirectory?1:0))),f-10);return e(g,{items:i,maxHeight:u,scrollOffset:s,getKey:r=>r.path||r.name,renderItem:(r,p)=>{const l=p===a&&m,d=(r.isDirectory?`${r.name}/`:r.name).padEnd(x+1);return e(t,{children:e(n,{color:l?"cyan":void 0,bold:l,inverse:l,children:r.isDirectory?e(n,{color:l?"cyan":"blue",children:d}):e(n,{color:l?"cyan":void 0,children:d})})})}})}export function buildBreadcrumbs(o){return o?o.split("/").filter(Boolean):[]}export function getExplorerTotalRows(o){return o.length}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as e,jsxs as l}from"react/jsx-runtime";import{Box as
|
|
1
|
+
import{jsx as e,jsxs as l}from"react/jsx-runtime";import{Box as c,Text as o}from"ink";export function Footer({activeTab:r,mouseEnabled:i=!0,autoTabEnabled:n=!1,wrapMode:d=!1}){return l(c,{justifyContent:"space-between",children:[l(o,{children:[e(o,{dimColor:!0,children:"?"})," ",e(o,{color:"yellow",children:i?"[scroll]":"m:[select]"})," ",e(o,{color:n?"blue":void 0,dimColor:!n,children:"[auto]"})," ",e(o,{color:d?"blue":void 0,dimColor:!d,children:"[wrap]"})]}),l(o,{children:[e(o,{color:r==="diff"?"cyan":void 0,bold:r==="diff",children:"[1]Diff"})," ",e(o,{color:r==="commit"?"cyan":void 0,bold:r==="commit",children:"[2]Commit"})," ",e(o,{color:r==="history"?"cyan":void 0,bold:r==="history",children:"[3]History"})," ",e(o,{color:r==="compare"?"cyan":void 0,bold:r==="compare",children:"[4]Compare"})]})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as t,jsxs as c}from"react/jsx-runtime";import{Box as i,Text as s,useInput as C}from"ink";import{Modal as b,centerModal as M}from"./Modal.js";const r=[{title:"Navigation",entries:[{key:"\u2191/k",description:"Move up"},{key:"\u2193/j",description:"Move down"},{key:"Tab",description:"Toggle pane focus"}]},{title:"Staging",entries:[{key:"^S",description:"Stage file"},{key:"^U",description:"Unstage file"},{key:"^A",description:"Stage all"},{key:"^Z",description:"Unstage all"},{key:"Space/Enter",description:"Toggle stage"}]},{title:"Actions",entries:[{key:"c",description:"Open commit panel"},{key:"r",description:"Refresh"},{key:"q",description:"Quit"}]},{title:"Pane Resize",entries:[{key:"[",description:"Shrink top pane"},{key:"]",description:"Grow top pane"}]},{title:"Tabs",entries:[{key:"1",description:"Diff view"},{key:"2",description:"Commit panel"},{key:"3",description:"History view"},{key:"4",description:"Compare view"},{key:"a",description:"Toggle auto-tab mode"}]},{title:"Other",entries:[{key:"m",description:"Toggle scroll/select mode"},{key:"f",description:"Toggle follow mode"},{key:"t",description:"Theme picker"},{key:"b",description:"Base branch picker"},{key:"u",description:"Toggle uncommitted"},{key:"?",description:"This help"}]}];export function HotkeysModal({onClose:T,width:h,height:y}){C((e,o)=>{(o.escape||o.return||e==="?")&&T()});const m=h>=90,l=m?38:30,d=Math.min(m?82:40,h-4);let
|
|
1
|
+
import{jsx as t,jsxs as c}from"react/jsx-runtime";import{Box as i,Text as s,useInput as C}from"ink";import{Modal as b,centerModal as M}from"./Modal.js";const r=[{title:"Navigation",entries:[{key:"\u2191/k",description:"Move up"},{key:"\u2193/j",description:"Move down"},{key:"Tab",description:"Toggle pane focus"}]},{title:"Staging",entries:[{key:"^S",description:"Stage file"},{key:"^U",description:"Unstage file"},{key:"^A",description:"Stage all"},{key:"^Z",description:"Unstage all"},{key:"Space/Enter",description:"Toggle stage"}]},{title:"Actions",entries:[{key:"c",description:"Open commit panel"},{key:"r",description:"Refresh"},{key:"q",description:"Quit"}]},{title:"Pane Resize",entries:[{key:"[",description:"Shrink top pane"},{key:"]",description:"Grow top pane"}]},{title:"Tabs",entries:[{key:"1",description:"Diff view"},{key:"2",description:"Commit panel"},{key:"3",description:"History view"},{key:"4",description:"Compare view"},{key:"a",description:"Toggle auto-tab mode"}]},{title:"Other",entries:[{key:"m",description:"Toggle scroll/select mode"},{key:"f",description:"Toggle follow mode"},{key:"w",description:"Toggle wrap mode"},{key:"t",description:"Theme picker"},{key:"b",description:"Base branch picker"},{key:"u",description:"Toggle uncommitted"},{key:"?",description:"This help"}]}];export function HotkeysModal({onClose:T,width:h,height:y}){C((e,o)=>{(o.escape||o.return||e==="?")&&T()});const m=h>=90,l=m?38:30,d=Math.min(m?82:40,h-4);let p;if(m){const e=Math.ceil(r.length/2),o=r.slice(0,e),n=r.slice(e),a=o.reduce((g,k)=>g+k.entries.length+2,0),w=n.reduce((g,k)=>g+k.entries.length+2,0);p=Math.min(Math.max(a,w)+5,y-4)}else{const e=r.reduce((o,n)=>o+n.entries.length+2,0)+4;p=Math.min(e,y-4)}const{x:f,y:x}=M(d,p,h,y),u=(e,o)=>c(i,{flexDirection:"column",marginBottom:1,children:[t(s,{bold:!0,dimColor:!0,children:e.title}),e.entries.map(n=>c(i,{children:[t(i,{width:13,children:t(s,{color:"cyan",children:n.key})}),t(i,{width:o-13,children:t(s,{children:n.description})})]},n.key))]},e.title);if(m){const e=Math.ceil(r.length/2),o=r.slice(0,e),n=r.slice(e);return t(b,{x:f,y:x,width:d,height:p,children:c(i,{borderStyle:"round",borderColor:"cyan",flexDirection:"column",width:d,children:[t(i,{justifyContent:"center",marginBottom:1,children:c(s,{bold:!0,color:"cyan",children:[" ","Keyboard Shortcuts"," "]})}),c(i,{children:[t(i,{flexDirection:"column",width:l,marginRight:2,children:o.map(a=>u(a,l))}),t(i,{flexDirection:"column",width:l,children:n.map(a=>u(a,l))})]}),t(i,{marginTop:1,justifyContent:"center",children:t(s,{dimColor:!0,children:"Press Esc, Enter, or ? to close"})})]})})}return t(b,{x:f,y:x,width:d,height:p,children:c(i,{borderStyle:"round",borderColor:"cyan",flexDirection:"column",width:d,children:[t(i,{justifyContent:"center",marginBottom:1,children:c(s,{bold:!0,color:"cyan",children:[" ","Keyboard Shortcuts"," "]})}),r.map(e=>u(e,l)),t(i,{marginTop:1,justifyContent:"center",children:t(s,{dimColor:!0,children:"Press Esc, Enter, or ? to close"})})]})})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsxs as
|
|
1
|
+
import{jsxs as s,jsx as f}from"react/jsx-runtime";import{useMemo as C}from"react";import{Box as R,Text as w}from"ink";export function ScrollableList({items:e,renderItem:u,maxHeight:i,scrollOffset:o,getKey:n,header:r,showIndicators:m=!0,getItemHeight:x}){const d=!!x,{itemRowStarts:S,totalRows:g}=C(()=>{if(!d)return{itemRowStarts:[],totalRows:e.length};const a=[];let t=0;for(let l=0;l<e.length;l++)a.push(t),t+=x(e[l],l);return{itemRowStarts:a,totalRows:t}},[e,x,d]);let h=i;r&&h--;const j=o>0,p=(d?g:e.length)>i;m&&p&&(h-=2),h=Math.max(1,h);const v=[];let c=0,M=0,b=0;if(d){let a=0;for(let t=0;t<e.length;t++){const l=x(e[t],t);if(S[t]+l>o){a=t;break}}for(let t=a;t<e.length&&c<h;t++){const l=x(e[t],t);v.push({item:e[t],index:t}),c+=l}M=o,b=Math.max(0,g-o-c)}else{const a=Math.min(o+h,e.length);for(let t=o;t<a;t++)v.push({item:e[t],index:t}),c++;M=o,b=Math.max(0,e.length-o-c)}return s(R,{flexDirection:"column",overflowX:"hidden",height:i,overflow:"hidden",children:[r,m&&p&&(j?s(w,{dimColor:!0,children:["\u2191 ",M," more above"]}):f(w,{children:" "})),v.map(({item:a,index:t})=>f(R,{children:u(a,t)},`${o}-${t}-${n(a,t)}`)),m&&p&&(b>0?s(w,{dimColor:!0,children:["\u2193 ",b," more below"]}):f(w,{children:" "}))]})}export function getMaxScrollOffset(e,u,i=!1,o=!0){let n=u;return i&&n--,o&&e>n&&(n-=2),n=Math.max(1,n),Math.max(0,e-n)}export function getVisibleItemCount(e,u,i,o=!1,n=!0){let r=u;return o&&r--,n&&(i>0&&r--,e>i+r&&r--),r=Math.max(1,r),Math.min(r,e-i)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as
|
|
1
|
+
import{jsx as e,jsxs as o,Fragment as s}from"react/jsx-runtime";import G from"react";import{Box as n,Text as i}from"ink";import{FileList as X}from"./FileList.js";import{HistoryView as b}from"./HistoryView.js";import{CompareListView as z}from"./CompareListView.js";import{ExplorerView as H,buildBreadcrumbs as N}from"./ExplorerView.js";import{categorizeFiles as Y}from"../utils/fileCategories.js";export function TopPane({bottomTab:d,currentPane:l,terminalWidth:c,topPaneHeight:t,files:h,selectedIndex:g,fileListScrollOffset:C,stagedCount:w,onStage:y,onUnstage:a,commits:u,historySelectedIndex:A,historyScrollOffset:O,onSelectHistoryCommit:p,compareDiff:r,compareListSelection:v,compareScrollOffset:F,includeUncommitted:f,explorerCurrentPath:m="",explorerItems:I=[],explorerSelectedIndex:E=0,explorerScrollOffset:R=0,explorerIsLoading:j=!1,explorerError:L=null}){const{modified:S,untracked:k}=Y(h),B=S.length,M=k.length;return o(n,{flexDirection:"column",height:t,width:c,overflowX:"hidden",overflowY:"hidden",children:[(d==="diff"||d==="commit")&&o(s,{children:[o(n,{children:[e(i,{bold:!0,color:l==="files"?"cyan":void 0,children:"STAGING AREA"}),o(i,{dimColor:!0,children:[" ","(",B," modified, ",M," untracked, ",w," staged)"]})]}),e(X,{files:h,selectedIndex:g,isFocused:l==="files",scrollOffset:C,maxHeight:t-1,width:c,onStage:y,onUnstage:a})]}),d==="history"&&o(s,{children:[o(n,{children:[e(i,{bold:!0,color:l==="history"?"cyan":void 0,children:"COMMITS"}),o(i,{dimColor:!0,children:[" (",u.length," commits)"]})]}),e(b,{commits:u,selectedIndex:A,scrollOffset:O,maxHeight:t-1,isActive:l==="history",width:c,onSelectCommit:p})]}),d==="compare"&&o(s,{children:[o(n,{children:[e(i,{bold:!0,color:l==="compare"?"cyan":void 0,children:"COMPARE"}),e(i,{dimColor:!0,children:" (vs "}),e(i,{color:"cyan",children:r?.baseBranch??"..."}),o(i,{dimColor:!0,children:[": ",r?.commits.length??0," commits, ",r?.files.length??0," files) (b)"]}),r&&r.uncommittedCount>0&&o(s,{children:[e(i,{dimColor:!0,children:" | "}),o(i,{color:f?"magenta":"yellow",children:["[",f?"x":" ","] uncommitted"]}),e(i,{dimColor:!0,children:" (u)"})]})]}),e(z,{commits:r?.commits??[],files:r?.files??[],selectedItem:v,scrollOffset:F,maxHeight:t-1,isActive:l==="compare",width:c})]}),d==="explorer"&&o(s,{children:[o(n,{children:[e(i,{bold:!0,color:l==="explorer"?"cyan":void 0,children:"EXPLORER"}),e(i,{dimColor:!0,children:" "}),N(m).map((V,x,_)=>o(G.Fragment,{children:[e(i,{color:"blue",children:V}),x<_.length-1&&e(i,{dimColor:!0,children:" / "})]},x)),m&&e(i,{dimColor:!0,children:" /"}),!m&&e(i,{dimColor:!0,children:"(root)"})]}),e(H,{currentPath:m,items:I,selectedIndex:E,scrollOffset:R,maxHeight:t-1,isActive:l==="explorer",width:c,isLoading:j,error:L})]})]})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsxs as f,jsx as e}from"react/jsx-runtime";import{useMemo as N}from"react";import{Box as m,Text as o}from"ink";import{getTheme as D}from"../themes.js";import{ScrollableList as I}from"./ScrollableList.js";import{getDisplayRowsLineNumWidth as j}from"../utils/displayRows.js";function l(n,r){return r<=0||n.length<=r?n:r<=1?"\u2026":n.slice(0,r-1)+"\u2026"}function b(n,r){return n===void 0?" ".repeat(r):String(n).padStart(r," ")}function T({row:n,lineNumWidth:r,width:g,theme:C,wrapMode:u}){const{colors:c}=C,h=g-r-5,s=g-2;switch(n.type){case"diff-header":{const t=n.content;if(t.startsWith("diff --git")){const i=t.match(/diff --git a\/.+ b\/(.+)$/);if(i){const a=s-6,d=l(i[1],a);return f(o,{color:"cyan",bold:!0,children:["\u2500\u2500 ",d," \u2500\u2500"]})}}return e(o,{dimColor:!0,children:l(t,s)})}case"diff-hunk":{const t=n.content.match(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$/);if(t){const i=parseInt(t[1],10),a=t[2]?parseInt(t[2],10):1,d=parseInt(t[3],10),p=t[4]?parseInt(t[4],10):1,x=t[5].trim(),k=i+a-1,B=d+p-1,S=a===1?`${i}`:`${i}-${k}`,R=p===1?`${d}`:`${d}-${B}`,y=`Lines ${S} \u2192 ${R}`,L=s-y.length-1,$=x&&L>3?" "+l(x,L):"";return f(m,{children:[e(o,{color:"cyan",dimColor:!0,children:y}),$&&e(o,{color:"gray",children:$})]})}return e(o,{color:"cyan",dimColor:!0,children:l(n.content,s)})}case"diff-add":{const t=n.isContinuation,i=t?"\xBB":"+",d=" "+(u?n.content||"":l(n.content,h)||"")||" ";return f(m,{children:[e(o,{backgroundColor:c.addBg,color:c.addLineNum,children:b(n.lineNum,r)+" "}),e(o,{backgroundColor:c.addBg,color:t?c.addLineNum:c.addSymbol,bold:!t,children:i}),e(o,{backgroundColor:c.addBg,color:c.text,children:d})]})}case"diff-del":{const t=n.isContinuation,i=t?"\xBB":"-",d=" "+(u?n.content||"":l(n.content,h)||"")||" ";return f(m,{children:[e(o,{backgroundColor:c.delBg,color:c.delLineNum,children:b(n.lineNum,r)+" "}),e(o,{backgroundColor:c.delBg,color:t?c.delLineNum:c.delSymbol,bold:!t,children:i}),e(o,{backgroundColor:c.delBg,color:c.text,children:d})]})}case"diff-context":{const i=n.isContinuation?"\xBB ":" ",a=u?n.content:l(n.content,h);return f(m,{children:[f(o,{color:c.contextLineNum,children:[b(n.lineNum,r)," "]}),e(o,{dimColor:!0,children:i}),e(o,{children:a})]})}case"commit-header":return e(o,{color:"yellow",children:l(n.content,s)});case"commit-message":return e(o,{children:l(n.content,s)});case"spacer":return e(o,{children:" "})}}export function UnifiedDiffView({rows:n,maxHeight:r,scrollOffset:g,theme:C,width:u,wrapMode:c=!1}){const h=N(()=>D(C),[C]),s=N(()=>j(n),[n]);return n.length===0?e(m,{paddingX:1,children:e(o,{dimColor:!0,children:"No diff to display"})}):e(m,{flexDirection:"column",paddingX:1,width:u,children:e(I,{items:n,maxHeight:r,scrollOffset:g,getKey:(t,i)=>`row-${i}`,renderItem:t=>e(T,{row:t,lineNumWidth:s,width:u,theme:h,wrapMode:c})})})}export function getUnifiedDiffTotalRows(n){return n.length}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useState as
|
|
1
|
+
import{useState as a,useEffect as h,useCallback as o,useMemo as L,useRef as Z}from"react";import{getCompareItemIndexFromRow as _,getFileScrollOffset as $}from"../utils/rowCalculations.js";import{buildCompareDisplayRows as H,getDisplayRowsLineNumWidth as S,getWrappedRowCount as p}from"../utils/displayRows.js";export function useCompareState({repoPath:m,isActive:s,compareDiff:t,refreshCompareDiff:R,getCandidateBaseBranches:k,setCompareBaseBranch:y,selectCompareCommit:C,topPaneHeight:b,compareScrollOffset:i,setCompareScrollOffset:g,setDiffScrollOffset:l,status:T,wrapMode:U,terminalWidth:F}){const[d,W]=a(!0),[z,I]=a(null),[u,w]=a(0),r=Z(!1),[E,M]=a([]),[N,x]=a(!1);h(()=>{m&&s&&R(d)},[m,s,T,R,d]),h(()=>{m&&s&&k().then(M)},[m,s,k]),h(()=>{s&&(r.current=!1,I(null),l(0))},[s,l]),h(()=>{if(s&&t&&r.current){const n=t.commits.length,e=t.files.length;if(u<n)I({type:"commit",index:u}),C(u),l(0);else if(u<n+e){const c=u-n;I({type:"file",index:c});const Y=$(t,c);l(Y)}}},[s,t,u,C,l]);const B=L(()=>t?t.commits.length+t.files.length:0,[t]),j=L(()=>{const n=H(t);if(!U)return n.length;const e=S(n),c=F-e-5;return p(n,c,!0)},[t,U,F]),q=o(()=>{W(n=>!n)},[]),G=o(()=>{x(!0)},[]),J=o(()=>{x(!1)},[]),K=o(n=>{x(!1),y(n,d)},[y,d]),P=o(()=>{r.current=!0},[]),Q=o(()=>{r.current=!0,w(n=>{const e=Math.max(0,n-1);return e<i&&g(e),e})},[i,g]),V=o(()=>{r.current=!0,w(n=>{const e=Math.min(B-1,n+1),c=i+b-2;return e>=c&&g(i+1),e})},[B,i,b,g]),X=o(n=>t?_(n,t.commits.length,t.files.length):-1,[t]);return{includeUncommitted:d,compareListSelection:z,compareSelectedIndex:u,baseBranchCandidates:E,showBaseBranchPicker:N,compareTotalItems:B,compareDiffTotalRows:j,setCompareSelectedIndex:w,toggleIncludeUncommitted:q,openBaseBranchPicker:G,closeBaseBranchPicker:J,selectBaseBranch:K,navigateCompareUp:Q,navigateCompareDown:V,markSelectionInitialized:P,getItemIndexFromRow:X}}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{useState as p,useEffect as k,useCallback as L,useMemo as v}from"react";import*as z from"node:fs";import*as h from"node:path";import{simpleGit as G}from"simple-git";const K=1024*1024,N=100*1024;function W(r){const s=Math.min(r.length,8192);for(let m=0;m<s;m++)if(r[m]===0)return!0;return!1}async function X(r,s){if(s.length===0)return new Set;const m=G(r),d=new Set,c=100;for(let g=0;g<s.length;g+=c){const w=s.slice(g,g+c);try{const F=(await m.raw(["check-ignore",...w])).trim().split(`
|
|
2
|
+
`).filter(i=>i.length>0);for(const i of F)d.add(i)}catch{}}return d}export function useExplorerState({repoPath:r,isActive:s,topPaneHeight:m,explorerScrollOffset:d,setExplorerScrollOffset:c,fileScrollOffset:g,setFileScrollOffset:w}){const[t,F]=p(""),[i,E]=p([]),[D,I]=p(0),[x,f]=p(null),[_,B]=p(!1),[$,C]=p(null);k(()=>{if(!s||!r)return;(async()=>{B(!0),C(null);try{const a=h.join(r,t),o=await z.promises.readdir(a,{withFileTypes:!0}),y=o.map(e=>t?h.join(t,e.name):e.name),M=await X(r,y),l=o.filter(e=>{const u=t?h.join(t,e.name):e.name;return!M.has(u)}).map(e=>({name:e.name,path:t?h.join(t,e.name):e.name,isDirectory:e.isDirectory()}));l.sort((e,u)=>e.isDirectory&&!u.isDirectory?-1:!e.isDirectory&&u.isDirectory?1:e.name.localeCompare(u.name)),t&&l.unshift({name:"..",path:h.dirname(t)||"",isDirectory:!0}),E(l),I(0),c(0)}catch(a){C(a instanceof Error?a.message:"Failed to read directory"),E([])}finally{B(!1)}})()},[r,t,s,c]),k(()=>{if(!s||!r||i.length===0){f(null);return}const n=i[D];if(!n||n.isDirectory){f(null);return}(async()=>{try{const o=h.join(r,n.path),y=await z.promises.stat(o);if(y.size>K){f({path:n.path,content:`File too large to display (${(y.size/1024/1024).toFixed(2)} MB).
|
|
3
|
+
Maximum size: 1 MB`,truncated:!0});return}const M=await z.promises.readFile(o);if(W(M)){f({path:n.path,content:"Binary file - cannot display"});return}let l=M.toString("utf-8"),e=!1;y.size>N&&(l=`\u26A0 Large file (${(y.size/1024).toFixed(1)} KB)
|
|
4
|
+
|
|
5
|
+
`+l);const u=5e3,j=l.split(`
|
|
6
|
+
`);j.length>u&&(l=j.slice(0,u).join(`
|
|
7
|
+
`)+`
|
|
8
|
+
|
|
9
|
+
... (truncated, ${j.length-u} more lines)`,e=!0),f({path:n.path,content:l,truncated:e}),w(0)}catch(o){f({path:n.path,content:o instanceof Error?`Error: ${o.message}`:"Failed to read file"})}})()},[r,i,D,s,w]);const T=v(()=>i.length,[i]),b=L(()=>{I(n=>{const a=Math.max(0,n-1);return a<d&&c(a),a})},[d,c]),R=L(()=>{I(n=>{const a=Math.min(i.length-1,n+1),o=d+m-2;return a>=o&&c(d+1),a})},[i.length,d,m,c]),U=L(()=>{const n=i[D];n&&n.isDirectory&&(n.name===".."?F(h.dirname(t)||""):F(n.path))},[i,D,t]),Z=L(()=>{t&&F(h.dirname(t)||"")},[t]);return{currentPath:t,items:i,selectedIndex:D,setSelectedIndex:I,selectedFile:x,fileScrollOffset:g,setFileScrollOffset:w,navigateUp:b,navigateDown:R,enterDirectory:U,goUp:Z,isLoading:_,error:$,explorerTotalRows:T}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useState as
|
|
1
|
+
import{useState as h,useEffect as I,useCallback as b,useMemo as W}from"react";import{getCommitHistory as k}from"../git/status.js";import{buildHistoryDisplayRows as C,getDisplayRowsLineNumWidth as H,getWrappedRowCount as L}from"../utils/displayRows.js";export function useHistoryState({repoPath:s,isActive:u,selectHistoryCommit:g,historyCommitDiff:c,historySelectedCommit:w,topPaneHeight:p,historyScrollOffset:e,setHistoryScrollOffset:i,setDiffScrollOffset:r,status:y,wrapMode:x,terminalWidth:R}){const[t,D]=h([]),[a,m]=h(0);I(()=>{s&&u&&k(s,100).then(D)},[s,u,y]),I(()=>{if(u&&t.length>0){const n=t[a];n&&(g(n),r(0))}},[u,t,a,g,r]);const E=W(()=>{const n=C(w,c);if(!x)return n.length;const o=H(n),d=R-o-5;return L(n,d,!0)},[w,c,x,R]),M=W(()=>t.length,[t]),N=b(()=>{m(n=>{const o=Math.max(0,n-1);return o<e&&i(o),o})},[e,i]),T=b(()=>{m(n=>{const o=Math.min(t.length-1,n+1),d=e+p-2;return o>=d&&i(e+1),o})},[t.length,e,p,i]);return{commits:t,historySelectedIndex:a,setHistorySelectedIndex:m,historyDiffTotalRows:E,navigateHistoryUp:N,navigateHistoryDown:T,historyTotalRows:M}}
|
package/dist/hooks/useKeymap.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useInput as
|
|
1
|
+
import{useInput as l}from"ink";export function useKeymap(r,n,f){l((e,o)=>{if(!f){if(o.ctrl&&e==="c"){r.onQuit();return}if(e==="q"){r.onQuit();return}if(e==="j"||o.downArrow){r.onNavigateDown();return}if(e==="k"||o.upArrow){r.onNavigateUp();return}if(o.tab){r.onTogglePane();return}if(e==="1"){r.onSwitchTab("diff");return}if(e==="2"){r.onSwitchTab("commit");return}if(e==="3"){r.onSwitchTab("history");return}if(e==="4"){r.onSwitchTab("compare");return}if(e==="5"){r.onSwitchTab("explorer");return}if(e==="u"&&r.onToggleIncludeUncommitted){r.onToggleIncludeUncommitted();return}if(e==="b"&&r.onCycleBaseBranch){r.onCycleBaseBranch();return}if(e==="t"&&r.onOpenThemePicker){r.onOpenThemePicker();return}if(e==="?"&&r.onOpenHotkeysModal){r.onOpenHotkeysModal();return}if(e==="["&&r.onShrinkTopPane){r.onShrinkTopPane();return}if(e==="]"&&r.onGrowTopPane){r.onGrowTopPane();return}if(e==="m"&&r.onToggleMouse){r.onToggleMouse();return}if(e==="f"&&r.onToggleFollow){r.onToggleFollow();return}if(e==="a"&&r.onToggleAutoTab){r.onToggleAutoTab();return}if(e==="w"&&r.onToggleWrap){r.onToggleWrap();return}if(o.ctrl&&e==="s"){r.onStage();return}if(o.ctrl&&e==="u"){r.onUnstage();return}if(o.ctrl&&e==="a"){r.onStageAll();return}if(o.ctrl&&e==="z"){r.onUnstageAll();return}if(e==="c"){r.onCommit();return}if(o.ctrl&&e==="r"){r.onRefresh();return}if(e==="r"){r.onRefresh();return}if(r.onExplorerEnter&&o.return){r.onExplorerEnter();return}if(r.onExplorerBack&&(o.backspace||o.delete||e==="h")){r.onExplorerBack();return}if(o.return||e===" "){r.onSelect();return}}})}
|
package/dist/hooks/useLayout.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useState as m,useEffect as
|
|
1
|
+
import{useState as m,useEffect as g,useMemo as T,useCallback as a}from"react";import{getRowForFileIndex as q,calculateScrollOffset as z,getFileListSectionCounts as G,getFileListTotalRows as J}from"../utils/layoutCalculations.js";import{calculatePaneBoundaries as K}from"../utils/mouseCoordinates.js";export const LAYOUT_OVERHEAD=5;const b={diff:.4,commit:.4,history:.5,compare:.5,explorer:.4};export const SPLIT_RATIO_STEP=.05;export function useLayout(u,N,l,O,F,S="diff",Q,y,H=0){const r=u-LAYOUT_OVERHEAD-H,[p,R]=m(y??null),x=p??b[S],{topPaneHeight:i,bottomPaneHeight:f}=T(()=>{const t=r-5,o=Math.floor(r*x),s=Math.max(5,Math.min(o,t)),n=r-s;return{topPaneHeight:s,bottomPaneHeight:n}},[r,x]),A=a(e=>{const t=Math.max(.15,Math.min(.85,e));R(t)},[]),E=a(e=>{const t=p??b[S],o=Math.max(.15,Math.min(.85,t+e));R(o)},[p,S]),I=x,d=H+1,_=T(()=>K(i,f,u,d),[i,f,u,d]),[D,h]=m(0),[k,M]=m(0),[B,L]=m(0),[U,w]=m(0);g(()=>{h(0)},[l.length]),g(()=>{M(0)},[F]),g(()=>{const{modifiedCount:e,untrackedCount:t,stagedCount:o}=G(l),s=q(O,e,t,o),n=i-1;h(c=>z(s,c,n))},[O,l,i]);const V=a((e,t=3,o=0)=>{const s=f-1,c=o>s?s-2:s,C=Math.max(0,o-c);M(P=>e==="up"?Math.max(0,P-t):Math.min(C,P+t))},[f]),j=a((e,t=3)=>{const o=J(l),s=i-1,n=Math.max(0,o-s);h(c=>e==="up"?Math.max(0,c-t):Math.min(n,c+t))},[l,i]),W=a((e,t=0,o=3)=>{const s=Math.max(0,t-(i-1));L(n=>e==="up"?Math.max(0,n-o):Math.min(s,n+o))},[i]),Y=a((e,t,o=3)=>{const s=Math.max(0,t-(i-1));w(n=>e==="up"?Math.max(0,n-o):Math.min(s,n+o))},[i]);return{topPaneHeight:i,bottomPaneHeight:f,contentHeight:r,paneBoundaries:_,splitRatio:I,setSplitRatio:A,adjustSplitRatio:E,fileListScrollOffset:D,diffScrollOffset:k,historyScrollOffset:B,compareScrollOffset:U,setFileListScrollOffset:h,setDiffScrollOffset:M,setHistoryScrollOffset:L,setCompareScrollOffset:w,scrollDiff:V,scrollFileList:j,scrollHistory:W,scrollCompare:Y}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isDisplayableDiffLine as p}from"./diffFilters.js";import{getLineRowCount as m}from"./lineBreaking.js";export function getLineContent(t){return t.type==="addition"||t.type==="deletion"||t.type==="context"&&t.content.startsWith(" ")?t.content.slice(1):t.content}export function getLineNumWidth(t){let e=0;for(const o of t)o.oldLineNum&&o.oldLineNum>e&&(e=o.oldLineNum),o.newLineNum&&o.newLineNum>e&&(e=o.newLineNum);return Math.max(3,String(e).length)}export function getDiffLineWidth(t,e){if(t.type==="header"){if(t.content.startsWith("diff --git")){const n=t.content.match(/diff --git a\/.+ b\/(.+)$/);if(n)return n[1].length+6+2}return t.content.length+2}if(t.type==="hunk"){const n=t.content.match(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$/);if(n){const c=parseInt(n[1],10),i=n[2]?parseInt(n[2],10):1,s=parseInt(n[3],10),f=n[4]?parseInt(n[4],10):1,u=n[5]?.trim()??"",a=c+i-1,d=s+f-1,g=i===1?`${c}`:`${c}-${a}`,h=f===1?`${s}`:`${s}-${d}`;return`Lines ${g} \u2192 ${h}`.length+(u?u.length+1:0)+2}return t.content.length+2}const r=getLineContent(t);return e+1+1+1+r.length+2}export function getDiffLineRowCount(t,e,o){if(o<=0||t.type==="header"||t.type==="hunk")return 1;const r=o-e-5;if(r<=0)return 1;const n=getLineContent(t);return m(n,r)}export function getDiffTotalRows(t,e,o){if(!t||e<=0)return 0;const r=t.lines.filter(p);if(r.length===0)return 0;const n=o??getLineNumWidth(r);let c=0;for(const i of r)c+=getDiffLineRowCount(i,n,e);return c}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{formatDateAbsolute as d}from"./formatDate.js";import{isDisplayableDiffLine as h}from"./diffFilters.js";import{breakLine as m,getLineRowCount as l}from"./lineBreaking.js";function p(t){return t.type==="addition"||t.type==="deletion"||t.type==="context"&&t.content.startsWith(" ")?t.content.slice(1):t.content}function y(t){switch(t.type){case"header":return{type:"diff-header",content:t.content};case"hunk":return{type:"diff-hunk",content:t.content};case"addition":return{type:"diff-add",lineNum:t.newLineNum,content:p(t)};case"deletion":return{type:"diff-del",lineNum:t.oldLineNum,content:p(t)};case"context":return{type:"diff-context",lineNum:t.oldLineNum??t.newLineNum,content:p(t)}}}export function buildDiffDisplayRows(t){return t?t.lines.filter(h).map(y):[]}export function buildHistoryDisplayRows(t,o){const e=[];if(t){e.push({type:"commit-header",content:`commit ${t.hash}`}),e.push({type:"commit-header",content:`Author: ${t.author}`}),e.push({type:"commit-header",content:`Date: ${d(t.date)}`}),e.push({type:"spacer"});for(const f of t.message.split(`
|
|
2
|
+
`))e.push({type:"commit-message",content:` ${f}`});e.push({type:"spacer"})}return e.push(...buildDiffDisplayRows(o)),e}export function buildCompareDisplayRows(t){if(!t||t.files.length===0)return[];const o=[];for(const e of t.files)o.push(...buildDiffDisplayRows(e.diff));return o}export function getDisplayRowsLineNumWidth(t){let o=0;for(const e of t)"lineNum"in e&&e.lineNum!==void 0&&(o=Math.max(o,e.lineNum));return Math.max(3,String(o).length)}export function wrapDisplayRows(t,o,e){if(!e)return t;const s=Math.max(10,o),i=[];for(const n of t)if(n.type==="diff-add"||n.type==="diff-del"||n.type==="diff-context"){const r=n.content;if(!r||r.length<=s){i.push(n);continue}const a=m(r,s);for(let u=0;u<a.length;u++){const c=a[u];i.push({...n,content:c.text,lineNum:c.isContinuation?void 0:n.lineNum,isContinuation:c.isContinuation})}}else i.push(n);return i}export function getWrappedRowCount(t,o,e){if(!e)return t.length;const s=Math.max(10,o);let i=0;for(const n of t)if(n.type==="diff-add"||n.type==="diff-del"||n.type==="diff-context"){const r=n.content;!r||r.length<=s?i+=1:i+=l(r,s)}else i+=1;return i}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export function breakLine(t,n,i=!0){if(n<=0)return[{text:t,isContinuation:!1}];if(t.length<=n)return[{text:t,isContinuation:!1}];const r=[];let e=t,o=!0;for(;e.length>0;){if(e.length<=n){r.push({text:e,isContinuation:!o});break}r.push({text:e.slice(0,n),isContinuation:!o}),e=e.slice(n),o=!1}return i&&l(t,n,r),r}function l(t,n,i){const r=i.map(e=>e.text).join("");if(r!==t)throw new Error(`[LineBreaking] Content was lost during breaking!
|
|
2
|
+
Original (${t.length} chars): "${t.slice(0,50)}${t.length>50?"...":""}"
|
|
3
|
+
Joined (${r.length} chars): "${r.slice(0,50)}${r.length>50?"...":""}"`);for(let e=0;e<i.length;e++){const o=i[e];if(o.text.length>n&&n>=1)throw new Error(`[LineBreaking] Segment ${e} exceeds maxWidth!
|
|
4
|
+
Segment length: ${o.text.length}, maxWidth: ${n}
|
|
5
|
+
Segment: "${o.text.slice(0,50)}${o.text.length>50?"...":""}"`)}if(i.length>0&&i[0].isContinuation)throw new Error("[LineBreaking] First segment incorrectly marked as continuation!");for(let e=1;e<i.length;e++)if(!i[e].isContinuation)throw new Error(`[LineBreaking] Segment ${e} should be marked as continuation but isn't!`)}export function getLineRowCount(t,n){return n<=0||t.length<=n?1:Math.ceil(t.length/n)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{categorizeFiles as d}from"./fileCategories.js";export function calculatePaneBoundaries(t,e,r,a=1){const s=a+2,i=a+1+t,f=i+1,
|
|
1
|
+
import{categorizeFiles as d}from"./fileCategories.js";export function calculatePaneBoundaries(t,e,r,a=1){const s=a+2,i=a+1+t,f=i+1,l=i+2,c=l+e-1;return{stagingPaneStart:s,fileListEnd:i,separatorRow:f,diffPaneStart:l,diffPaneEnd:c,footerRow:r}}export function getClickedFileIndex(t,e,r,a,s){if(t<a+1||t>s)return-1;const i=t-(a+1)+e,{modified:f,untracked:l,staged:c}=d(r);let n=0,u=0;if(f.length>0){n++;for(let o=0;o<f.length;o++){if(i===n)return u;n++,u++}}if(l.length>0){f.length>0&&n++,n++;for(let o=0;o<l.length;o++){if(i===n)return u;n++,u++}}if(c.length>0){(f.length>0||l.length>0)&&n++,n++;for(let o=0;o<c.length;o++){if(i===n)return u;n++,u++}}return-1}export function getTabBoundaries(t){const e=t-51;return{diffStart:e,diffEnd:e+6,commitStart:e+8,commitEnd:e+16,historyStart:e+18,historyEnd:e+27,compareStart:e+29,compareEnd:e+38,explorerStart:e+40,explorerEnd:e+50}}export function getClickedTab(t,e){const r=getTabBoundaries(e);return t>=r.diffStart&&t<=r.diffEnd?"diff":t>=r.commitStart&&t<=r.commitEnd?"commit":t>=r.historyStart&&t<=r.historyEnd?"history":t>=r.compareStart&&t<=r.compareEnd?"compare":t>=r.explorerStart&&t<=r.explorerEnd?"explorer":null}export function isButtonAreaClick(t){return t<=6}export function isInPane(t,e,r){return t>=e&&t<=r}export function getFooterLeftClick(t){return t===1?"hotkeys":t>=3&&t<=10?"mouse-mode":t>=12&&t<=17?"auto-tab":t>=19&&t<=24?"wrap":null}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import{isDisplayableDiffLine as
|
|
2
|
-
`);for(const o of i)n.push({type:"commit-message",content:` ${o}`});n.push({type:"spacer"})}if(t)for(const i of t.lines)
|
|
3
|
-
`),
|
|
1
|
+
import{isDisplayableDiffLine as f}from"./diffFilters.js";import{formatDateAbsolute as s}from"./formatDate.js";import{getDiffTotalRows as l,getDiffLineRowCount as u}from"./diffRowCalculations.js";export function getCommitIndexFromRow(e,t,n,i=0){const o=e+i;return o<0||o>=t.length?-1:o}export function getHistoryTotalRows(e,t){return e.length}export function getHistoryRowOffset(e,t,n){return t}export function buildHistoryDiffRows(e,t){const n=[];if(e){n.push({type:"commit-header",content:`commit ${e.hash}`}),n.push({type:"commit-header",content:`Author: ${e.author}`}),n.push({type:"commit-header",content:`Date: ${s(e.date)}`}),n.push({type:"spacer"});const i=e.message.split(`
|
|
2
|
+
`);for(const o of i)n.push({type:"commit-message",content:` ${o}`});n.push({type:"spacer"})}if(t)for(const i of t.lines)f(i)&&n.push({type:"diff-line",diffLine:i});return n}export function getHistoryDiffRowHeight(e,t,n){return e.type!=="diff-line"||!e.diffLine?1:u(e.diffLine,t,n)}export function getHistoryDiffTotalRows(e,t,n){let i=0;e&&(i+=3,i+=1,i+=e.message.split(`
|
|
3
|
+
`).length,i+=1);const o=l(t,n);return i+o}export function buildCombinedCompareDiff(e){if(!e||e.files.length===0)return{raw:"",lines:[]};const t=[],n=[];for(const i of e.files){for(const o of i.diff.lines)t.push(o);n.push(i.diff.raw)}return{raw:n.join(`
|
|
4
|
+
`),lines:t}}export function getCompareDiffTotalRows(e){return buildCombinedCompareDiff(e).lines.filter(f).length}export function getFileScrollOffset(e,t){if(!e||t<0||t>=e.files.length)return 0;const n=buildCombinedCompareDiff(e);let i=0,o=0;for(const r of n.lines){if(r.type==="header"&&r.content.startsWith("diff --git")){if(o===t)return i;o++}f(r)&&i++}return 0}export function getCompareItemIndexFromRow(e,t,n,i=!0,o=!0){let r=0;if(t>0){if(e===r)return-1;if(r++,i){if(e<r+t)return e-r;r+=t}}if(n>0){if(t>0){if(e===r)return-1;r++}if(e===r)return-1;if(r++,o&&e<r+n)return t+(e-r)}return-1}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{jsx as r,jsxs as a}from"react/jsx-runtime";import{useMemo as h}from"react";import{Box as e,Text as o}from"ink";import{DiffView as c}from"./DiffView.js";import{buildCombinedCompareDiff as u}from"../utils/rowCalculations.js";export{buildCombinedCompareDiff,getCompareDiffTotalRows,getFileScrollOffset}from"../utils/rowCalculations.js";export function CompareView({compareDiff:i,isLoading:d,error:n,scrollOffset:t,maxHeight:f,theme:m="dark",width:l}){const s=h(()=>u(i),[i]);return d?r(e,{paddingX:1,children:r(o,{dimColor:!0,children:"Loading diff..."})}):n?r(e,{paddingX:1,children:r(o,{color:"red",children:n})}):i?i.files.length===0?r(e,{paddingX:1,children:a(o,{dimColor:!0,children:["No changes compared to ",i.baseBranch]})}):r(c,{diff:s,maxHeight:f,scrollOffset:t,theme:m,width:l}):r(e,{paddingX:1,children:r(o,{dimColor:!0,children:"No base branch found (no origin/main or origin/master)"})})}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{jsx as a,jsxs as f}from"react/jsx-runtime";import{useMemo as I}from"react";import{Box as p,Text as u}from"ink";import{createEmphasize as R,common as z}from"emphasize";import L from"fast-diff";import{getTheme as G}from"../themes.js";import{ScrollableList as U}from"./ScrollableList.js";import{isDisplayableDiffLine as W}from"../utils/diffFilters.js";const X=R(z);function b(t,e){return e<=0||t.length<=e?t:e<=1?"\u2026":t.slice(0,e-1)+"\u2026"}const q={ts:"typescript",tsx:"typescript",js:"javascript",jsx:"javascript",mjs:"javascript",cjs:"javascript",py:"python",rb:"ruby",rs:"rust",go:"go",java:"java",c:"c",cpp:"cpp",h:"c",hpp:"cpp",cs:"csharp",php:"php",sh:"bash",bash:"bash",zsh:"bash",json:"json",yaml:"yaml",yml:"yaml",md:"markdown",html:"html",htm:"html",css:"css",scss:"scss",sass:"scss",less:"less",sql:"sql",xml:"xml",toml:"ini",ini:"ini",dockerfile:"dockerfile",makefile:"makefile",lua:"lua",vim:"vim",swift:"swift",kt:"kotlin",kts:"kotlin",scala:"scala",r:"r",pl:"perl",ex:"elixir",exs:"elixir",erl:"erlang",hs:"haskell",clj:"clojure",ml:"ocaml",fs:"fsharp",vue:"xml",svelte:"xml"};function O(t){if(!t)return;const e=t.split("/").pop()?.toLowerCase()??"";if(e==="dockerfile")return"dockerfile";if(e==="makefile"||e==="gnumakefile")return"makefile";const n=e.split(".").pop()?.toLowerCase();return n?q[n]||n:void 0}function P(t,e){if(!e||!t.trim())return t;try{return X.highlight(e,t).value}catch{return t}}function Q(t){let e=0;for(const n of t)n.oldLineNum&&n.oldLineNum>e&&(e=n.oldLineNum),n.newLineNum&&n.newLineNum>e&&(e=n.newLineNum);return Math.max(3,String(e).length)}function N(t){return t.type==="addition"||t.type==="deletion"||t.type==="context"&&t.content.startsWith(" ")?t.content.slice(1):t.content}const F=3;function $(t){if(t.length===0)return t;const e=[];for(let n=0;n<t.length;n++){const r=t[n];if(!r.isChange&&r.text.length<F){const o=n>0&&e[e.length-1]?.isChange,s=n<t.length-1&&t[n+1]?.isChange;if(o||s){o&&e.length>0?e[e.length-1].text+=r.text:e.push({text:r.text,isChange:!0});continue}}e.length>0&&e[e.length-1].isChange===r.isChange?e[e.length-1].text+=r.text:e.push({...r})}return e}function K(t,e){const n=L(t,e);let r=[],o=[];for(const[s,i]of n)s===L.EQUAL?(r.push({text:i,isChange:!1}),o.push({text:i,isChange:!1})):s===L.DELETE?r.push({text:i,isChange:!0}):s===L.INSERT&&o.push({text:i,isChange:!0});return r=$(r),o=$(o),{oldSegments:r,newSegments:o}}function V(t,e){if(t.length===0&&e.length===0)return 1;if(t.length===0||e.length===0)return 0;const n=L(t,e);let r=0,o=0;for(const[s,i]of n)s===L.EQUAL&&(r+=i.length),o+=i.length;return o>0?r/o:0}const Y=.35;function J(t){const e=new Map;for(let n=0;n<t.length-1;n++){const r=t[n],o=t[n+1];if(r.type==="deletion"&&o.type==="addition"){const s=N(r),i=N(o);if(V(s,i)>=Y){const d={deletion:r,addition:o,deletionIndex:n,additionIndex:n+1};e.set(n,d),e.set(n+1,d)}}}return e}function Z(t,e){const n=[];let r=e;for(const o of t){if(r<=0)break;if(o.text.length<=r)n.push(o),r-=o.text.length;else{const s=o.text.slice(0,r-1)+"\u2026";n.push({...o,text:s});break}}return n}function M({segments:t,isAddition:e,theme:n,maxWidth:r}){const{colors:o}=n,s=e?o.addBg:o.delBg,i=e?o.addHighlight:o.delHighlight,d=r?Z(t,r):t;return a(u,{backgroundColor:s,children:d.map((x,g)=>a(u,{color:o.text,backgroundColor:x.isChange?i:s,children:x.text||(g===d.length-1?" ":"")},g))})}function tt({line:t,lineNumWidth:e,language:n,wordDiffSegments:r,theme:o,maxWidth:s}){const{colors:i}=o,d=s?s-2:void 0;if(t.type==="header"){const c=t.content;if(c.startsWith("diff --git")){const m=c.match(/diff --git a\/.+ b\/(.+)$/);if(m){const C=d?d-6:void 0,y=C?b(m[1],C):m[1];return a(p,{children:f(u,{color:"cyan",bold:!0,children:["\u2500\u2500 ",y," \u2500\u2500"]})})}}const k=d?b(c,d):c;return a(p,{children:a(u,{dimColor:!0,children:k})})}if(t.type==="hunk"){const c=t.content.match(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$/);if(c){const m=parseInt(c[1],10),C=c[2]?parseInt(c[2],10):1,y=parseInt(c[3],10),v=c[4]?parseInt(c[4],10):1,E=c[5].trim(),T=m+C-1,H=y+v-1,A=C===1?`${m}`:`${m}-${T}`,_=v===1?`${y}`:`${y}-${H}`,B=`Lines ${A} \u2192 ${_}`,S=d?d-B.length-1:void 0,D=E&&S&&S>3?b(E,S):"";return f(p,{children:[a(u,{color:"cyan",dimColor:!0,children:B}),D&&f(u,{color:"gray",children:[" ",D]})]})}const k=d?b(t.content,d):t.content;return a(u,{color:"cyan",dimColor:!0,children:k})}const x=t.type==="addition"?t.newLineNum:t.type==="deletion"?t.oldLineNum:t.oldLineNum??t.newLineNum,g=x!==void 0?String(x).padStart(e," "):" ".repeat(e),w=N(t),l=s?s-e-5:void 0,h=l?b(w,l):w;if(t.type==="addition")return f(p,{children:[f(u,{backgroundColor:i.addBg,color:i.addLineNum,children:[g," "]}),f(u,{backgroundColor:i.addBg,color:i.addSymbol,bold:!0,children:["+"," "]}),r?a(M,{segments:r,isAddition:!0,theme:o,maxWidth:l}):a(u,{backgroundColor:i.addBg,color:i.text,children:h||" "})]});if(t.type==="deletion")return f(p,{children:[f(u,{backgroundColor:i.delBg,color:i.delLineNum,children:[g," "]}),f(u,{backgroundColor:i.delBg,color:i.delSymbol,bold:!0,children:["-"," "]}),r?a(M,{segments:r,isAddition:!1,theme:o,maxWidth:l}):a(u,{backgroundColor:i.delBg,color:i.text,children:h||" "})]});const j=P(h,n);return f(p,{children:[f(u,{color:i.contextLineNum,children:[g," "]}),a(u,{children:j})]})}export function DiffView({diff:t,filePath:e,maxHeight:n=20,scrollOffset:r=0,theme:o="dark",width:s}){const i=I(()=>G(o),[o]),d=I(()=>O(e),[e]),x=I(()=>{if(!t)return new Map;const l=J(t.lines),h=new Map;for(const[j,c]of l)if(j===c.deletionIndex){const k=N(c.deletion),m=N(c.addition),{oldSegments:C,newSegments:y}=K(k,m);h.set(c.deletionIndex,C),h.set(c.additionIndex,y)}return h},[t]),g=I(()=>t?.lines.map((l,h)=>({line:l,originalIndex:h})).filter(({line:l})=>W(l))??[],[t]);if(!t||g.length===0)return a(p,{paddingX:1,children:a(u,{dimColor:!0,children:"No diff to display"})});const w=Q(g.map(l=>l.line));return a(p,{flexDirection:"column",paddingX:1,overflowX:"hidden",children:a(U,{items:g,maxHeight:n,scrollOffset:r,getKey:l=>`${l.originalIndex}`,renderItem:l=>{const h=x.get(l.originalIndex);return a(tt,{line:l.line,lineNumWidth:w,language:d,wordDiffSegments:h,theme:i,maxWidth:s})}})})}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{jsx as i,jsxs as w}from"react/jsx-runtime";import{useMemo as x}from"react";import{Box as r,Text as n}from"ink";import{DiffView as g}from"./DiffView.js";import{buildHistoryDiffRows as R}from"../utils/rowCalculations.js";import{isDisplayableDiffLine as b}from"../utils/diffFilters.js";export{buildHistoryDiffRows,getHistoryDiffTotalRows}from"../utils/rowCalculations.js";export function HistoryDiffView({commit:s,diff:t,scrollOffset:l,maxHeight:d,theme:m="dark",width:a}){const c=x(()=>R(s,t),[s,t]),u=x(()=>{for(let e=0;e<c.length;e++)if(c[e].type==="diff-line")return e;return c.length},[c]),f=c.slice(l,l+d);if(!s)return i(r,{paddingX:1,children:i(n,{dimColor:!0,children:"Select a commit to view its diff"})});if(!t||t.lines.length===0)return w(r,{flexDirection:"column",children:[f.map((e,h)=>{const o=`row-${l+h}`;return e.type==="commit-header"?i(r,{children:i(n,{color:"yellow",children:e.content})},o):e.type==="commit-message"?i(r,{children:i(n,{children:e.content})},o):e.type==="spacer"?i(r,{children:i(n,{children:" "})},o):null}),i(r,{children:i(n,{dimColor:!0,children:"No changes in this commit"})})]});const p=t.lines.filter(b);if(l>=u)return i(g,{diff:{raw:t.raw,lines:p},maxHeight:d,scrollOffset:l-u,theme:m,width:a});const D=f.filter(e=>e.type!=="diff-line"),y=d-D.length;return w(r,{flexDirection:"column",overflowX:"hidden",children:[f.map((e,h)=>{const o=`row-${l+h}`;return e.type==="commit-header"?i(r,{children:i(n,{color:"yellow",children:e.content})},o):e.type==="commit-message"?i(r,{children:i(n,{children:e.content})},o):e.type==="spacer"?i(r,{children:i(n,{children:" "})},o):null}),y>0&&i(g,{diff:{raw:t.raw,lines:p},maxHeight:y,scrollOffset:0,theme:m,width:a})]})}
|