© Alessandro Del Sole 2019
Alessandro Del SoleVisual Studio Code Distilledhttps://doi.org/10.1007/978-1-4842-4224-7_8

8. Automating Tasks

Alessandro Del Sole1 
(1)
Cremona, Italy
 
When talking about Visual Studio Code, you will often hear that it is not a simple code editor. This is certainly true, and the reason is that it allows executing operations such as compiling and testing code by running external tools. In this chapter you will learn how Code can execute external programs via tasks, by both learning about existing tasks and configuring custom tasks. In order to run the examples provided in this chapter, you will need the following software:
  • Node.js, a free and open source JavaScript runtime based upon Chrome’s JavaScript engine that can be downloaded from https://nodejs.org

  • The TypeScript compiler (tsc), which you install via the Node.js command line with the following command:

> npm install -g typescript

Using Node.js and TypeScript will help you to avoid dependencies on the operating system and proprietary development environments. Obviously, all the topics discussed in this chapter apply to other languages and platforms as well. For the last example about MSBuild tasks on Windows, you instead need Microsoft Visual Studio 2017. The Community edition is available for free at www.visualstudio.com .

Note

If you have worked with the first Visual Studio Code releases, it is important for you to know that the way tasks are handled has changed. If this is your case, you might want to read the migration guide for tasks written with older versions to the last version: https://code.visualstudio.com/docs/editor/tasks#_convert-from-010-to-200 .

Understanding Tasks

At its core, Visual Studio Code is a code-centric tool, so it often requires executing external programs to complete operations that are part of the application lifecycle, such as compilation, debugging, and testing.

In the Visual Studio Code terminology, integrating with an external program within the flow of the application lifecycle is a task. Running a task not only means executing an external program but also getting the output of the external program and displaying it in the most convenient way inside the user interface.

Note

Tasks are only available with folders, not individual code files.

A task is basically a set of instructions and properties represented with the JSON notation, stored in a special file called tasks.json. If VS Code is able to detect the type of project or source code inside the folder, a tasks.json file will not always be necessary, and VS Code will do all the job for you. If it cannot detect the type of project or source code, or if you are not satisfied with the default settings of a task, under the current folder, it generates a hidden subfolder called .vscode, and, inside this folder, it also generates a tasks.json file. If VS Code is able to detect the type of project or source code inside the folder, it will also prefill the tasks.json content with the proper information, otherwise you will need to configure tasks.json manually. For a better understanding, I will explain tasks that VS Code can detect and that it configures on your behalf, and then I will discuss how to create and configure tasks manually.

Tasks Types

There is no limit to how many types of tasks could be available for a source code folder, but the most common are the following:
  • Build task: A build task is configured to compile the source code, assets, metadata, and resources into a binary or executable file, such as libraries or programs.

  • Test task: A test task is configured to run unit tests in the source code.

  • Watch task: A watch task starts a compiler in the so-called watch mode. In this mode, a compiler always watches for changes to any unresolved files after the latest build and will recompile them at every save.

Visual Studio Code provides built-in shortcuts to execute a build task. When new tasks are added, VS Code updates itself to provide shortcuts for the new tasks. Additionally, you can differentiate tasks of the same type. For example, you can have a default build task and other custom build tasks that can be executed only with specific situations.

Running and Managing Tasks

