@@ -146,15 +146,71 @@ module SolutionExplorer =
146146
147147 entry.Children |> Seq.rev |> Seq.map ( toModel projPath) |> Seq.toList
148148
149+ // File extension to item type mapping
150+ let getItemTypeForFile ( filePath : string ) =
151+ let ext = node.path.extname( filePath) .ToLowerInvariant()
152+
153+ match ext with
154+ | " .fs"
155+ | " .fsi" -> " Compile"
156+ | " .fsx" -> " Compile"
157+ | " .fsl" -> " FsLex"
158+ | " .fsy" -> " FsYacc"
159+ | " .txt"
160+ | " .md"
161+ | " .json"
162+ | " .xml"
163+ | " .config" -> " Content"
164+ | " .resx" -> " EmbeddedResource"
165+ | " .dll"
166+ | " .exe" -> " Reference"
167+ | _ -> " Content" // Default fallback
168+
169+ // Check if a folder should be included in the tree view
170+ let isSpecialFolder ( folderName : string ) =
171+ folderName = " .deps"
172+ || folderName = " bin"
173+ || folderName = " obj"
174+ || folderName = " packages"
175+ || folderName = " docs"
176+ || folderName = " scripts"
177+ || folderName = " tools"
178+
149179 let private getProjectModel ( proj : Project ) =
150180 let projects = Project.getLoaded () |> Seq.toArray
151181
152- let files =
153- proj.Items
154- |> Seq.filter ( fun p -> p.Name = " Compile" )
155- |> Seq.map ( fun p -> p.VirtualPath, p.FilePath)
156- |> Seq.toList
157- |> buildTree proj.Project
182+
183+ // Get project files from FSAC
184+ let projectFiles =
185+ proj.Items |> Seq.map ( fun p -> p.VirtualPath, p.FilePath) |> Seq.toList
186+
187+ // Add additional folders that aren't in the project file
188+ let projectDir = node.path.dirname proj.Project
189+
190+ let additionalFolders =
191+ try
192+ let dirContents = node.fs.readdirSync ( U2.Case1 projectDir)
193+
194+ dirContents
195+ |> Seq.filter ( fun item ->
196+ let fullPath = node.path.join ( projectDir, item)
197+ let stats = node.fs.statSync ( U2.Case1 fullPath)
198+ let isDir = stats.isDirectory ()
199+
200+ isDir && isSpecialFolder item)
201+ |> Seq.map ( fun folder ->
202+ let fullPath = node.path.join ( projectDir, folder)
203+ ( folder, fullPath))
204+ |> Seq.toList
205+ with ex ->
206+ []
207+
208+ // Combine project files with additional folders
209+ let allItems =
210+ projectFiles
211+ @ ( additionalFolders |> List.map ( fun ( name , path ) -> ( name, path)))
212+
213+ let files = buildTree proj.Project allItems
158214
159215 let packageRefs =
160216 proj.PackageReferences
@@ -245,13 +301,85 @@ module SolutionExplorer =
245301
246302 match ws with
247303 | WorkspacePeekFound.Solution sln ->
304+ // Get solution items from the solution file
305+ let solutionItems = sln.Items |> Array.map getItem |> List.ofArray
306+
307+ // Add additional folders that aren't in the solution file
308+ let solutionDir = node.path.dirname sln.Path
309+
310+ // Get existing folder names from solution items to avoid duplicates
311+ let existingFolderNames =
312+ solutionItems
313+ |> List.collect ( fun item ->
314+ match item with
315+ | WorkspaceFolder(_, name, _) -> [ name ]
316+ | _ -> [])
317+
318+ let additionalSolutionFolders =
319+ try
320+ let dirContents = node.fs.readdirSync ( U2.Case1 solutionDir)
321+
322+ dirContents
323+ |> Seq.filter ( fun item ->
324+ let fullPath = node.path.join ( solutionDir, item)
325+ let stats = node.fs.statSync ( U2.Case1 fullPath)
326+ let isDir = stats.isDirectory ()
327+
328+ isDir && isSpecialFolder item && not ( existingFolderNames |> List.contains item))
329+ |> Seq.map ( fun folder ->
330+ let fullPath = node.path.join ( solutionDir, folder)
331+
332+ // Recursively scan the contents of this folder
333+ let rec scanFolderContents ( currentPath : string ) ( depth : int ) =
334+ // Helper function to determine if an item should be hidden
335+ let shouldHideItem ( item : string ) ( depth : int ) =
336+ item.StartsWith( " ." ) && item <> " .deps"
337+ || item = " node_modules"
338+ || item = " .git"
339+ || item = " .vs"
340+ || ( item = " packages" && depth > 0 )
341+
342+ try
343+ let contents = node.fs.readdirSync ( U2.Case1 currentPath)
344+
345+ contents
346+ |> Seq.filter ( fun item -> not ( shouldHideItem item depth))
347+ |> Seq.map ( fun item ->
348+ let itemPath = node.path.join ( currentPath, item)
349+ let stats = node.fs.statSync ( U2.Case1 itemPath)
350+
351+ if stats.isDirectory () then
352+ // Recursively scan subdirectories (limit depth to avoid infinite recursion)
353+ if depth < 6 then
354+ let subContents = scanFolderContents itemPath ( depth + 1 )
355+ Model.Folder( ref None, item, itemPath, subContents, " " )
356+ else
357+ // For very deep directories, just show as empty folder
358+ Model.Folder( ref None, item, itemPath, [], " " )
359+ else
360+ // Use the same file type mapping as project level
361+ let itemType = getItemTypeForFile item
362+
363+ // For files, create a file representation
364+ Model.File( ref None, itemPath, item, None, " " ))
365+ |> Seq.toList
366+ with ex ->
367+ []
368+
369+ let folderContents = scanFolderContents fullPath 0
370+
371+
372+ // Create a WorkspaceFolder with the scanned contents
373+ Model.WorkspaceFolder( ref None, folder, folderContents))
374+ |> Seq.toList
375+ with ex ->
376+ []
377+
378+ // Combine solution items with additional folders
379+ let allSolutionItems = solutionItems @ additionalSolutionFolders
380+
248381 let s =
249- Solution(
250- ref None,
251- sln.Path,
252- ( node.path.basename sln.Path),
253- ( sln.Items |> Array.map getItem |> List.ofArray)
254- )
382+ Solution( ref None, sln.Path, ( node.path.basename sln.Path), allSolutionItems)
255383
256384 let result = Workspace [ s ]
257385 setParentRef s result
0 commit comments