/// <summary>
        /// Creates a copy of <paramref name="profile"/> in which tokens are replaced via <paramref name="replaceAsync"/>.
        /// </summary>
        /// <remarks>
        /// Intended to replace tokens such as environment variables and MSBuild properties.
        /// </remarks>
        /// <param name="profile">The source profile to copy from.</param>
        /// <param name="replaceAsync">A function that performs token substitution.</param>
        /// <returns>A profile with tokens substituted.</returns>
        internal static async Task <LaunchProfile> ReplaceTokensAsync(ILaunchProfile profile, Func <string, Task <string> > replaceAsync)
        {
            return(new(
                       name : profile.Name,
                       commandName : profile.CommandName,
                       executablePath : await ReplaceOrNullAsync(profile.ExecutablePath),
                       commandLineArgs : await ReplaceOrNullAsync(profile.CommandLineArgs),
                       workingDirectory : await ReplaceOrNullAsync(profile.WorkingDirectory),
                       launchBrowser : profile.LaunchBrowser,
                       launchUrl : await ReplaceOrNullAsync(profile.LaunchUrl),
                       doNotPersist : profile.IsInMemoryObject(),
                       environmentVariables : await GetEnvironmentVariablesAsync(),
                       otherSettings : await GetOtherSettingsAsync()));

            Task <string?> ReplaceOrNullAsync(string?s)
            {
                if (Strings.IsNullOrWhiteSpace(s))
                {
                    return(TaskResult.Null <string>());
                }

                return(replaceAsync(s) !);
            }

            Task <ImmutableArray <(string Key, string Value)> > GetEnvironmentVariablesAsync()
            {
                return(profile switch
                {
                    ILaunchProfile2 profile2 => ReplaceValuesAsync(profile2.EnvironmentVariables, replaceAsync),
                    _ => ReplaceValuesAsync(profile.FlattenEnvironmentVariables(), replaceAsync)
                });
        public static LaunchProfile Clone(ILaunchProfile profile)
        {
            // LaunchProfile is immutable and doesn't need to be cloned.
            if (profile is LaunchProfile lp)
            {
                return(lp);
            }

            // Unknown implementation. Make a defensive copy to a new immutable instance.
            return(new LaunchProfile(
                       name: profile.Name,
                       executablePath: profile.ExecutablePath,
                       commandName: profile.CommandName,
                       commandLineArgs: profile.CommandLineArgs,
                       workingDirectory: profile.WorkingDirectory,
                       launchBrowser: profile.LaunchBrowser,
                       launchUrl: profile.LaunchUrl,
                       environmentVariables: profile.FlattenEnvironmentVariables(),
                       otherSettings: profile.FlattenOtherSettings(),
                       doNotPersist: profile.IsInMemoryObject()));
        }