The first approach to understanding tasks in practice is running existing, preconfigured tasks. For the sake of simplicity, start Visual Studio Code and open the project folder called simple from the collection of examples you downloaded previously from the TypeScript Samples repository on GitHub ( https://github.com/Microsoft/TypeScriptSamples ).

Visual Studio Code detects it as a TypeScript project, and therefore it will preconfigure some tasks (in the next section, I will provide more details about task auto-detection). Now open the Terminal menu. As you can see, there are several commands related to tasks, as you can see in Figure 8-1.
../images/474995_1_En_8_Chapter/474995_1_En_8_Fig1_HTML.jpg
Figure 8-1

Commands for running and managing tasks in the Terminal menu

An explanation of each command is provided in Table 8-1.
Table 8-1

Commands for Task Execution and Management

Command

Description

Run Task

Shows the list of available tasks in the Command Palette and runs the selected task.

Run Build Task

Runs the default, preconfigured build task (if any).

Terminate Task

Forces a task to be stopped.

Restart Running Task

Restarts the currently running task.

Show Running Task

Shows the output of the currently running task in the Terminal panel.

Configure Tasks

Shows the list of available tasks in the Command Palette and allows editing the selected task inside the tasks.json file editor.

Configure Default Build Task

Shows the list of available tasks in the Command Palette and allows selecting for the task that will be used as the build task.

If you select Run Task, VS Code will open the Command Palette showing the list of available tasks, as represented in Figure 8-2.
../images/474995_1_En_8_Chapter/474995_1_En_8_Fig2_HTML.jpg
Figure 8-2

Running a task from the Command Palette

As you can see, there are two tasks: tsc build and tsc watch, both pointing to the tsconfig.json project file. This means that either task will run against the specified file. tsc is the name of the command line TypeScript compiler, whereas build and watch are two preconfigured tasks whose description has been provided previously. If you select tsc build, Visual Studio Code will launch the tsc compiler and will compile the TypeScript code into JavaScript code, as shown in Figure 8-3.

Note

In the case of TypeScript, the build task will compile TypeScript code into JavaScript code. In the case of other languages, the build task will generate binaries from the source code. More generally, a build task will produce the expected output from the compilation process depending on the language. Also, the list of available tasks varies depending on the type of project or folder you are working with. For example, for .NET Core projects, only a task called build is available.

../images/474995_1_En_8_Chapter/474995_1_En_8_Fig3_HTML.jpg
Figure 8-3

Executing a build task

The Terminal panel shows the progress and result of the task execution. In this case, the result of the task is also represented by the generation of a .js file and a .js.map file, now visible in the Explorer bar. You can stop and restart a task using the Terminate Task and Restart Running Task commands, respectively, both described in Table 8-1. Now suppose there is a critical error that prevents the build task from completing successfully. For demonstration purposes, remove a closing bracket from the code of the simple.ts file and run again the build task. At this point, Visual Studio Code will show the detailed log from the tsc tool in the Terminal panel, as shown in Figure 8-4, describing the error and the line of code that caused it.
../images/474995_1_En_8_Chapter/474995_1_En_8_Fig4_HTML.jpg
Figure 8-4

Visual Studio Code shows the output of the external tool in a convenient way

In the real world, this error would not probably happen because you have the Problems panel and red squiggles in the code editor that both highlight the error. But this is actually an example of how Visual Studio Code integrates with an external tool and shows its output directly in the Terminal panel, helping to solve the problem with the most detailed information possible.

The Default Build Task

Because building the source code is the most frequently used task, Visual Studio Code provides a built-in shortcut to run this task in the Terminal menu, called Run Build Task (Ctrl+Shift+B on Windows and ⇧+⌘+B on macOS). However, you first need to set a default build task, otherwise the Run Build Task command will behave like the Run Task command.

To accomplish this, select TerminalConfigure Default Build Task. When the Command Palette appears, select the task you want to be set as the default build task, in this case select tsc build. When you do this, Visual Studio Code is actually changing its default configuration and therefore will generate a new tasks.json file under the .vscode folder, and it will open this file in a new editor window. The content and structure of tasks.json file will be discussed shortly in this chapter, so for now let’s focus on the new default build task. If you now select TerminalRun Build Task, or use the keyboard shortcut, you will see how the default build task will be executed, without the need of specifying it every time from the Command Palette.

Auto-Detected Tasks

Visual Studio Code can auto-detect tasks for the following environments: Grunt, Gulp, Jake, and Node.js. Auto-detecting tasks means that Visual Studio Code can analyze a project built for one of the aforementioned platforms and generate the appropriate tasks without the need of creating custom ones. Figure 8-5 shows an example based on the Node debugger extension for Visual Studio Code, whose source code is available at https://github.com/Microsoft/vscode-node-debug .
../images/474995_1_En_8_Chapter/474995_1_En_8_Fig5_HTML.jpg
Figure 8-5

Auto-detected tasks

The source code of this extension is made of JavaScript and TypeScript files and is built upon the Node.js runtime. So Visual Studio Code has been able to detect a number of tasks that work well with this kind of project, including tasks to run npm (the command line tool for Node.js) and the tsc TypeScript compiler.

Auto-detected tasks are very useful because they allow to save a lot of time in terms of task automation. However, more often than not, you will have needs that are not satisfied by existing tasks, so you will need to make your own customizations.

Note

In order to auto-detect tasks, behind the scenes VS Code requires that specific environments are installed. For example, VS Code can auto-detect tasks based on Node.js only if Node.js is installed; similarly, it can auto-detect tasks based on Gulp only if Gulp is installed and so on.

Configuring Tasks

When Visual Studio Code cannot auto-detect tasks for a folder, or when auto-detection does not satisfy your needs, you can create and configure custom tasks by editing the tasks.json file. In this section I will go through two examples that will help you understand how to configure your own tasks.

More specifically, I will explain how to compile Pascal source code files using the OmniPascal extension and the Free Pascal compiler, available to all operating systems, and how to build a Visual Studio solution based on the full .NET Framework on Windows by invoking the MSBuild.exe compiler.

In order to complete both the examples, you will need the following:
  • The OmniPascal language extension for Visual Studio Code, which you can download via the Extensions panel. This extension is useful to enable Pascal syntax highlighting and code navigation, though you can still compile source files without it.

  • The Free Pascal compiler, which includes all you need to develop applications using Pascal and that provides a free command line compiler. Free Pascal is available for Windows, macOS, Linux, and other systems, and it can be downloaded from www.freepascal.org .

  • On Windows only, download the latest version of the .NET Framework (4.7.2 at this writing), which includes the MSBuild.exe tool.

Let’s start with an example based on the Pascal language.

First Example: Compiling Pascal Source Code

In this section, I will explain how to create a custom task that allows for compiling Pascal source code files by invoking the Free Pascal command line compiler from VS Code. Assuming you have downloaded and installed the required software as listed in the preceding text, locate the Free Pascal folder installation on disk (usually /FPC/version number), then open the examples folder. In Visual Studio Code, open any folder containing some Pascal source code. I will use one called fcl-json.

Figure 8-6 shows how Visual Studio Code appears with Pascal source files currently opened.
../images/474995_1_En_8_Chapter/474995_1_En_8_Fig6_HTML.jpg
Figure 8-6

Editing Pascal source code

The OmniPascal extension installed previously enables syntax colorization and the other common editing features. Now imagine you want to compile the source code into an executable binary by invoking the Free Pascal command line compiler. This can be accomplished by creating a custom task. Follow these steps to create a new tasks.json file and set up the custom task:
  1. 1.

    Select TerminalConfigure Task: When the Command Palette appears asking for a task to configure, select Create tasks.json from template (see Figure 8-7). There is no existing task to configure at this particular point, so the only thing you can do is creating a new tasks.json file.

     
  2. 2.

    The Command Palette will now show the list of available task templates: MSBuild, maven, .NET Core, and Others (see Figure 8-8). Select Others to create a new task that is independent from other systems.

     
../images/474995_1_En_8_Chapter/474995_1_En_8_Fig7_HTML.jpg
Figure 8-7

Creating a new task from scratch

../images/474995_1_En_8_Chapter/474995_1_En_8_Fig8_HTML.jpg
Figure 8-8

Selecting a task template

Visual Studio Code generates a subfolder called .vscode and, inside this folder, a new tasks.json file whose content at this point is the following:
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "echo",
            "type": "shell",
            "command": "echo Hello"
        }
    ]
}
The core node of this JSON file is an array called tasks. It contains a list of tasks, and for each tasks, you can specify the text that VS Code will use to display it in the Command Palette (label), the type of task (type), and the external program that will be executed (command). An additional JSON property called args allows for specifying command line arguments for the program you invoke. The list of supported JSON properties is available in Table 8-2 and will be discussed later in this chapter, but if you are impatient, you can quickly look at the table and then get back here. Now suppose you want to create a build task which, by convention, is the type of task you use to compile source code. This can be accomplished by modifying tasks.json as follows:
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "command": "fpc",
            "args": ["${file}"]
        }
    ]
}
The key points are the following:
  • The label property value is now build so that the task is clearly provided as the build task.

  • The type property value is shell, meaning it will be executed by the operating system’s shell.

  • The command property value is fpc, which is the file name of the Free Pascal compiler.

  • The args property value is an array of command line arguments to be passed to the external program; in this case there is only one argument that is the active source file, represented by the $(file) variable.

