Skip to content

Commit

Permalink
work
Browse files Browse the repository at this point in the history
  • Loading branch information
saranshsaini committed Jan 30, 2025
1 parent 14d40d4 commit 2f310df
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 46 deletions.
15 changes: 7 additions & 8 deletions CodeiumVS/LanguageServer/LanguageServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -754,14 +754,12 @@ private async Task InitializeTrackedWorkspaceAsync()
foreach (EnvDTE.Document doc in documents)
{
ProjectItem projectItem = doc.ProjectItem;
await _package.LogAsync($"projectITEM: {projectItem}");
if (projectItem != null)
{
EnvDTE.Project project = projectItem.ContainingProject;
if (project != null && !openFileProjects.Contains(project))
{
openFileProjects.Add(project);
await _package.LogAsync($"Open File FOUNDD: {project}, {project.FullName}, {project.Name}");
}
}
}
Expand Down Expand Up @@ -828,12 +826,13 @@ async Task AddFilesToIndexLists(EnvDTE.Project project)
return;
}
string projectFullName = project.FullName;
string projectName = Path.GetFileNameWithoutExtension(projectFullName);
IEnumerable<string> commonDirs = Enumerable.Empty<string>();

await _package.LogAsync($"Adding files to index of project: {projectFullName}");
if (!string.IsNullOrEmpty(projectFullName) && !processedProjects.Any(p => projectFullName.StartsWith(p)))
{
// Parse the csproj file to find all source directories
string projectName = Path.GetFileNameWithoutExtension(projectFullName);
IEnumerable<string> commonDirs = Enumerable.Empty<string>();
string projectDir = Path.GetDirectoryName(projectFullName);
// Parse the proj file to find all source directories
if (File.Exists(projectFullName) && (projectFullName.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase) || projectFullName.EndsWith(".vcxproj", StringComparison.OrdinalIgnoreCase)))
{
try
Expand Down Expand Up @@ -907,7 +906,7 @@ async Task AddFilesToIndexLists(EnvDTE.Project project)
}
catch (Exception ex)
{
await _package.LogAsync($"Failed to process project: {ex.Message}");
await _package.LogAsync($"Failed to process open project: {ex.Message}");
continue;
}
}
Expand All @@ -923,7 +922,7 @@ async Task AddFilesToIndexLists(EnvDTE.Project project)
}
catch (Exception ex)
{
await _package.LogAsync($"Failed to process project: {ex.Message}");
await _package.LogAsync($"Failed to process remaining project: {ex.Message}");
continue;
}
if (remainingToFind <=0)
Expand Down
114 changes: 76 additions & 38 deletions CodeiumVS/Utilities/FileUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,53 +58,91 @@ internal static List<string> FindMinimumEncompassingDirectories(IEnumerable<stri
{
if (filePaths == null || !filePaths.Any())
return new List<string>();
// Get the directory paths of the file paths
var directoryPaths = filePaths.Select(Path.GetDirectoryName).Distinct().ToList();
CodeiumVSPackage.Instance?.Log($"Directories before minimization: {string.Join(", ", directoryPaths)}");
var result = GetMinimumDirectoryCover(directoryPaths);
CodeiumVSPackage.Instance?.Log($"Directories after minimization: {string.Join(", ", result)}");
return result.Where(dir => CountPathSegments(dir) > 1).ToList();
}


public static List<string> GetMinimumDirectoryCover(IEnumerable<string> directories)
{
// 1. Normalize all paths to full/absolute paths and remove duplicates
var normalizedDirs = directories
.Select(d => NormalizePath(d))
.Distinct()
.ToList();

// Get all parent directories for each file
var allPaths = filePaths.Select(path =>
// 2. Sort by ascending number of path segments (shallow first)
normalizedDirs.Sort((a, b) =>
CountPathSegments(a).CompareTo(CountPathSegments(b)));

var coverSet = new List<string>();

// 3. Greedy selection
foreach (var dir in normalizedDirs)
{
var parents = new List<string>();
var dir = Path.GetDirectoryName(path);
while (!string.IsNullOrEmpty(dir))
bool isCovered = false;

// Check if 'dir' is already covered by any directory in coverSet
foreach (var coverDir in coverSet)
{
parents.Add(dir);
dir = Path.GetDirectoryName(dir);
if (IsSubdirectoryOrSame(coverDir, dir))
{
isCovered = true;
break;
}
}
return parents;
}).ToList();

// Find directories that contain files
var directoryCounts = new Dictionary<string, HashSet<int>>();
for (int i = 0; i < allPaths.Count; i++)
{
foreach (var dir in allPaths[i])
// If not covered, add it to the cover set
if (!isCovered)
{
if (!directoryCounts.ContainsKey(dir))
directoryCounts[dir] = new HashSet<int>();
directoryCounts[dir].Add(i);
coverSet.Add(dir);
}
}

var result = new List<string>();
var coveredFiles = new HashSet<int>();

// While we haven't covered all files
while (coveredFiles.Count < allPaths.Count)
{
// Find directory that covers most uncovered files
var bestDir = directoryCounts
.Where(kvp => kvp.Value.Except(coveredFiles).Any())
.OrderByDescending(kvp => kvp.Value.Except(coveredFiles).Count())
.ThenBy(kvp => kvp.Key.Count(c => c == Path.DirectorySeparatorChar)) // Prefer deeper directories
.FirstOrDefault();

if (bestDir.Key == null)
break;

result.Add(bestDir.Key);
coveredFiles.UnionWith(bestDir.Value);
}
return coverSet;
}

// Filter out paths that are too shallow (less than 3 levels deep)
return result.Where(dir => dir.Count(c => c == Path.DirectorySeparatorChar) >= 2).ToList();
/// <summary>
/// Checks if 'child' is the same or a subdirectory of 'parent'.
/// </summary>
private static bool IsSubdirectoryOrSame(string parent, string child)
{
// 1. Normalize both directories to their full path (remove extra slashes, etc.).
string parentFull = Path.GetFullPath(parent)
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
string childFull = Path.GetFullPath(child)
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);

// 2. Append a directory separator at the end of each path to ensure
// that "C:\Folder" won’t incorrectly match "C:\Folder2".
// e.g. "C:\Folder" -> "C:\Folder\"
parentFull += Path.DirectorySeparatorChar;
childFull += Path.DirectorySeparatorChar;

// 3. On Windows, paths are case-insensitive. Use OrdinalIgnoreCase
// to compare. On non-Windows systems, consider using Ordinal.
return childFull.StartsWith(parentFull, StringComparison.OrdinalIgnoreCase);
}

/// <summary>
/// Normalize a directory path by getting its full path (removing trailing slash, etc).
/// </summary>
private static string NormalizePath(string path)
{
return Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
}

/// <summary>
/// Count path segments based on splitting by directory separators.
/// E.g. "C:\Folder\Sub" -> 3 segments (on Windows).
/// </summary>
private static int CountPathSegments(string path)
{
return path.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
.Count(segment => !string.IsNullOrEmpty(segment));
}
}

0 comments on commit 2f310df

Please sign in to comment.