@@ -39,6 +39,12 @@ pub struct RepoInfo {
3939 pub size_bytes : Option < u64 > ,
4040 /// Current operation status
4141 pub operation_status : RepoOperationStatus ,
42+ /// Whether this repo is a submodule
43+ pub is_submodule : bool ,
44+ /// Whether this submodule is initialized (checked out)
45+ pub submodule_initialized : bool ,
46+ /// Path to parent repository (for submodules)
47+ pub parent_repo_path : Option < PathBuf > ,
4248}
4349
4450#[ derive( Clone ) ]
@@ -78,6 +84,30 @@ impl TreeNode {
7884 }
7985 }
8086
87+ pub fn new_submodule (
88+ name : String ,
89+ parent_path : PathBuf ,
90+ submodule_path : PathBuf ,
91+ initialized : bool ,
92+ ) -> Self {
93+ Self {
94+ name,
95+ repo_info : Some ( RepoInfo {
96+ path : parent_path. join ( & submodule_path) ,
97+ display_name : submodule_path. display ( ) . to_string ( ) ,
98+ is_clean : true , // Submodule status computed separately
99+ modification_time : None ,
100+ size_bytes : None ,
101+ operation_status : RepoOperationStatus :: None ,
102+ is_submodule : true ,
103+ submodule_initialized : initialized,
104+ parent_repo_path : Some ( parent_path) ,
105+ } ) ,
106+ children : Vec :: new ( ) ,
107+ expanded : false , // Submodules start collapsed
108+ }
109+ }
110+
81111 /// Flatten the tree into a list of (node, depth, index_path, full_path) tuples
82112 pub fn flatten (
83113 & self ,
@@ -142,8 +172,13 @@ impl TreeNode {
142172
143173/// Build a tree structure from a flat list of repos
144174pub fn build_tree ( mut repos : Vec < RepoInfo > ) -> Vec < TreeNode > {
145- // Sort repos by modification time (most recent first)
146- repos. sort_by ( |a, b| {
175+ // Separate regular repos from submodules
176+ let ( submodules, regular_repos) : ( Vec < _ > , Vec < _ > ) =
177+ repos. drain ( ..) . partition ( |r| r. is_submodule ) ;
178+
179+ // Sort regular repos by modification time (most recent first)
180+ let mut sorted_repos = regular_repos;
181+ sorted_repos. sort_by ( |a, b| {
147182 match ( a. modification_time , b. modification_time ) {
148183 ( Some ( a_time) , Some ( b_time) ) => b_time. cmp ( & a_time) , // Most recent first
149184 ( Some ( _) , None ) => std:: cmp:: Ordering :: Less , // Items with time come first
@@ -154,7 +189,8 @@ pub fn build_tree(mut repos: Vec<RepoInfo>) -> Vec<TreeNode> {
154189
155190 let mut root_nodes: Vec < TreeNode > = Vec :: new ( ) ;
156191
157- for repo in repos {
192+ // Build tree from regular repos
193+ for repo in sorted_repos {
158194 let parts: Vec < & str > = repo. display_name . split ( '/' ) . collect ( ) ;
159195
160196 if parts. is_empty ( ) {
@@ -189,9 +225,68 @@ pub fn build_tree(mut repos: Vec<RepoInfo>) -> Vec<TreeNode> {
189225 }
190226 }
191227
228+ // Now insert submodules as children of their parent repos
229+ for submodule in submodules {
230+ insert_submodule_into_tree ( & mut root_nodes, submodule) ;
231+ }
232+
192233 root_nodes
193234}
194235
236+ /// Helper function to insert a submodule into the tree as a child of its parent repo
237+ fn insert_submodule_into_tree ( root_nodes : & mut Vec < TreeNode > , submodule : RepoInfo ) {
238+ let parent_path = match & submodule. parent_repo_path {
239+ Some ( path) => path,
240+ None => return , // Shouldn't happen, but skip if no parent
241+ } ;
242+
243+ // Find the parent repo node
244+ if let Some ( parent_node) = find_repo_node_by_path ( root_nodes, parent_path) {
245+ // Create submodule node
246+ let submodule_name = submodule
247+ . path
248+ . file_name ( )
249+ . and_then ( |n| n. to_str ( ) )
250+ . unwrap_or ( & submodule. display_name )
251+ . to_string ( ) ;
252+
253+ let submodule_node = TreeNode :: new_submodule (
254+ submodule_name,
255+ parent_path. clone ( ) ,
256+ submodule
257+ . path
258+ . strip_prefix ( parent_path)
259+ . unwrap_or ( & submodule. path )
260+ . to_path_buf ( ) ,
261+ submodule. submodule_initialized ,
262+ ) ;
263+
264+ // Add as child of parent
265+ parent_node. children . push ( submodule_node) ;
266+ }
267+ }
268+
269+ /// Recursively find a tree node by its repository path
270+ fn find_repo_node_by_path < ' a > (
271+ nodes : & ' a mut Vec < TreeNode > ,
272+ path : & PathBuf ,
273+ ) -> Option < & ' a mut TreeNode > {
274+ for node in nodes {
275+ // Check if this node matches
276+ if let Some ( ref repo_info) = node. repo_info
277+ && & repo_info. path == path
278+ {
279+ return Some ( node) ;
280+ }
281+
282+ // Recursively check children
283+ if let Some ( found) = find_repo_node_by_path ( & mut node. children , path) {
284+ return Some ( found) ;
285+ }
286+ }
287+ None
288+ }
289+
195290/// Build library tree, excluding repos that exist in workspace
196291pub fn build_library_tree (
197292 library_repos : Vec < RepoInfo > ,
0 commit comments