Note

As a general rule, an external program can be invoked without specifying its full path only if such a path has been registered in the operating system’s environment variables, such as PATH on Windows. In the case of Free Pascal, the installer takes care of registering the program’s path, but remember to have a look at the environment variables for other programs.

You could certainly specify the name of the file you want to compile, but using a variable is more flexible so that you can simply compile any file that is currently active in the code editor. In addition to the properties in tasks.json, variables are also discussed shortly and will be summarized in Table 8-3. Notice how IntelliSense helps you find the appropriate properties in tasks.json, as shown in Figure 8-9.
../images/474995_1_En_8_Chapter/474995_1_En_8_Fig9_HTML.jpg
Figure 8-9

IntelliSense helps defining tasks properties

Save and close tasks.json, then open one of the Pascal source files. Now you can run the newly created build task. Select TerminalRun Task, and from the Command Palette, select the build task (see Figure 8-10).
../images/474995_1_En_8_Chapter/474995_1_En_8_Fig10_HTML.jpg
Figure 8-10

Selecting the new task

At this point, VS Code will ask you what would you like to do to detect any problems encountered during the execution of the external program so that they can be displayed in the Problems panel. Detecting problems in the program’s output is the job of a so-called problem matcher. This is a more complex topic and will be discussed in a dedicated section. For now, select Continue without scanning the task output (see Figure 8-11).
../images/474995_1_En_8_Chapter/474995_1_En_8_Fig11_HTML.jpg
Figure 8-11

