Guss
Guss

Reputation: 950

VsCode : How to generate custom task input options from a command?

Let's say we have the following custom task :

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "do smthg",
            "type": "shell",
            "command": "echo \"selected option: ${input:option_name}\"",
            "problemMatcher": [],
            "presentation": {
                "panel": "dedicated",
                "focus": true
            }
        }
    ],
    "inputs": [
        {
            "type": "pickString",
            "id": "option_name",
            "description": "select an option :",
            "options": [
                // want possible options to be the output of a command
            ],
            "default": ""
        }
    ]
}

But I want the available options to be the result of a command,
like ls, or a cat smthg.txt | grep -oP '\"value\:\"\K\w*',

how can I do that ? Is it only possible ?

Upvotes: 2

Views: 3249

Answers (2)

kyrlon
kyrlon

Reputation: 1316

This rough approach avoids the use of either a custom or external extension. The only presumption is that Python is already installed on the system. Using the python module json (assuming there are no comments in your task.json), a "pre-task" is made to modify the options key within the list for the inputs key in task.json. In this example, the "main task" will use echo in the terminal to say "Hi" to a chosen user from the updated input options after the "pre-task" runs. A directory has a set of folders that follow a naming scheme USER_[insert_username]:

.vscode/
├─ task.json
USER_CindycinErean
USER_Link/
USER_Mario/
USER_Ness/
USER_ShihTzu/

With python, the "pre-task" will scan the directory that matches this schema and update the options key as a list within inputs. The block below is how the code normally looks in a typical python script:

import json, os
base_folder = os.getcwd()
list_of_users = [f.name.split('_')[1] for f in os.scandir(base_folder) if (f.is_dir() and 'USER' in f.name)]
path = base_folder + r'\\.vscode\\tasks.json'
path = r'{}'.format(path)
j = open(path, 'r');ex = json.load(j)
j.close()
j = open(path, 'w');ex['inputs'][0]['options'] = list_of_users
ex['inputs'][0]['default'] = list_of_users[0]
json.dump(ex,j, indent=4);j.close()

And here is the code in a single line:

import json, os;base_folder = os.getcwd();list_of_users = [f.name.split('_')[1] for f in os.scandir(base_folder) if (f.is_dir() and 'USER' in f.name)];path = base_folder + r'\\.vscode\\tasks.json';path = r'{}'.format(path);j = open(path, 'r');ex = json.load(j);j.close();j = open(path, 'w');ex['inputs'][0]['options'] = list_of_users;ex['inputs'][0]['default'] = list_of_users[0];json.dump(ex,j, indent=4);j.close()

The "pre-task" is created using the single line code after double quotes have been escaped and the Python command argument (-c) has been used.

"command": "python3 -c \"import json, os;base_folder = os.getcwd();list_of_users = [f.name.split('_')[1] for f in os.scandir(base_folder) if (f.is_dir() and 'USER' in f.name)];path = base_folder + r'\\.vscode\\tasks.json';path = r'{}'.format(path);j = open(path, 'r');ex = json.load(j);j.close();j = open(path, 'w');ex['inputs'][0]['options'] = list_of_users;ex['inputs'][0]['default'] = list_of_users[0];json.dump(ex,j, indent=4);j.close()\""

Now with that defined, here is the before state of task.json for Windows, OSX, and Linux:

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Say Hi to selected user",
            "type": "shell",
            "dependsOn":["Update for User Selection"],
            "command": "echo Hi ${input:userSelect} !!!",
            "problemMatcher": []
        },
        {
            "label": "Update for User Selection",
            "type": "shell",
            "linux": {
                "options": {
                    "cwd": "${workspaceFolder}"
                },
                "command": "python3 -c \"import json, os;base_folder = os.getcwd();list_of_users = [f.name.split('_')[1] for f in os.scandir(base_folder) if (f.is_dir() and 'USER' in f.name)];path = base_folder + r'\\.vscode\\tasks.json';path = r'{}'.format(path);j = open(path, 'r');ex = json.load(j);j.close();j = open(path, 'w');ex['inputs'][0]['options'] = list_of_users;ex['inputs'][0]['default'] = list_of_users[0];json.dump(ex,j, indent=4);j.close()\""
            },
            "osx": {
                "options": {
                    "cwd": "${workspaceFolder}"
                },
                "command": "python3 -c \"import json, os;base_folder = os.getcwd();list_of_users = [f.name.split('_')[1] for f in os.scandir(base_folder) if (f.is_dir() and 'USER' in f.name)];path = base_folder + r'\\.vscode\\tasks.json';path = r'{}'.format(path);j = open(path, 'r');ex = json.load(j);j.close();j = open(path, 'w');ex['inputs'][0]['options'] = list_of_users;ex['inputs'][0]['default'] = list_of_users[0];json.dump(ex,j, indent=4);j.close()\""
            },
            "windows": {
                "options": {
                    "shell": {
                        "executable": "C:\\Windows\\system32\\cmd.exe",
                        "args": [
                            "/d",
                            "/c"
                        ]
                    },
                    "cwd": "${workspaceFolder}"
                },
                "command": "python -c \"import json, os;base_folder = os.getcwd();list_of_users = [f.name.split('_')[1] for f in os.scandir(base_folder) if (f.is_dir() and 'USER' in f.name)];path = base_folder + r'\\.vscode\\tasks.json';path = r'{}'.format(path);j = open(path, 'r');ex = json.load(j);j.close();j = open(path, 'w');ex['inputs'][0]['options'] = list_of_users;ex['inputs'][0]['default'] = list_of_users[0];json.dump(ex,j, indent=4);j.close()\""
            },
            "problemMatcher": []
        }
    ],
    "inputs": [
        {
            "type": "pickString",
            "id": "userSelect",
            "description": "Choose a user from the directory to say Hi to!",
            "options": [
                "UserA",
                "UserB",
                "UserC",
                "UserD"
            ],
            "default": "UserA"
        }
    ]
}

