enableOptionAsMetaForTerminal function

Future<String> enableOptionAsMetaForTerminal()

Enable Option as Meta key for Terminal.app.

Reads default and startup profiles, enables Option as Meta key and disables audio bell for both, then flushes the preferences cache.

Implementation

Future<String> enableOptionAsMetaForTerminal() async {
  try {
    // Create a backup of the current plist file.
    final plistPath = getTerminalPlistPath();
    final backupPath = '$plistPath.${_randomHex(4)}.bak';
    try {
      await File(plistPath).copy(backupPath);
    } catch (_) {
      throw Exception(
        'Failed to create backup of Terminal.app preferences, bailing out',
      );
    }

    // Read the current default profile.
    final defaultResult = await Process.run('defaults', [
      'read',
      'com.apple.Terminal',
      'Default Window Settings',
    ]);
    if (defaultResult.exitCode != 0 ||
        (defaultResult.stdout as String).trim().isEmpty) {
      throw Exception('Failed to read default Terminal.app profile');
    }

    final startupResult = await Process.run('defaults', [
      'read',
      'com.apple.Terminal',
      'Startup Window Settings',
    ]);
    if (startupResult.exitCode != 0 ||
        (startupResult.stdout as String).trim().isEmpty) {
      throw Exception('Failed to read startup Terminal.app profile');
    }

    bool wasAnyProfileUpdated = false;
    final defaultProfileName = (defaultResult.stdout as String).trim();

    final optionAsMetaEnabled = await enableOptionAsMetaForProfile(
      defaultProfileName,
    );
    final audioBellDisabled = await disableAudioBellForProfile(
      defaultProfileName,
    );
    if (optionAsMetaEnabled || audioBellDisabled) {
      wasAnyProfileUpdated = true;
    }

    final startupProfileName = (startupResult.stdout as String).trim();

    // Only proceed if the startup profile is different from default.
    if (startupProfileName != defaultProfileName) {
      final startupOptionEnabled = await enableOptionAsMetaForProfile(
        startupProfileName,
      );
      final startupBellDisabled = await disableAudioBellForProfile(
        startupProfileName,
      );
      if (startupOptionEnabled || startupBellDisabled) {
        wasAnyProfileUpdated = true;
      }
    }

    if (!wasAnyProfileUpdated) {
      throw Exception(
        'Failed to enable Option as Meta key or disable audio bell '
        'for any Terminal.app profile',
      );
    }

    // Flush the preferences cache.
    await Process.run('killall', ['cfprefsd']);

    return 'Configured Terminal.app settings:\n'
        '- Enabled "Use Option as Meta key"\n'
        '- Switched to visual bell\n'
        'Option+Enter will now enter a newline.\n'
        'You must restart Terminal.app for changes to take effect.\n';
  } catch (e) {
    throw Exception('Failed to enable Option as Meta key for Terminal.app: $e');
  }
}