Selecting a problem matcher

The Free Pascal compiler will be executed in the Terminal panel, where you also see the program output as demonstrated in Figure 8-12.
../images/474995_1_En_8_Chapter/474995_1_En_8_Fig12_HTML.jpg
Figure 8-12

Executing the Free Pascal compiler

If the execution succeeds, you will find a new binary file in the source code’s folder. If it fails, the compiler’s output displayed in the Terminal panel will help you understand what the problem was. Before moving to a second example, I will now explain more about default tasks, task templates, JSON properties in tasks.json, and variables.

Multiple Tasks and Default Build Tasks

Tasks.json can define multiple tasks. At the beginning of this chapter, I told you that, among the others, common tasks are build and test, but you might want to implement multiple tasks that are specific to your scenario. For example, suppose you want to use the Free Pascal compiler to build Delphi source code files.

The Free Pascal command line compiler provides the -Mdelphi option, which enables compilation based on the Delphi compatibility mode. You can therefore modify tasks.json as follows:
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "command": "fpc",
            "args": ["${file}"]
        },
        {
            "label": "Delphi build",
            "type": "shell",
            "command": "fpc",
            "args": ["${file}", "-Mdelphi"]
        }
    ]
}
As you can see, there is a new custom task called Delphi build in the tasks array which still invokes the Free Pascal compiler on the active file, but with the -Mdelphi option being passed as a command line argument. Now if you select TerminalRun Task again, you will see both tasks in the Command Palette, as demonstrated in Figure 8-13.
../images/474995_1_En_8_Chapter/474995_1_En_8_Fig13_HTML.jpg
Figure 8-13

All defined tasks are displayed in the Command Palette

It is common to have multiple build tasks, and even multiple tasks of the same type, but in most cases, you will usually run the same task and keep other tasks for very specific situations. Related to the current example, you will usually build Pascal source files and sometimes build Delphi source files, so a convenient choice is configuring a default build task for Pascal files. As you learned in the “The Default Build Task” section previously, this can be easily accomplished with the following steps:
  1. 1.

    Select TerminalConfigure Default Build Task.

     
  2. 2.

    In the Command Palette, select the build task defined previously.

     
  3. 3.

    With a Pascal source file active, select TerminalRun Build Task, or press the keyboard shortcut for your system.

     

This command will automatically start the default build task, without the need of manually selecting a task every time.

Understanding tasks.json Properties and Substitution Variables

There are a number of properties available to customize a task. Table 8-2 provides a summary of common properties you use with custom tasks.
Table 8-2

Available Properties for Task Customization

Property Name

Description

label

