diffstalker 0.1.6 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/release.yml +5 -3
- package/CHANGELOG.md +36 -0
- package/bun.lock +378 -0
- package/dist/App.js +1162 -1
- package/dist/config.js +83 -2
- package/dist/core/ExplorerStateManager.js +266 -0
- package/dist/core/FilePathWatcher.js +133 -0
- package/dist/core/GitOperationQueue.js +109 -1
- package/dist/core/GitStateManager.js +525 -1
- package/dist/git/diff.js +471 -10
- package/dist/git/ignoreUtils.js +30 -0
- package/dist/git/status.js +237 -5
- package/dist/index.js +70 -16
- package/dist/ipc/CommandClient.js +165 -0
- package/dist/ipc/CommandServer.js +152 -0
- package/dist/services/commitService.js +22 -1
- package/dist/state/CommitFlowState.js +86 -0
- package/dist/state/UIState.js +182 -0
- package/dist/themes.js +127 -1
- package/dist/types/tabs.js +4 -0
- package/dist/ui/Layout.js +252 -0
- package/dist/ui/modals/BaseBranchPicker.js +110 -0
- package/dist/ui/modals/DiscardConfirm.js +77 -0
- package/dist/ui/modals/HotkeysModal.js +209 -0
- package/dist/ui/modals/ThemePicker.js +107 -0
- package/dist/ui/widgets/CommitPanel.js +58 -0
- package/dist/ui/widgets/CompareListView.js +216 -0
- package/dist/ui/widgets/DiffView.js +279 -0
- package/dist/ui/widgets/ExplorerContent.js +102 -0
- package/dist/ui/widgets/ExplorerView.js +95 -0
- package/dist/ui/widgets/FileList.js +185 -0
- package/dist/ui/widgets/Footer.js +46 -0
- package/dist/ui/widgets/Header.js +111 -0
- package/dist/ui/widgets/HistoryView.js +69 -0
- package/dist/utils/ansiToBlessed.js +125 -0
- package/dist/utils/ansiTruncate.js +108 -0
- package/dist/utils/baseBranchCache.js +44 -2
- package/dist/utils/commitFormat.js +38 -1
- package/dist/utils/diffFilters.js +21 -1
- package/dist/utils/diffRowCalculations.js +113 -1
- package/dist/utils/displayRows.js +351 -2
- package/dist/utils/explorerDisplayRows.js +169 -0
- package/dist/utils/fileCategories.js +26 -1
- package/dist/utils/formatDate.js +39 -1
- package/dist/utils/formatPath.js +58 -1
- package/dist/utils/languageDetection.js +236 -0
- package/dist/utils/layoutCalculations.js +98 -1
- package/dist/utils/lineBreaking.js +88 -5
- package/dist/utils/mouseCoordinates.js +165 -1
- package/dist/utils/pathUtils.js +27 -0
- package/dist/utils/rowCalculations.js +246 -4
- package/dist/utils/wordDiff.js +50 -0
- package/package.json +15 -19
- package/dist/components/BaseBranchPicker.js +0 -1
- package/dist/components/BottomPane.js +0 -1
- package/dist/components/CommitPanel.js +0 -1
- package/dist/components/CompareListView.js +0 -1
- package/dist/components/ExplorerContentView.js +0 -3
- package/dist/components/ExplorerView.js +0 -1
- package/dist/components/FileList.js +0 -1
- package/dist/components/Footer.js +0 -1
- package/dist/components/Header.js +0 -1
- package/dist/components/HistoryView.js +0 -1
- package/dist/components/HotkeysModal.js +0 -1
- package/dist/components/Modal.js +0 -1
- package/dist/components/ScrollableList.js +0 -1
- package/dist/components/ThemePicker.js +0 -1
- package/dist/components/TopPane.js +0 -1
- package/dist/components/UnifiedDiffView.js +0 -1
- package/dist/hooks/useCommitFlow.js +0 -1
- package/dist/hooks/useCompareState.js +0 -1
- package/dist/hooks/useExplorerState.js +0 -9
- package/dist/hooks/useGit.js +0 -1
- package/dist/hooks/useHistoryState.js +0 -1
- package/dist/hooks/useKeymap.js +0 -1
- package/dist/hooks/useLayout.js +0 -1
- package/dist/hooks/useMouse.js +0 -1
- package/dist/hooks/useTerminalSize.js +0 -1
- package/dist/hooks/useWatcher.js +0 -11
|
@@ -1 +0,0 @@
|
|
|
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"})})]})})}
|
package/dist/components/Modal.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{jsx as e,jsxs as c}from"react/jsx-runtime";import{Box as i,Text as x}from"ink";export function Modal({x:o,y:r,width:n,height:t,children:l}){const a=" ".repeat(n);return c(i,{position:"absolute",marginLeft:o,marginTop:r,flexDirection:"column",children:[Array.from({length:t}).map((f,s)=>e(x,{children:a},`blank-${s}`)),e(i,{position:"absolute",flexDirection:"column",children:l})]})}export function centerModal(o,r,n,t){return{x:Math.floor((n-o)/2),y:Math.floor((t-r)/2)}}
|
|
@@ -1 +0,0 @@
|
|
|
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 +0,0 @@
|
|
|
1
|
-
import{jsx as o,jsxs as c}from"react/jsx-runtime";import{useState as y}from"react";import{Box as l,Text as r,useInput as w}from"ink";import{themes as j,themeOrder as t,getTheme as S}from"../themes.js";import{Modal as T,centerModal as v}from"./Modal.js";function M({theme:h}){const{colors:e}=h;return c(l,{flexDirection:"column",marginLeft:2,children:[c(l,{children:[o(r,{backgroundColor:e.delBg,color:e.delLineNum,children:" 5 "}),o(r,{backgroundColor:e.delBg,color:e.delSymbol,bold:!0,children:"- "}),o(r,{backgroundColor:e.delBg,color:e.text,children:"const "}),o(r,{backgroundColor:e.delHighlight,color:e.text,children:"old"}),o(r,{backgroundColor:e.delBg,color:e.text,children:" = value;"})]}),c(l,{children:[o(r,{backgroundColor:e.addBg,color:e.addLineNum,children:" 5 "}),o(r,{backgroundColor:e.addBg,color:e.addSymbol,bold:!0,children:"+ "}),o(r,{backgroundColor:e.addBg,color:e.text,children:"const "}),o(r,{backgroundColor:e.addHighlight,color:e.text,children:"new"}),o(r,{backgroundColor:e.addBg,color:e.text,children:" = value;"})]})]})}export function ThemePicker({currentTheme:h,onSelect:e,onCancel:f,width:m,height:g}){const[a,x]=y(()=>{const n=t.indexOf(h);return n>=0?n:0}),C=S(t[a]);w((n,d)=>{d.escape?f():d.return?e(t[a]):d.upArrow||n==="k"?x(i=>Math.max(0,i-1)):(d.downArrow||n==="j")&&x(i=>Math.min(t.length-1,i+1))});const s=Math.min(50,m-4),b=Math.min(t.length+10,g-4),{x:p,y:B}=v(s,b,m,g);return o(T,{x:p,y:B,width:s,height:b,children:c(l,{borderStyle:"round",borderColor:"cyan",flexDirection:"column",width:s,children:[o(l,{justifyContent:"center",marginBottom:1,children:c(r,{bold:!0,color:"cyan",children:[" ","Select Theme"," "]})}),t.map((n,d)=>{const i=j[n],u=d===a,k=n===h;return c(l,{children:[o(r,{color:u?"cyan":void 0,children:u?"\u25B8 ":" "}),o(r,{bold:u,color:u?"cyan":void 0,children:i.displayName}),k&&o(r,{dimColor:!0,children:" (current)"})]},n)}),c(l,{marginTop:1,flexDirection:"column",children:[o(r,{dimColor:!0,children:"Preview:"}),o(M,{theme:C})]}),o(l,{marginTop:1,justifyContent:"center",children:o(r,{dimColor:!0,children:"\u2191\u2193 navigate \u2022 Enter select \u2022 Esc cancel"})})]})})}
|
|
@@ -1 +0,0 @@
|
|
|
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})]})]})}
|
|
@@ -1 +0,0 @@
|
|
|
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 +0,0 @@
|
|
|
1
|
-
import{useState as o,useCallback as i,useEffect as M}from"react";import{validateCommit as S,formatCommitMessage as b}from"../services/commitService.js";export function useCommitFlow(C){const{stagedCount:l,onCommit:m,onSuccess:c,getHeadMessage:f}=C,[s,n]=o(""),[t,r]=o(!1),[p,u]=o(!1),[h,a]=o(null),[v,d]=o(!1);M(()=>{t&&f().then(e=>{e&&!s&&n(e)})},[t,f]);const y=i(()=>{r(e=>!e)},[]),E=i(async()=>{const e=S(s,l,t);if(!e.valid){a(e.error);return}u(!0),a(null);try{await m(b(s),t),n(""),r(!1),c()}catch(g){a(g instanceof Error?g.message:"Commit failed")}finally{u(!1)}},[s,l,t,m,c]),F=i(()=>{n(""),r(!1),a(null),d(!1)},[]);return{message:s,amend:t,isCommitting:p,error:h,inputFocused:v,setMessage:n,toggleAmend:y,setInputFocused:d,handleSubmit:E,reset:F}}
|
|
@@ -1 +0,0 @@
|
|
|
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}}
|
|
@@ -1,9 +0,0 @@
|
|
|
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}}
|
package/dist/hooks/useGit.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{useState as i,useEffect as k,useCallback as a,useRef as v}from"react";import{getManagerForRepo as I,removeManagerForRepo as T}from"../core/GitStateManager.js";export function useGit(c){const[n,m]=i({status:null,diff:null,stagedDiff:"",selectedFile:null,isLoading:!1,error:null}),[o,p]=i({compareDiff:null,compareBaseBranch:null,compareLoading:!1,compareError:null}),[f,h]=i({selectedCommit:null,commitDiff:null}),[l,C]=i({type:null,index:0,diff:null}),t=v(null);k(()=>{if(!c){m({status:null,diff:null,stagedDiff:"",selectedFile:null,isLoading:!1,error:null});return}const e=I(c);t.current=e;const s=r=>{m(r)},u=r=>{p(r)},g=r=>{h(r)},d=r=>{C(r)};return e.on("state-change",s),e.on("compare-state-change",u),e.on("history-state-change",g),e.on("compare-selection-change",d),e.startWatching(),e.refresh(),()=>{e.off("state-change",s),e.off("compare-state-change",u),e.off("history-state-change",g),e.off("compare-selection-change",d),T(c),t.current=null}},[c]);const y=a(e=>{t.current?.selectFile(e)},[]),S=a(async e=>{await t.current?.stage(e)},[]),B=a(async e=>{await t.current?.unstage(e)},[]),D=a(async e=>{await t.current?.discard(e)},[]),w=a(async()=>{await t.current?.stageAll()},[]),F=a(async()=>{await t.current?.unstageAll()},[]),L=a(async(e,s=!1)=>{await t.current?.commit(e,s)},[]),H=a(async()=>{await t.current?.refresh()},[]),x=a(async()=>t.current?.getHeadCommitMessage()??"",[]),A=a(async(e=!1)=>{await t.current?.refreshCompareDiff(e)},[]),E=a(async()=>t.current?.getCandidateBaseBranches()??[],[]),M=a(async(e,s=!1)=>{await t.current?.setCompareBaseBranch(e,s)},[]),R=a(async e=>{await t.current?.selectHistoryCommit(e)},[]),G=a(async e=>{await t.current?.selectCompareCommit(e)},[]),b=a(e=>{t.current?.selectCompareFile(e)},[]);return{status:n.status,diff:n.diff,stagedDiff:n.stagedDiff,selectedFile:n.selectedFile,isLoading:n.isLoading,error:n.error,selectFile:y,stage:S,unstage:B,discard:D,stageAll:w,unstageAll:F,commit:L,refresh:H,getHeadCommitMessage:x,compareDiff:o.compareDiff,compareBaseBranch:o.compareBaseBranch,compareLoading:o.compareLoading,compareError:o.compareError,refreshCompareDiff:A,getCandidateBaseBranches:E,setCompareBaseBranch:M,historySelectedCommit:f.selectedCommit,historyCommitDiff:f.commitDiff,selectHistoryCommit:R,compareSelectionType:l.type,compareSelectionIndex:l.index,compareSelectionDiff:l.diff,selectCompareCommit:G,selectCompareFile:b}}
|
|
@@ -1 +0,0 @@
|
|
|
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
DELETED
|
@@ -1 +0,0 @@
|
|
|
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
DELETED
|
@@ -1 +0,0 @@
|
|
|
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}}
|
package/dist/hooks/useMouse.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{useEffect as d,useState as y,useCallback as C,useRef as x}from"react";import{useStdin as R}from"ink";export function useMouse(p,b=!1){const{stdin:u,setRawMode:h}=R(),[e,w]=y(!0),o=x(p);d(()=>{o.current=p});const M=C(()=>{w(l=>!l)},[]),a=x(e);return d(()=>{a.current=e},[e]),d(()=>{!b&&e?(process.stdout.write("\x1B[?1000h"),process.stdout.write("\x1B[?1006h")):(process.stdout.write("\x1B[?1006l"),process.stdout.write("\x1B[?1000l"))},[b,e]),d(()=>{if(!u||!h)return;const l=g=>{const m=g.toString(),s=m.match(/\x1b\[<(\d+);(\d+);(\d+)([Mm])/);if(s){const t=parseInt(s[1],10),n=parseInt(s[2],10),r=parseInt(s[3],10),c=s[4]==="m";if(t>=64&&t<96){if(a.current){const f=t===64?"scroll-up":"scroll-down";o.current({x:n,y:r,type:f,button:"none"})}}else if(c&&t>=0&&t<3){const f=t===0?"left":t===1?"middle":"right";o.current({x:n,y:r,type:"click",button:f})}return}const i=m.match(/\x1b\[M(.)(.)(.)/);if(i){const t=i[1].charCodeAt(0)-32,n=i[2].charCodeAt(0)-32,r=i[3].charCodeAt(0)-32;if(t>=64){if(a.current){const c=t===64?"scroll-up":"scroll-down";o.current({x:n,y:r,type:c,button:"none"})}}else if(t>=0&&t<3){const c=t===0?"left":t===1?"middle":"right";o.current({x:n,y:r,type:"click",button:c})}}};return u.on("data",l),()=>{u.off("data",l),process.stdout.write("\x1B[?1006l"),process.stdout.write("\x1B[?1000l")}},[u,h]),{mouseEnabled:e,toggleMouse:M}}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{useState as t,useEffect as r}from"react";export function useTerminalSize(){const[o,e]=t({rows:process.stdout.rows??24,columns:process.stdout.columns??80});return r(()=>{const s=()=>{e({rows:process.stdout.rows??24,columns:process.stdout.columns??80})};return process.stdout.on("resize",s),()=>{process.stdout.off("resize",s)}},[]),o}
|
package/dist/hooks/useWatcher.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import{useState as h,useEffect as S,useRef as $}from"react";import*as f from"node:fs";import*as a from"node:path";import*as v from"node:os";import{watch as b}from"chokidar";import{ensureTargetDir as I}from"../config.js";function y(t){return t.startsWith("~/")?a.join(v.homedir(),t.slice(2)):t==="~"?v.homedir():t}function R(t){const e=t.split(`
|
|
2
|
-
`);for(let s=e.length-1;s>=0;s--){const n=e[s].trim();if(n)return n}return""}export function useWatcher(t,e,s=!1){const[n,T]=h(t),[x,p]=h({path:null,lastUpdate:null,rawContent:null,sourceFile:t?e:null,enabled:t}),i=$(null),l=$(null);return S(()=>{p(d=>({...d,enabled:n,sourceFile:n?e:null}))},[n,e]),S(()=>{if(!n)return;I(e),f.existsSync(e)||f.writeFileSync(e,"");const d=()=>{i.current&&clearTimeout(i.current),i.current=setTimeout(()=>{try{const m=f.readFileSync(e,"utf-8"),r=R(m);if(r&&r!==l.current){const o=y(r),c=a.isAbsolute(o)?o:a.resolve(o),u=new Date;s&&(process.stderr.write(`[diffstalker ${u.toISOString()}] Path change detected
|
|
3
|
-
`),process.stderr.write(` Source file: ${e}
|
|
4
|
-
`),process.stderr.write(` Raw content: "${r}"
|
|
5
|
-
`),process.stderr.write(` Previous: "${l.current??"(none)"}"
|
|
6
|
-
`),process.stderr.write(` Resolved: "${c}"
|
|
7
|
-
`)),l.current=c,p({path:c,lastUpdate:u,rawContent:r,sourceFile:e,enabled:!0})}}catch{}},100)};try{const m=f.readFileSync(e,"utf-8"),r=R(m);if(r){const o=y(r),c=a.isAbsolute(o)?o:a.resolve(o),u=new Date;s&&(process.stderr.write(`[diffstalker ${u.toISOString()}] Initial path read
|
|
8
|
-
`),process.stderr.write(` Source file: ${e}
|
|
9
|
-
`),process.stderr.write(` Raw content: "${r}"
|
|
10
|
-
`),process.stderr.write(` Resolved: "${c}"
|
|
11
|
-
`)),l.current=c,p({path:c,lastUpdate:u,rawContent:r,sourceFile:e,enabled:!0})}}catch{}const w=b(e,{persistent:!0,ignoreInitial:!0});return w.on("change",d),w.on("add",d),()=>{i.current&&clearTimeout(i.current),w.close()}},[n,e,s]),{state:x,setEnabled:T}}
|