And this is the after state:

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Say Hi to selected user",
            "type": "shell",
            "dependsOn": [
                "Update for User Selection"
            ],
            "command": "echo Hi ${input:userSelect} !!!",
            "problemMatcher": []
        },
        {
            "label": "Update for User Selection",
            "type": "shell",
            "linux": {
                "options": {
                    "cwd": "${workspaceFolder}"
                },
                "command": "python3 -c \"import json, os;base_folder = os.getcwd();list_of_users = [f.name.split('_')[1] for f in os.scandir(base_folder) if (f.is_dir() and 'USER' in f.name)];path = base_folder + r'\\.vscode\\tasks.json';path = r'{}'.format(path);j = open(path, 'r');ex = json.load(j);j.close();j = open(path, 'w');ex['inputs'][0]['options'] = list_of_users;ex['inputs'][0]['default'] = list_of_users[0];json.dump(ex,j, indent=4);j.close()\""
            },
            "osx": {
                "options": {
                    "cwd": "${workspaceFolder}"
                },
                "command": "python3 -c \"import json, os;base_folder = os.getcwd();list_of_users = [f.name.split('_')[1] for f in os.scandir(base_folder) if (f.is_dir() and 'USER' in f.name)];path = base_folder + r'\\.vscode\\tasks.json';path = r'{}'.format(path);j = open(path, 'r');ex = json.load(j);j.close();j = open(path, 'w');ex['inputs'][0]['options'] = list_of_users;ex['inputs'][0]['default'] = list_of_users[0];json.dump(ex,j, indent=4);j.close()\""
            },
            "windows": {
                "options": {
                    "shell": {
                        "executable": "C:\\Windows\\system32\\cmd.exe",
                        "args": [
                            "/d",
                            "/c"
                        ]
                    },
                    "cwd": "${workspaceFolder}"
                },
                "command": "python -c \"import json, os;base_folder = os.getcwd();list_of_users = [f.name.split('_')[1] for f in os.scandir(base_folder) if (f.is_dir() and 'USER' in f.name)];path = base_folder + r'\\.vscode\\tasks.json';path = r'{}'.format(path);j = open(path, 'r');ex = json.load(j);j.close();j = open(path, 'w');ex['inputs'][0]['options'] = list_of_users;ex['inputs'][0]['default'] = list_of_users[0];json.dump(ex,j, indent=4);j.close()\""
            },
            "problemMatcher": []
        }
    ],
    "inputs": [
        {
            "type": "pickString",
            "id": "userSelect",
            "description": "Choose a user from the directory to say Hi to!",
            "options": [
                "CindycinErean",
                "Link",
                "Mario",
                "Ness",
                "ShihTzu"
            ],
            "default": "CindycinErean"
        }
    ]
}

Below is a demonstration of the task Update for User Selection being executed with the user Mario selected after changes to the task.json: enter image description here

Upvotes: 2

rioV8
rioV8

Reputation: 28763

You can use the extension Command Variable v1.34.0

Use the replacement for pickString named extension.commandvariable.pickStringRemember.

This command can read options from a file, you determine the format with a regexp like the problem matcher of tasks.

An example:

  "inputs": [
    {
      "type": "command",
      "id": "option_name",
      "command": "extension.commandvariable.pickStringRemember",
      "args": {
        "description": "select an option :",
        "options": [
          ["always 1", "5000"],
          ["always 2", "5100"]
        ],
        "default": "",
        "fileName": "${workspaceFolder}/foo-bar.txt",
        "pattern": {
          "regexp": "^\\s*(?!#)([^=]+?)\\s*=\\s*(?:(\\{.+\\})|(.+))$",
          "label": "$1",
          "json": "$2",
          "value": "$3"
        }
      }
    }
  ]

If you don't have label - value lines you can simplify the pattern to

        "pattern": {
          "regexp": "^\\s*(?!#)(.+)$"
        }

If you don't have static options (always 1/2 in example) you can remove the options property from args.

With an additional task you create the file with a command or a shell script if grep-ping and file redirection might be a problem (pass the output file name, using variables, as argument to the script).

You can construct a sequence of tasks, a compound task, see VSC doc.

Upvotes: 3

Related Questions