using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace OpenNest.Desktop;
///
/// Opens a file in the program the system associates with its type: Plate > View in CAD's
/// DXF, View Nest Report's PDF. Windows opens it through the shell, macOS through
/// open and Linux and other Unix desktops through xdg-open.
///
public static class ExternalFileLauncher
{
/// The start info that opens on the running platform.
public static ProcessStartInfo StartInfo(string path) => StartInfo(path, CurrentPlatform());
/// The start info that opens on .
public static ProcessStartInfo StartInfo(string path, OSPlatform platform)
{
ArgumentException.ThrowIfNullOrWhiteSpace(path);
// .NET defaults UseShellExecute to false, which would try to run the file itself as a
// program; the shell opens it in the associated program instead.
if (platform == OSPlatform.Windows)
return new ProcessStartInfo(path) { UseShellExecute = true };
var info = new ProcessStartInfo(platform == OSPlatform.OSX ? "open" : "xdg-open")
{
UseShellExecute = false,
};
// An argument, never a shell command line: spaces and quotes in the path stay literal.
info.ArgumentList.Add(path);
return info;
}
/// Opens in its associated program; throws when it cannot start.
public static void Open(string path)
{
using var process = Process.Start(StartInfo(path));
}
///
/// Opens and, where an opener program reports the result
/// (xdg-open, open), waits for it without blocking and returns why it failed,
/// or null once it opened. The Windows shell reports a failure by throwing instead. Throws
/// when the opener cannot start.
///
public static async Task OpenAsync(string path)
{
var info = StartInfo(path);
using var process = Process.Start(info);
if (info.UseShellExecute || process == null)
return null;
await process.WaitForExitAsync().ConfigureAwait(false);
return FailureMessage(process.ExitCode, path);
}
///
/// What an xdg-open or open exit code means for , or
/// null for success (0).
///
public static string FailureMessage(int exitCode, string path) => exitCode switch
{
0 => null,
2 => $"'{path}' was not found.",
3 => $"No program is set up to open '{System.IO.Path.GetFileName(path)}'.",
_ => $"The system could not open '{path}' (exit code {exitCode}).",
};
private static OSPlatform CurrentPlatform() =>
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? OSPlatform.Windows
: RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? OSPlatform.OSX
: OSPlatform.Linux;
}