Multiple commands/tasks with Visual Studio Code

53,695

Solution 1

You can always use bash as your task runner and then assign arbitrary terminal commands as your tasks.

{
    "version": "0.1.0",
    "command": "bash",
    "isShellCommand": true,
    "showOutput": "always",
    "args": [
        "-c"
    ],
    "tasks": [
        {
            "taskName": "My First Command",
            "suppressTaskName": true,
            "isBuildCommand": true,
            "args": ["echo cmd1"]
        },
        {
            "taskName": "My Command Requiring .bash_profile",
            "suppressTaskName": true,
            "args": ["source ~/.bash_profile && echo cmd2"]
        },
        {
            "taskName": "My Python task",
            "suppressTaskName": true,
            "args": ["/usr/bin/python ${file}"]
        }
    ]
}

A few notes on what is happening here:

  • Using bash -c for all tasks by putting it in args list of the command so that we can run arbitrary commands. The echo statements are just examples but could be anything executable from your bash terminal.
  • The args array will contain a single string to be passed to bash -c (separate items would be treated as multiple arguments to the bash command and not the command associated with the -c arg).
  • suppressTaskName is being used to keep the taskName out of the mix
  • The second command shows how you can load your ~/.bash_profile if you need anything that it provides such as aliases, env variables, whatever
  • Third command shows how you could use your Python command you mentioned

This will not give you any sort of file extension detection, but you can at least use cmd+p then type "task " to get a list of your tasks. You can always mark your 2 most common commands with isBuildCommand and isTestCommand to run them via cmd+shift+b or cmd+shift+t respectively.

This answer has some helpful information that might be useful to you as well.

Solution 2

The simplest way would be to add them separated by ; (or &&) in a shell:

tasks.json:

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "test",
            "type": "shell",
            "command": "cd ~/dev/xxxx;source ~/dev/yyyy;ls",
        }
    ]
}

Solution 3

Recent changes to the tasks.json seem to have made a command available for each of the tasks listed. See https://code.visualstudio.com/docs/editor/tasks which makes a lot of this moot.


This answer was originally aimed at a more complex solution, but the simple shell runner task format as presented in the accepted answer proved more useful. See below for what that looks like now.


The limitation here is that VS Code is limited to a single high level build task/command for a given workspace. Multiple sub-tasks are allowed, but they are limited to using the top level "command" but can provide different "arguments". This would be well suited to an environment that uses a build system akin to make, ant or msbuild. E.g.;

{
    "version": "0.1.0",
    "command": "make", // command must appear here
    "tasks" : [
        {
            "taskName": "clean",
            "suppressTaskName": false, // false by default
            //"command": "somethingelse", // not valid here
            "args": ["${file}"] // if required
        },
        {
            "taskName": "install"
            // ...
        }
    ]
}

Two alternatives are available;

  • Have a custom script attempt to run the compile/execution solely given the arguments in task.json.

     -- the shell file would be a simple
     "$@" # run what I get
     -- the tasks.json
     "args": ["clang++", "-std=c++14", "-O2", "${file}"]
    

Getting the exectuable to run (./a.out) was more effort. Simply adding it as an argument didn't work, the shell script was required to execute it if it was there.

  • Shell out the switching and the execution of the output to a custom script, given the file extension and filename. This proved easier to implement and offered more control in the shell script.

     {
         "version": "0.1.0",
         "isShellCommand": true,
         "taskName": "generic build",
         "showOutput": "always",
         "args": ["${fileExtname}", "${file}"]
         "command": "./.vscode/compileme.sh", // expected in the "local settings" folder
         //"command": "~/compileme.sh", // if in HOME folder
     }
    

And the shell script, compileme.sh;

    #!/bin/sh
    # basic error checking not shown...
    echo "compilation being executed with the arguments;"
    echo "$@"
    filetype=$1
    file=$2
    if [ $filetype = ".cpp" -o $filetype = ".cxx" ] ; then 
        clang++ -std=c++14 -Wall -Wextra -pedantic -pthread $file && ./a.out
    elif [ $filetype = ".c" ]
        then 
        clang -std=c11 -Wall -Wextra -pedantic -pthread $file && ./a.out
    elif [ $filetype = ".sh" ]
        then
        $file
    elif [ $filetype = ".py" ]
        then
        python $file
    else
        echo "file type not supported..."
        exit 1
    fi

