Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/common/Helpers/FileHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public static IEnumerable<string> FindFiles(string path, string pattern)

public static IEnumerable<string> FindFiles(string fileNames)
{
fileNames = PathHelpers.ExpandPath(fileNames);
var currentDir = Directory.GetCurrentDirectory();
foreach (var item in fileNames.Split(new char[] { ';', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries))
{
Expand Down Expand Up @@ -103,11 +104,14 @@ public static IEnumerable<string> FindFilesInOsPath(string fileName)

public static bool FileExists(string? fileName)
{
return !string.IsNullOrEmpty(fileName) && (File.Exists(fileName) || fileName == "-");
if (string.IsNullOrEmpty(fileName)) return false;
fileName = PathHelpers.ExpandPath(fileName);
return File.Exists(fileName) || fileName == "-";
}

public static bool IsFileMatch(string fileName, List<Regex> includeFileContainsPatternList, List<Regex> excludeFileContainsPatternList)
{
fileName = PathHelpers.ExpandPath(fileName);
var checkContent = includeFileContainsPatternList.Any() || excludeFileContainsPatternList.Any();
if (!checkContent) return true;

Expand Down Expand Up @@ -185,6 +189,7 @@ public static bool IsFileMatch(string fileName, List<Regex> includeFileContainsP

public static void ReadIgnoreFile(string ignoreFile, out List<string> excludeGlobs, out List<Regex> excludeFileNamePatternList)
{
ignoreFile = PathHelpers.ExpandPath(ignoreFile);
ConsoleHelpers.WriteDebugLine($"ReadIgnoreFile: ignoreFile: {ignoreFile}");

excludeGlobs = new List<string>();
Expand Down Expand Up @@ -355,6 +360,7 @@ public static bool IsFileTimeMatch(string fileName,
DateTime? accessedAfter, DateTime? accessedBefore,
DateTime? anyTimeAfter, DateTime? anyTimeBefore)
{
fileName = PathHelpers.ExpandPath(fileName);
try
{
var fileInfo = new FileInfo(fileName);
Expand Down Expand Up @@ -436,6 +442,7 @@ public static string MakeRelativePath(string fullPath)

public static string ReadAllText(string fileName)
{
fileName = PathHelpers.ExpandPath(fileName);
var content = ConsoleHelpers.IsStandardInputReference(fileName)
? string.Join("\n", ConsoleHelpers.GetAllLinesFromStdin())
: File.ReadAllText(fileName, Encoding.UTF8);
Expand All @@ -445,6 +452,7 @@ public static string ReadAllText(string fileName)

public static string[] ReadAllLines(string fileName)
{
fileName = PathHelpers.ExpandPath(fileName);
var lines = ConsoleHelpers.IsStandardInputReference(fileName)
? ConsoleHelpers.GetAllLinesFromStdin().ToArray()
: File.ReadAllLines(fileName, Encoding.UTF8);
Expand All @@ -454,6 +462,7 @@ public static string[] ReadAllLines(string fileName)

public static string WriteAllText(string fileName, string content, string? saveToFolderOnAccessDenied = null)
{
fileName = PathHelpers.ExpandPath(fileName);
try
{
DirectoryHelpers.EnsureDirectoryForFileExists(fileName);
Expand All @@ -478,6 +487,7 @@ public static string WriteAllText(string fileName, string content, string? saveT

public static void AppendAllText(string fileName, string trajectoryContent)
{
fileName = PathHelpers.ExpandPath(fileName);
DirectoryHelpers.EnsureDirectoryForFileExists(fileName);
File.AppendAllText(fileName, trajectoryContent, Encoding.UTF8);
}
Expand Down Expand Up @@ -638,6 +648,9 @@ private static char[] GetInvalidFileNameCharsForWeb()
{
if (fileNames == null || fileNames.Length == 0)
return null;

// Expand tilde paths for all filenames
fileNames = fileNames.Select(PathHelpers.ExpandPath).ToArray();

var currentPath = Directory.GetCurrentDirectory();

Expand Down
32 changes: 32 additions & 0 deletions src/common/Helpers/PathHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;

public class PathHelpers
{
public static string? Combine(string path1, string path2)
Expand Down Expand Up @@ -47,4 +51,32 @@ public static string NormalizePath(string outputDirectory)
? normalized.Substring(cwd.Length + 1)
: normalized;
}

/// <summary>
/// Expands tilde (~) paths to full paths using the user's home directory.
/// Handles both "~" (home directory) and "~/path" (home directory + path).
/// </summary>
/// <param name="path">The path that may contain a tilde</param>
/// <returns>The expanded path with tilde replaced by the home directory</returns>
public static string ExpandPath(string path)
{
if (string.IsNullOrEmpty(path))
return path;

// Handle exact "~" case
if (path == "~")
{
return Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
}

// Handle "~/..." case
if (path.StartsWith("~/"))
{
var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
return Path.Combine(homeDir, path.Substring(2));
}

// Return unchanged if no tilde expansion needed
return path;
}
}
10 changes: 10 additions & 0 deletions src/cycod/FunctionCallingTools/StrReplaceEditorHelperFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public class StrReplaceEditorHelperFunctions
[Description("Returns a list of non-hidden files and directories up to 2 levels deep.")]
public string ListFiles([Description("Absolute or relative path to directory.")] string path)
{
path = PathHelpers.ExpandPath(path);

if (Directory.Exists(path))
{
path = Path.GetFullPath(path);
Expand Down Expand Up @@ -54,6 +56,8 @@ public string ViewFile(
[Description("Maximum number of characters to display per line.")] int maxCharsPerLine = 500,
[Description("Maximum total number of characters to display.")] int maxTotalChars = 100000)
{
path = PathHelpers.ExpandPath(path);

// Basic file validation
var noFile = Directory.Exists(path) || !File.Exists(path);
if (noFile) return $"Path {path} does not exist or is not a file.";
Expand Down Expand Up @@ -296,6 +300,7 @@ public string CreateFile(
[Description("Absolute or relative path to file.")] string path,
[Description("Content to be written to the file.")] string fileText)
{

if (File.Exists(path))
{
return $"Path {path} already exists; cannot create file. Use ViewFile and then ReplaceOneInFile to edit the file.";
Expand All @@ -312,6 +317,7 @@ public string ReplaceFileContent(
[Description("New content to replace the entire file.")] string newContent,
[Description("Current line count of the file (for verification).")] int oldContentLineCount)
{

if (!File.Exists(path))
{
return $"File {path} does not exist. Use CreateFile to create a new file.";
Expand Down Expand Up @@ -392,6 +398,7 @@ public string ReplaceOneInFile(
[Description("Existing text in the file that should be replaced. Must match exactly one occurrence.")] string oldStr,
[Description("New string content that will replace the old string.")] string newStr)
{

if (!File.Exists(path))
{
return $"File {path} does not exist.";
Expand Down Expand Up @@ -422,6 +429,7 @@ public string ReplaceMultipleInFile(
[Description("Array of old strings to be replaced. Each must match exactly one occurrence.")] string[] oldStrings,
[Description("Array of new strings to replace with. Must be same length as oldStrings.")] string[] newStrings)
{

if (!File.Exists(path))
{
return $"File {path} does not exist.";
Expand Down Expand Up @@ -491,6 +499,7 @@ public string Insert(
[Description("Line number (1-indexed) after which to insert the new string.")] int insertLine,
[Description("The string to insert into the file.")] string newStr)
{

if (!File.Exists(path))
{
return $"File {path} does not exist.";
Expand Down Expand Up @@ -518,6 +527,7 @@ public string Insert(
public string UndoEdit(
[Description("Absolute or relative path to file.")] string path)
{

if (!EditHistory.ContainsKey(path))
{
return $"No previous edit found for {path}.";
Expand Down