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
53 changes: 53 additions & 0 deletions src/DiffEngineViewer.Tests/RevealFileTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/// <summary>
/// What "reveal" opens. The path it is given is often one that does not exist: revealing a pending
/// move points at the target, and for a snapshot being written for the first time nothing is there
/// yet.
/// </summary>
public class RevealFileTests :
IDisposable
{
[Test]
public async Task A_file_that_is_there_is_selected()
{
var file = Path.Combine(directory, "sample.verified.txt");
File.WriteAllText(file, "");

var resolved = RevealFile.Resolve(file);

await Assert.That(resolved!.Value.Target).IsEqualTo(file);
await Assert.That(resolved.Value.Select).IsTrue();
}

/// <summary>
/// Explorer opens the default folder when asked to select a path that is not there - Documents,
/// nothing to do with the review - and <c>open -R</c> errors. The directory the file is about
/// to be written into is the useful answer.
/// </summary>
[Test]
public async Task A_file_that_is_not_there_yet_falls_back_to_its_directory()
{
var resolved = RevealFile.Resolve(Path.Combine(directory, "new.verified.txt"));

await Assert.That(resolved!.Value.Target).IsEqualTo(directory);
await Assert.That(resolved.Value.Select).IsFalse();
}

[Test]
public async Task Nothing_is_opened_for_a_path_with_no_directory_either()
{
var missing = Path.Combine(directory, "gone", "new.verified.txt");

await Assert.That(RevealFile.Resolve(missing)).IsNull();
}

public RevealFileTests()
{
directory = Path.Combine(Path.GetTempPath(), $"RevealFileTests_{Guid.NewGuid()}");
Directory.CreateDirectory(directory);
}

public void Dispose() =>
Directory.Delete(directory, true);

readonly string directory;
}
46 changes: 42 additions & 4 deletions src/DiffEngineViewer/RevealFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@ static class RevealFile
{
public static void Show(string path)
{
if (Resolve(path) is not var (target, select))
{
return;
}

try
{
if (OperatingSystem.IsWindows())
{
Process.Start(new ProcessStartInfo("explorer.exe", $"/select,\"{path}\"")
var arguments = select ? $"/select,\"{target}\"" : $"\"{target}\"";
Process.Start(new ProcessStartInfo("explorer.exe", arguments)
{
UseShellExecute = true
});
Expand All @@ -20,16 +26,48 @@ public static void Show(string path)

if (OperatingSystem.IsMacOS())
{
Process.Start("open", ["-R", path]);
Process.Start("open", select ? ["-R", target] : [target]);
return;
}

// No cross-desktop way to select a file, so the directory is the target.
Process.Start("xdg-open", [Path.GetDirectoryName(path) ?? path]);
Process.Start("xdg-open", [select ? Path.GetDirectoryName(target) ?? target : target]);
}
catch (Exception exception)
{
Console.Error.WriteLine($"Could not open a file manager on {path}: {exception.Message}");
Console.Error.WriteLine($"Could not open a file manager on {target}: {exception.Message}");
}
}

/// <summary>
/// What to open, and whether the file manager can be asked to select it.
/// <para>
/// A path that is not there cannot be selected, and revealing a move used to hand one over
/// whenever the snapshot was new: the target of the move is where the file is going, not
/// somewhere it has been. Explorer answers that by opening the default folder - Documents,
/// nothing to do with the review - and <c>open -R</c> by erroring. Linux happened to work,
/// having only ever opened the directory.
/// </para>
/// <para>
/// So the directory is what is shown for a path that is not there yet, which is where the
/// file is about to be written. Null when even that is absent, since there is nothing useful
/// left to open.
/// </para>
/// </summary>
internal static (string Target, bool Select)? Resolve(string path)
{
if (File.Exists(path))
{
return (path, true);
}

var directory = Path.GetDirectoryName(path);
if (directory is {Length: > 0} &&
Directory.Exists(directory))
{
return (directory, false);
}

return null;
}
}
Loading