gonuit / rps

Define and use scripts from your pubspec.yaml file.
MIT License
41 stars 7 forks source link

Feature Suggestion: Interactive Mode for Running Commands #22

Open shtse8 opened 1 month ago

shtse8 commented 1 month ago

Description

It would be beneficial to introduce an interactive mode to the RPS script manager, allowing users to select and run scripts interactively. This mode would display a list of available scripts, and users could navigate through them using arrow keys. Once a script is selected, the user can input any additional arguments required before executing the script.

Example Flow:

  1. The user runs the command rps.
  2. RPS displays a list of available scripts:
    Which scripts do you want to run?
    1) build
    2) compile
    3) format
  3. The user navigates using the arrow keys and selects the desired script.
  4. If needed, RPS prompts the user to input additional arguments.
  5. The selected script runs with the provided arguments.

Benefits

Implementation Notes:

shtse8 commented 1 month ago

Here's a draft implementation focusing solely on the interactive mode. This draft assumes that the script running part of the project is already in place. The interactive mode allows users to select and run scripts defined in the pubspec.yaml file interactively, with support for nested script selection and predefined arguments.

Key Implementation

  1. Load and Parse pubspec.yaml:

    • Load the pubspec.yaml file and parse the scripts section.
  2. Interactive Mode:

    • Display Top-Level Scripts: Present a list of top-level scripts using the console.
    • Nested Selection: Allow users to navigate into nested scripts, making selections one level at a time.
    • Handle Predefined Args: If a script has predefined arguments, display them for selection. Users can also input custom arguments if none are predefined.
    • Execute the Script: The selected script and arguments are passed to the existing execution logic.

Here’s a draft implementation of the interactive mode:

void runInteractiveMode(Map scripts) {
  var currentScripts = scripts;

  while (true) {
    final selectedScriptKey = _selectScript(currentScripts);
    if (selectedScriptKey == null) {
      print('No valid selection. Exiting...');
      break;
    }

    final selectedScript = currentScripts[selectedScriptKey];

    if (selectedScript is Map) {
      currentScripts = selectedScript; // Enter the nested scripts
    } else if (selectedScript is String) {
      final predefinedArgs = _getPredefinedArgs(selectedScriptKey);
      final userArgs = _promptForArgs(predefinedArgs);

      // Pass selectedScript and userArgs to the existing execution function
      executeScript(selectedScript, userArgs);
      break; // Exit after running the script
    }
  }
}

String? _selectScript(Map scripts) {
  print('Select a script to run:');
  final scriptKeys = scripts.keys.toList();

  for (var i = 0; i < scriptKeys.length; i++) {
    print('${i + 1}) ${scriptKeys[i]}');
  }

  // Use arrow keys for selection or type the number
  final choice = _getUserChoice(scriptKeys.length);
  if (choice == null) {
    return null;
  }

  return scriptKeys[choice - 1];
}

List<String>? _getPredefinedArgs(String scriptKey) {
  // Retrieve predefined arguments for the selected script from pubspec.yaml
  // Return a list of arguments or null if none are predefined
}

String _promptForArgs(List<String>? predefinedArgs) {
  if (predefinedArgs != null && predefinedArgs.isNotEmpty) {
    print('Select or customize arguments:');
    for (var i = 0; i < predefinedArgs.length; i++) {
      print('${i + 1}) ${predefinedArgs[i]}');
    }

    final choice = _getUserChoice(predefinedArgs.length);
    return predefinedArgs[choice - 1];
  }

  print('Enter any additional arguments:');
  return stdin.readLineSync() ?? '';
}

int? _getUserChoice(int max) {
  final input = stdin.readLineSync();
  final choice = int.tryParse(input ?? '');
  if (choice != null && choice > 0 && choice <= max) {
    return choice;
  }
  return null;
}

Key Features:

This implementation focuses on a user-friendly, nested interactive mode, allowing for easy navigation and selection of scripts. It should integrate seamlessly with the existing script execution logic.

Looking forward to your feedback!