Given the options listed above, the second option is preferable. This implementation works on OS X, but it could be easily ported to Linux and Windows as needed. I'll keep on eye on this and try track changes to the VS Code build tasks, file based builds or support for multiple commands could be a welcome addition.


My tasks.json supports a few runners, and a default for the build that prints message as a reminder. It uses the shell as the runner and now looks like...

{
    "version": "0.1.0",
    "isShellCommand": true,
    "taskName": "GenericBuild",
    "showOutput": "always",
    "command": "sh",
    "suppressTaskName": false,
    "args": ["-c"],
    "tasks": [
        {
            "taskName": "no build",
            "suppressTaskName": true,
            "isBuildCommand": true,
            "args": [
                "echo There is no default build task, run a task by name..."
            ]
        },
        {
            "taskName": "cpp",
            "suppressTaskName": true,
            "args": [
                "clang++ -std=c++14 -Wall -Wextra -pedantic -pthread \"${file}\" && ./a.out"
            ]
        },
        {
            "taskName": "shell",
            "suppressTaskName": true,
            "args": [
                "\"${file}\""
            ]
        },
        {
            "taskName": "python",
            "suppressTaskName": true,
            "args": [
                "python \"${file}\""
            ]
        },
        {
            "taskName": "c",
            "suppressTaskName": true,
            "args": [
                "clang -std=c11 -Wall -Wextra -pedantic -pthread \"${file}\" && ./a.out"
            ]
        }
    ]
}

Solution 4

You can use compound tasks to run multiple commands https://code.visualstudio.com/docs/editor/tasks#_compound-tasks

Solution 5

You could write and run a custom script file instead of python etc. directly. In the script file you would extract the file extension in order to call python, clang or whatever the compiler/translator needed may be.

So your task file would look like this;

// A task runner that runs a program
{
   "version": "0.1.0",
   "command": "${workspaceRoot}\\runProgram.sh",
   "args": ["${file}"]
}
Share:
53,695
Niall
Author by

Niall

Software engineer, primarily involved in lower level, framework and systems development. Languages and technologies of interest and choice, C++ and node.js.

Updated on July 26, 2022

Comments

  • Niall
    Niall almost 2 years

    I have a local folder that I use as a scratch pad for multiple little sample and toy pieces of code. I store a host of python, C++, shell scripts etc. in this directory.

    I'm using Visual Studio Code (on OS X) and am looking into its tasks to run/compile the code snippets without having to switch to a terminal.

    For example, I found this following task will run python on the currently open file.

    // A task runner that runs a python program
    {
        "version": "0.1.0",
        "command": "/usr/bin/python",
        "args": ["${file}"]
    }
    

    This task will use python as the task runner irrespective of the type of file I'm currently editing.

    How do I implement a task to run a command based on the file type (or select between multiple commands)? I.e. if I'm editing a C++ file, it will run clang++.

    • If I can't do it based on file type; are there any alternatives to this?
    • An alternative would be; are multiple commands supported?
  • MrAlex6204
    MrAlex6204 over 8 years
    you can use CTRL+D to close the IDLE
  • Niall
    Niall over 8 years
    I've come back to this and I really like the idea of using bash -c as the command runner. This suits me quite nicely.
  • andrea
    andrea over 8 years
    I've created a variant of what you mention above to compile a simple C++ program. Unfortunately I cannot paste it in a comment. However what I notice is that the output of the task is not shown in the output pane. For example if my task executes "bash -c helloworld" there is no "Hello world" appearing in the output pane. Trying to figure out how to do that right now.
  • andrea
    andrea over 8 years
    And this is what I converged to: github.com/ataiya/hellovsc Notice for some reason I can see the computer/run output only when I do "echoCommand": false, which is particularly counter-intuitive! Also it's quite terrible you have no idea when the task has finished executing.
  • cesaraviles
    cesaraviles over 8 years
    I've not worked with echoCommand so not sure what the nuance is there. As for knowing when your task is complete, you can always concatenate && echo done to the end of your command. "args": ["g++ -v hello.cpp -o hello && echo done"]
  • wisbucky
    wisbucky over 2 years
    That works for a few short commands, but unfortunately, you cannot have multi-line strings in json, so you can't add line breaks for visual readability if there are many commands.
  • Nour
    Nour about 2 years
    why isn't this the accepted answer :)