A string used to identify the task (e.g., in the Command Palette).

type

Represents the task type. For custom tasks, supported values are shell and process. With shell, the command is interpreted as a shell command (such as bash, cmd, or PowerShell). With process, the command is interpreted as a process to be executed.

command

The command or external program to be executed.

args

An array of command line arguments to be passed to the command.

windows

Allows specifying task properties that are specific to the Windows operating system.

Osx

Allows specifying task properties that are specific to macOS.

Linux

Allows specifying task properties that are specific to Linux and its distributions.

Group

Allows for defining task groups and for specifying to which group a task belongs to.

Presentation

Defines how Visual Studio Code handles the task output in the user interface (see the following example).

Options

Allows for providing custom values about the cwd (current working directory), env (environment variables), and shell (default shell) options.

The windows, osx, and linux properties will be discussed separately in the next section. The group property allows grouping tasks by category. For instance, if you consider the two multiple tasks created previously, they are both related to building code, so they might be grouped into a category called build. This is accomplished by modifying tasks.json as follows:
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "args": ["${file}"],
            "group": "build",
        },
        {
            "label": "Delphi build",
            "type": "shell",
            "command": "fpc",
            "args": ["${file}", "-Mdelphi"],
            "group": "build"
        }
    ]
}
Notice how IntelliSense shows the built-in supported values for the group property (see Figure 8-14).
../images/474995_1_En_8_Chapter/474995_1_En_8_Fig14_HTML.jpg
Figure 8-14

IntelliSense helping with groups

Notice how you can also specify additional values to individual tasks in a group. For example, if you want to set a task as the default one in the group, you might change the JSON as follows:
"group": {
     "kind": "build",
     "isDefault": true
  }
}
The kind property represents the group name and isDefault is self-explanatory. You can also customize the way VS Code handles the task output via the presentation property. When you type presentation and then press Enter, IntelliSense adds a number of key/value pairs with some default values, as follows:
"presentation": {
    "echo": true,
    "reveal": "always",
    "focus": false,
    "panel": "shared",
    "showReuseMessage": true
}
Following is the description of each key and its values:
  • echo can be true or false and specifies whether the task output is actually written to the Terminal panel.

  • reveal can be always, never, or silent and specifies whether the Terminal panel where the task is running should be always visible, never visible, or visible only when a problem matcher is not specified and some errors occur.

  • focus can be true or false and specifies if the Terminal panel should get focused when the task is running.

  • panel can be shared, dedicated, or new, and it specifies if the terminal instance is shared across tasks or if an instance must be dedicated to the current task or if a new instance should be created at every task run.

  • showReuseMessage can be true or false and specifies whether a message should be displayed to inform that the Terminal panel will be reused by a task and that therefore it is possible to close it.

The values you see in the preceding snippet are the default values. In case of default values, a key can be omitted. For example, the following markup demonstrates how to create a new Terminal panel at every run without showing a reuse message:
"presentation": {
    "panel": "new",
    "showReuseMessage": false
}

Other values can be omitted because we are okay with the default values seen in the preceding text.

Note

The list of supported properties is much longer, but most of them are not of common use. If you want to get deeper knowledge about the full list of available properties, you can look at the tasks.json schema, which provides detailed comments about each property and that is available at https://code.visualstudio.com/docs/editor/tasks-appendix .

Visual Studio Code also offers several predefined variables that you can use instead of regular strings and that are useful to represent file and folder names when passing these to a command. Table 8-3 provides a summary of supported variables.
Table 8-3

Supported Substitution Variables

Variable

Description

${workspaceFolder}

Represents the path of the currently opened folder.

${workSpaceFolderBasename}

Represents the path of the currently opened folder without any slashes.

${file}

The active code file.

${relativeFile}

The active code file relative to ${workspaceFolder}.

${fileBaseName}

The active code file’s base name.

${fileBaseNameNoExtension}

The active code file’s base name without the extension.

${fileDirname}

The name of the directory that contains the active code file.

${fileExtname}

The file extension of the active code file.

${cwd}

The current working directory of the task.

${lineNumber}

The currently selected line number in the active file.

${selectedText}

The currently selected text in the active file.

${env.VARIABLENAME}

References an environment variable, such as {$env.PATH}.

Using variables is very common when you run a task that works at the project/folder level or against file names that you either cannot predict or that you do not want to hardcode. You can check the variables documentation for further details at https://code.visualstudio.com/docs/editor/variables-reference .

Operating System-Specific Properties

Sometimes you might need to provide task property values that are different based on the operating system. In Visual Studio Code, you can use the windows, osx, and linux properties to specify different values of a property, depending on the target.

For example, the following tasks.json implementation shows how to explicitly specify the path of an external tool for Windows and Linux (the directory names might not be the same on your machine):
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "args": ["${file}"],
            "windows": {
                "command": "C:\Program Files\FPC\fpc.exe"
            },
            "linux": {
                "command": "/usr/bin/fpc"
            }
        }
    ]
}

More specifically, you will need to move the property of your interest under the operating system property and provide the desired value. In the preceding code, the command property has been moved from the higher level down to the windows and linux property nodes. All supported properties can have different values, not only command.

Reusing Existing Task Templates

In the previous example about compiling Pascal source code, you have seen how to create a custom task from scratch. However, for some particular scenarios, you can leverage existing task templates, which consists of tasks.json files already preconfigured to work with specific command and settings.

The list of task templates may vary depending on the extensions you have installed, but assuming you have installed only the C# extension, your list should look like in Figure 8-8. The first template is called MSBuild and generates the following tasks.json file:
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "command": "msbuild",
            "args": [
                // Ask msbuild to generate full paths for file names.
                "/property:GenerateFullPaths=true",
                "/t:build"
            ],
            "group": "build",
            "presentation": {
                // Reveal the output only if unrecognized errors occur.
                "reveal": "silent"
            },
            // Use the standard MS compiler pattern to detect errors, warnings and infos
            "problemMatcher": "$msCompile"
        }
    ]
}

This template is very useful if you want to work with Microsoft Visual Studio solutions inside VS Code, and a more specific example is coming in the next subsection. It is worth mentioning that this template has been included thinking about C# solutions (such as web applications and Xamarin projects), but MSBuild can build any kind of solution so it can be reused for different purposes.

The second template is called Maven and is tailored to work with the same-named build automation tool for Java. Such a template generates the following tasks.json file:
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "verify",
            "type": "shell",
            "command": "mvn -B verify",
            "group": "build"
        },
        {
            "label": "test",
            "type": "shell",
            "command": "mvn -B test",
            "group": "test"
        }
    ]
}
Obviously, Maven must be installed on your machine (you can find it at https://maven.apache.org ). The third template is called .NET Core and, as the name implies, it generates a tasks.json file which is tailored to automate the build of .NET Core projects. The configuration looks like the following:
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "command": "dotnet build",
            "type": "shell",
            "group": "build",
            "presentation": {
                "reveal": "silent"
            },
            "problemMatcher": "$msCompile"
        }
    ]
}
In this case, the command is not MSBuild; instead it is dotnet. These templates are useful for at least two reasons:
  • They provide ready-to-use configurations for projects of the targeted type, where you might need only a few adjustments.

  • They provide a complete task structure, where you only need to replace the command and target and optionally the presentation and the problem matcher.

You will now see an example based on the MSBuild task template.

Second Example: Building a MSBuild Solution (Windows Only)

MSBuild has been the Microsoft build engine since the very first release of the .NET Framework back in 2002. It is a very powerful tool, because it can build a Visual Studio solution with no effort. So, a very nice to have feature would be the possibility of compiling your solutions and projects inside Visual Studio Code.

You can configure a task to run MSBuild.exe, the build engine used by Visual Studio. In the next example, you will see how to compile an MSBuild solution made of a Visual Basic project based on Windows Presentation Foundation (WPF), but of course all the steps apply to any .sln file and to any supported languages. If you do not have one, in Visual Studio 2017 create a blank WPF project with Visual Basic as the language. There’s no need of writing code, as I focus on the project type. Save the project, then open the project folder in VS Code.

Before configuring a task, it is worth mentioning that, by default, the MSBuild path is not registered in the Windows’ environment variables, so you have two possible alternatives:
  • Add the MSBuild directory to the PATH environment variable via Control PanelSystemAdvanced system settingsEnvironment Variables.

  • Specify the full MSBuild pathname in tasks.json. This is the quickest option and the one I will use.

Select TerminalConfigure Task. Select the MSBuild template from the list of templates. When tasks.json has been created, change the value of the command property as follows, also replacing Enterprise with the name of the Visual Studio edition you have on your machine, for example:
"command": "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\msbuild"
Also, change the value of the reveal property from never to always for demonstration purposes, so that you can see the output of MSBuild in the Terminal panel. Now if you select TerminalRun Task and select the preconfigured build task, MSBuild will be started and the solution will be built, as you can see in Figure 8-15.
../images/474995_1_En_8_Chapter/474995_1_En_8_Fig15_HTML.jpg
Figure 8-15

Compiling a WPF project written in Visual Basic with the MSBuild task

The preconfigured MSBuild task uses the $msCompile problem matcher to detect problems related to C# and Visual Basic in the build output, so that they can be presented in a convenient way in the user interface. Let’s spend some more words about problem matchers.

Understanding Problem Matchers

Problem matchers scan the task output text for known warning or error strings and report these inline in the editor and in the Problems panel. Visual Studio Code ships with a number of built-in problem matchers for TypeScript, JSHint, ESLint, Go, C# and Visual Basic, Lessc, and Node Sass (see https://code.visualstudio.com/docs/editor/tasks#_processing-task-output-with-problem-matchers ).

Built-in problem matchers are extremely useful, because for the aforementioned environments, VS Code can present problems that occurred at build time in the Problems panel, but it can also highlight the line of code in the code editor that caused the problem.

You can also define custom problem matchers to scan the output of an external program. For instance, a problem matcher for scanning the Free Pascal compiler could look like the following:
            "problemMatcher": {
                "owner": "external",
                "fileLocation": ["relative", "${workspaceRoot}"],
                "pattern": {
                    "regexp": "((([A-Za-z]):\\(?:[^\/:*?\"<>|\r\n]+\\)*)?[^\/\s\(:*?\"<>|\r\n]*)\((\d+)\):\s.*(fatal|error|warning|hint)\s(.*):\s(.*)",
        // The first match group matches the file name which is relative.
        "file": 1,
        // The second match group matches the line on which the problem occurred.
        "line": 2,
        // The third match group matches the column at which the problem occurred.
        "column": 3,
        // The fourth match group matches the problem's severity. Can be ignored. Then all problems are captured as errors.
        "severity": 4,
        // The fifth match group matches the message.
        "message": 5
                }

The owner property represents the language service, which is external in this case, but it could be, for example, cpp in the case of a C++ project. But the most important property is pattern, where you specify a regular expression (regexp) to match error strings sent by the external program. Also notice, with the help of comments, how matches are grouped by target. Building problem matchers can be tricky and it is out of the scope of this book, so I recommend you to read the official documentation available at https://code.visualstudio.com/docs/editor/tasks#_processing-task-output-with-problem-matchers .

Running Files with a Default Program

In case you are editing in VS Code a file whose type is associated with the operating system, you do not need to create custom tasks to run it. For example, a batch program (.bat) in Windows or a shell script file (.sh) on macOS can be run by simply clicking Terminal ➤ Run Active File.

The file name will be passed to the current terminal program on your system (PowerShell on Windows or the bash on Linux and macOS) so that the operating system will try to open the file with the program that is registered with the file extension, if any. In the case of a batch or shell script file, the operating system will execute the file. The output will be displayed in the Terminal panel.

Note

Only the output of the operating system or of command line tools will be redirected to the Terminal panel. For instance, if you try to edit a .txt file and then select Terminal ➤ Run Active File, such a file will be opened inside the default text editor on your system, and there will be no additional interactions with the Terminal panel.

Summary

There are many features in Visual Studio Code that make it different from a simple code editor. Tasks are among these features. With tasks you can attach external programs to the application lifecycle and run tools like compilers. VS Code ships with task auto-detection for some environments, but it allows for creating custom tasks when you need to associate specific tools to a project or folder.

By working on the tasks.json file and with the help of IntelliSense, you will be able to include the execution of any external program in your folders. The execution of external programs like compilers is certainly useful, but it would not be so important if VS Code could not make a step forward: debugging code, which is discussed in the next chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.133.96