├── .eslintrc.json
├── .gitignore
├── .vscode
├── launch.json
└── tasks.json
├── .vscodeignore
├── LICENSE.md
├── README.md
├── ReleaseNotes.md
├── images
├── demo_debug.gif
├── icon.png
├── icon_black.svg
├── icon_black_empty.svg
├── icon_full.svg
├── icon_small.png
├── screenshot.png
└── test_codelens_screenshot.png
├── package-lock.json
├── package.json
├── releases
├── bluebazel-0.0.1.vsix
├── bluebazel-0.0.2.vsix
├── bluebazel-0.0.3.vsix
├── bluebazel-0.0.4.vsix
├── bluebazel-0.0.5.vsix
├── bluebazel-1.0.0.vsix
├── bluebazel-1.0.1.vsix
├── bluebazel-1.0.2.vsix
├── bluebazel-1.0.3.vsix
├── bluebazel-1.0.4.vsix
├── bluebazel-1.0.5.vsix
└── bluebazel-1.0.6.vsix
├── src
├── controllers
│ ├── bazel-controller.ts
│ ├── bazel-target-operations-controller.ts
│ ├── command-controller.ts
│ ├── commands
│ │ ├── bazel-commands.ts
│ │ ├── bazel-target-operations-commands.ts
│ │ ├── debug-commands.ts
│ │ ├── multi-prop-tree-item-commands.ts
│ │ ├── single-prop-tree-item-commands.ts
│ │ ├── tree-data-provider-commands.ts
│ │ └── user-commands.ts
│ ├── target-controllers
│ │ ├── any-action-controller.ts
│ │ ├── bazel-target-controller-manager.ts
│ │ ├── bazel-target-controller.ts
│ │ ├── build-controller.ts
│ │ ├── debug-controller.ts
│ │ ├── run-controller.ts
│ │ └── test-controller.ts
│ ├── user-commands-controller.ts
│ └── workspace-events-controller.ts
├── extension.ts
├── languages
│ ├── language-plugin.ts
│ ├── language-registry.ts
│ └── plugins
│ │ ├── cpp-language-plugin.ts
│ │ ├── go-language-plugin.ts
│ │ └── python-language-plugin.ts
├── models
│ ├── bazel-action-manager.ts
│ ├── bazel-environment.ts
│ ├── bazel-target-manager.ts
│ ├── bazel-target-multi-property.ts
│ ├── bazel-target-property-history.ts
│ ├── bazel-target-property.ts
│ ├── bazel-target-state-manager.ts
│ ├── bazel-target.ts
│ ├── model-accessor.ts
│ ├── model.ts
│ └── workspace-state-manager.ts
├── services
│ ├── bazel-parser.ts
│ ├── bazel-rule-language-mapping.ts
│ ├── bazel-service.ts
│ ├── configuration-manager.ts
│ ├── configuration-utils.ts
│ ├── console.ts
│ ├── env-vars-utils.ts
│ ├── environment-service.ts
│ ├── extension-utils.ts
│ ├── file-storage-service.ts
│ ├── file-watcher-service.ts
│ ├── icon-service.ts
│ ├── network-utils.ts
│ ├── shell-service.ts
│ ├── string-utils.ts
│ ├── task-service.ts
│ └── workspace-service.ts
├── test
│ ├── runTest.ts
│ └── suite
│ │ ├── extension.test.ts
│ │ ├── index.ts
│ │ └── services
│ │ ├── bazel-parser.test.ts
│ │ └── bazel-service.test.ts
└── ui
│ ├── bazel-target-quick-pick-item.ts
│ ├── bazel-target-quick-pick.ts
│ ├── bazel-target-tree-provider.ts
│ ├── code-lens-provider-utils.ts
│ ├── code-lens-providers
│ └── unified-code-lens-provider.ts
│ ├── progress.ts
│ ├── quick-pick.ts
│ └── terminal.ts
└── tsconfig.json
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es2021": true
5 | },
6 | "extends": [
7 | "eslint:recommended",
8 | "plugin:@typescript-eslint/recommended"
9 | ],
10 | "overrides": [
11 | ],
12 | "parser": "@typescript-eslint/parser",
13 | "parserOptions": {
14 | "ecmaVersion": "latest",
15 | "sourceType": "module",
16 | "project": "./tsconfig.json"
17 | },
18 | "plugins": [
19 | "@typescript-eslint"
20 | ],
21 | "rules": {
22 | "indent": [
23 | "error",
24 | 4
25 | ],
26 | "linebreak-style": [
27 | "error",
28 | "unix"
29 | ],
30 | "quotes": [
31 | "error",
32 | "single"
33 | ],
34 | "semi": [
35 | "error",
36 | "always"
37 | ]
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | out
3 | .vscode-test
4 | .vscode/settings.json
5 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Run Extension",
9 | "type": "extensionHost",
10 | "request": "launch",
11 | "runtimeExecutable": "${execPath}",
12 | "args": [
13 | "--extensionDevelopmentPath=${workspaceFolder}"
14 | ],
15 | "outFiles": [
16 | "${workspaceFolder}/out/**/*.js"
17 | ],
18 | "preLaunchTask": "npm: watch",
19 | "sourceMaps": true
20 | },
21 | {
22 | "name": "Run Extension Tests",
23 | "type": "extensionHost",
24 | "request": "launch",
25 | "runtimeExecutable": "${execPath}",
26 | "args": [
27 | "--extensionDevelopmentPath=${workspaceFolder}",
28 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index"
29 | ],
30 | "outFiles": ["${workspaceFolder}/out/test/**/*.js"],
31 | "sourceMaps": true
32 | }
33 | ]
34 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | // See https://go.microsoft.com/fwlink/?LinkId=733558
2 | // for the documentation about the tasks.json format
3 | {
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "type": "npm",
8 | "script": "watch",
9 | "problemMatcher": "$tsc-watch",
10 | "isBackground": true,
11 | "presentation": {
12 | "reveal": "never"
13 | },
14 | "group": {
15 | "kind": "build",
16 | "isDefault": true
17 | }
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/.vscodeignore:
--------------------------------------------------------------------------------
1 | .vscode
2 | out/test/**
3 | tsconfig.json
4 | webpack.config.js
5 | node_modules/**
6 | src/**
7 | .git/**
8 | .vscode/**
9 | *.ts
10 | *.js.map
11 | *.log
12 | *.yml
13 | *.json
14 | coverage/**
15 | test/**
16 | releases/**
17 | out/**/*.js
18 | out/**/*.js.map
19 | !out/main.js
20 | images/icon_full.svg
21 | images/icon_black.svg
22 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021-2024 NVIDIA Corporation
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
--------------------------------------------------------------------------------
/ReleaseNotes.md:
--------------------------------------------------------------------------------
1 | # Blue Bazel - Changelog
2 |
3 | ## 0.0.1
4 |
5 | First release of Blue Bazel VS Code extension, which provides UI integration for bazel/dazel project building, running, debugging, and testing.
6 |
7 | ## 0.0.2
8 |
9 | Fix issue with executable paths not working because run configs were not applied to the query that retrieves the target path.
10 |
11 | ## 0.0.3
12 |
13 | Stop showing output pane for background tasks. Include file based settings for projects. Show progress bar for long-running tasks.
14 |
15 | ## 0.0.4
16 |
17 | Fix bug that caused empty test_arg to appear when there were no test args. Add ability to set environment before bazel commands.
18 |
19 | ## 0.0.5
20 |
21 | Fix bug that caused user to reload if settings changed for settings that did not require that.
22 | Fix issue of running query every time test button is pushed.
23 | Added copy buttons to args and to commands.
24 |
25 | ## 1.0.0
26 |
27 | First major release.
28 | Refactor entire codebase to address separation of concerns throughtout.
29 | Add capability to add multiple types of actions (not just build, run, test) such as query.
30 | Add capability to add multiple targets to each action.
31 | Add capability to debug golang and python targets.
32 | Add autocomplete (if available) to config and bazel args for target properties.
33 | Add quickpick for all targets.
34 |
35 | ## 1.0.1
36 |
37 | Add code lens actions to some language unit tests (run test and debug test).
38 | Fix bug that caused multiple refresh targets to fire when multiple BUILD files were changed at once (usually a git operation).
39 | Add option to not refresh targets automatically when BUILD files change as it is still experimental.
40 | Add optional timeout in milliseconds to refresh targets.
41 |
42 | ## 1.0.2
43 |
44 | Change loading of available targets so if cache exists, do no load targets.
45 | Make refreshing targets on workspace open optional.
46 | Fix regex for c/c++ test code lens provider.
47 | Add plugin support for languages.
48 | Add debug direct support for python.
49 | Python debugging with bazel run_under does not work because debugpy cannot work with os.execv. This is called when py_binary builds a wrapper around the src files in the py_binary.
50 | Allow for no reload when custom buttons are created.
51 |
52 | ## 1.0.3
53 |
54 | Change the way available targets are fetched. Now they can be fetched from BUILD files so that the Bazel engine is not tied up using query. The old query is maintained via a setting.
55 | Add a dialog before running clean command.
56 | Add capability to run and debug from main functions for languages that have support.
57 |
58 | ## 1.0.4
59 |
60 | Swap typescript in for awk when available targets are fetched. Awk, albeit much faster, is not as portable as the typescript solution.
61 | Remove shellscript from C++ language support.
62 | Clear the workspace state only on major version changes.
63 |
64 | ## 1.0.5
65 |
66 | Add unit tests for the bazel parser and service.
67 | Fix query of targets to be more accurate.
68 | Fix argument passing when debugging with C/C++ and GDB.
69 |
70 | ## 1.0.6
71 |
72 | Fix gdbserver not following child processes in C/C++ applications.
73 | Add support for bzlmod files.
74 |
--------------------------------------------------------------------------------
/images/demo_debug.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/images/demo_debug.gif
--------------------------------------------------------------------------------
/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/images/icon.png
--------------------------------------------------------------------------------
/images/icon_black_empty.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
143 |
--------------------------------------------------------------------------------
/images/icon_full.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
161 |
--------------------------------------------------------------------------------
/images/icon_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/images/icon_small.png
--------------------------------------------------------------------------------
/images/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/images/screenshot.png
--------------------------------------------------------------------------------
/images/test_codelens_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/images/test_codelens_screenshot.png
--------------------------------------------------------------------------------
/releases/bluebazel-0.0.1.vsix:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/releases/bluebazel-0.0.1.vsix
--------------------------------------------------------------------------------
/releases/bluebazel-0.0.2.vsix:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/releases/bluebazel-0.0.2.vsix
--------------------------------------------------------------------------------
/releases/bluebazel-0.0.3.vsix:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/releases/bluebazel-0.0.3.vsix
--------------------------------------------------------------------------------
/releases/bluebazel-0.0.4.vsix:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/releases/bluebazel-0.0.4.vsix
--------------------------------------------------------------------------------
/releases/bluebazel-0.0.5.vsix:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/releases/bluebazel-0.0.5.vsix
--------------------------------------------------------------------------------
/releases/bluebazel-1.0.0.vsix:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/releases/bluebazel-1.0.0.vsix
--------------------------------------------------------------------------------
/releases/bluebazel-1.0.1.vsix:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/releases/bluebazel-1.0.1.vsix
--------------------------------------------------------------------------------
/releases/bluebazel-1.0.2.vsix:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/releases/bluebazel-1.0.2.vsix
--------------------------------------------------------------------------------
/releases/bluebazel-1.0.3.vsix:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/releases/bluebazel-1.0.3.vsix
--------------------------------------------------------------------------------
/releases/bluebazel-1.0.4.vsix:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/releases/bluebazel-1.0.4.vsix
--------------------------------------------------------------------------------
/releases/bluebazel-1.0.5.vsix:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/releases/bluebazel-1.0.5.vsix
--------------------------------------------------------------------------------
/releases/bluebazel-1.0.6.vsix:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NVIDIA/bluebazel/f7381f2ac8b26d85878109d4b0e44ce9ddfd35a0/releases/bluebazel-1.0.6.vsix
--------------------------------------------------------------------------------
/src/controllers/command-controller.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { BazelController } from './bazel-controller';
26 | import { BazelTargetOperationsController } from './bazel-target-operations-controller';
27 | import { registerBazelCommands } from './commands/bazel-commands';
28 | import { registerBazelTargetOperationsCommands } from './commands/bazel-target-operations-commands';
29 | import { registerDebugCommands } from './commands/debug-commands';
30 | import { registerMultiPropTreeItemCommands } from './commands/multi-prop-tree-item-commands';
31 | import { registerSinglePropTreeItemCommands } from './commands/single-prop-tree-item-commands';
32 | import { registerTreeDataProviderCommands } from './commands/tree-data-provider-commands';
33 | import { registerUserCommands } from './commands/user-commands';
34 | import { BazelTargetControllerManager } from './target-controllers/bazel-target-controller-manager';
35 | import { DebugController } from './target-controllers/debug-controller';
36 | import { UserCommandsController } from './user-commands-controller';
37 | import { BazelTargetManager } from '../models/bazel-target-manager';
38 | import { ConfigurationManager } from '../services/configuration-manager';
39 | import { BazelTargetTreeProvider } from '../ui/bazel-target-tree-provider';
40 | import * as vscode from 'vscode';
41 |
42 | export function registerCommands(context: vscode.ExtensionContext,
43 | configurationManager: ConfigurationManager,
44 | userCommandsController: UserCommandsController,
45 | bazelController: BazelController,
46 | bazelTargetControllerManager: BazelTargetControllerManager,
47 | bazelTargetOpsController: BazelTargetOperationsController,
48 | bazelTargetManager: BazelTargetManager,
49 | bazelTreeDataProvider: BazelTargetTreeProvider
50 | ) {
51 | registerTreeDataProviderCommands(context);
52 | registerMultiPropTreeItemCommands(context, bazelTreeDataProvider);
53 | registerSinglePropTreeItemCommands(context, bazelTreeDataProvider);
54 | registerBazelCommands(context, bazelController);
55 | registerBazelTargetOperationsCommands(context, bazelTargetOpsController, bazelTargetManager);
56 | registerDebugCommands(context, bazelTargetControllerManager.getController('debug') as DebugController, bazelTargetManager);
57 | registerUserCommands(context, configurationManager, userCommandsController);
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/src/controllers/commands/bazel-commands.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { ExtensionUtils } from '../../services/extension-utils';
25 | import { BazelController } from '../bazel-controller';
26 | import * as vscode from 'vscode';
27 |
28 |
29 |
30 | export function registerBazelCommands(context: vscode.ExtensionContext,
31 | bazelController: BazelController) {
32 |
33 | const extensionName = ExtensionUtils.getExtensionName(context);
34 |
35 | context.subscriptions.push(vscode.commands.registerCommand(`${extensionName}.refreshTargets`, () => {
36 | bazelController.refreshAvailableTargets();
37 | }));
38 |
39 | context.subscriptions.push(vscode.commands.registerCommand(`${extensionName}.format`, () => {
40 | bazelController.format();
41 | }));
42 |
43 | context.subscriptions.push(vscode.commands.registerCommand(`${extensionName}.clean`, () => {
44 | bazelController.clean();
45 | }));
46 |
47 | context.subscriptions.push(vscode.commands.registerCommand(`${extensionName}.buildCurrentFile`, () => {
48 | bazelController.buildSingle();
49 | }));
50 |
51 | }
--------------------------------------------------------------------------------
/src/controllers/commands/bazel-target-operations-commands.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { BazelTarget } from '../../models/bazel-target';
25 | import { BazelTargetManager } from '../../models/bazel-target-manager';
26 | import { ExtensionUtils } from '../../services/extension-utils';
27 | import { BazelTargetCategory } from '../../ui/bazel-target-tree-provider';
28 | import { BazelTargetOperationsController } from '../bazel-target-operations-controller';
29 | import * as vscode from 'vscode';
30 |
31 | export function registerBazelTargetOperationsCommands(
32 | context: vscode.ExtensionContext,
33 | bazelTargetOpsController: BazelTargetOperationsController,
34 | bazelTargetManager: BazelTargetManager,
35 | ) {
36 |
37 |
38 | const extensionName = ExtensionUtils.getExtensionName(context);
39 |
40 | context.subscriptions.push(vscode.commands.registerCommand(`${extensionName}.addTarget`, (targetCategory: BazelTargetCategory) => {
41 | bazelTargetOpsController.pickTarget(targetCategory.action);
42 | }));
43 |
44 | context.subscriptions.push(vscode.commands.registerCommand(`${extensionName}.addActionAndTarget`, () => {
45 | bazelTargetOpsController.pickTarget();
46 | }));
47 |
48 | context.subscriptions.push(vscode.commands.registerCommand(`${extensionName}.removeTarget`, (target: BazelTarget) => {
49 | if (target) {
50 | bazelTargetOpsController.removeTarget(target);
51 | }
52 | }));
53 |
54 | context.subscriptions.push(vscode.commands.registerCommand(`${extensionName}.copyTarget`, (target: BazelTarget) => {
55 | if (target) {
56 | bazelTargetOpsController.copyTarget(target);
57 | }
58 | }));
59 |
60 | context.subscriptions.push(vscode.commands.registerCommand(`${extensionName}.copyCommand`, (target: BazelTarget) => {
61 | if (target) {
62 | bazelTargetOpsController.copyCommandToClipboard(target);
63 | }
64 | }));
65 |
66 | context.subscriptions.push(vscode.commands.registerCommand(`${extensionName}.pickTarget`, (target: BazelTarget) => {
67 | bazelTargetOpsController.pickTarget(target);
68 | }));
69 |
70 | context.subscriptions.push(vscode.commands.registerCommand(`${extensionName}.executeTarget`, (target: BazelTarget) => {
71 | bazelTargetOpsController.executeTarget(target);
72 | }), vscode.commands.registerCommand(`${extensionName}.executingTarget`, () => {
73 | // Do nothing
74 | }));
75 |
76 | // Make build, run, and test selected target commands public for hotkey binding
77 | ['build', 'run', 'test'].forEach(action => {
78 | context.subscriptions.push(vscode.commands.registerCommand(`${extensionName}.${action}`, () => {
79 | const selectedTarget = bazelTargetManager.getSelectedTarget(action);
80 | if (selectedTarget) {
81 | bazelTargetOpsController.executeTarget(selectedTarget);
82 | }
83 | }));
84 | });
85 | }
86 |
--------------------------------------------------------------------------------
/src/controllers/commands/debug-commands.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { BazelTarget } from '../../models/bazel-target';
25 | import { BazelTargetManager } from '../../models/bazel-target-manager';
26 | import { ExtensionUtils } from '../../services/extension-utils';
27 | import { DebugController } from '../target-controllers/debug-controller';
28 | import * as vscode from 'vscode';
29 |
30 |
31 | export function registerDebugCommands(context: vscode.ExtensionContext,
32 | debugController: DebugController,
33 | bazelTargetManager: BazelTargetManager) {
34 |
35 | const extensionName = ExtensionUtils.getExtensionName(context);
36 | context.subscriptions.push(vscode.commands.registerCommand(`${extensionName}.debugTarget`, (target: BazelTarget) => {
37 | debugController.execute(target).catch(error => {
38 | vscode.window.showErrorMessage(`${error}`);
39 | });
40 | }));
41 |
42 | context.subscriptions.push(vscode.commands.registerCommand(`${extensionName}.debug`, () => {
43 | const selectedTarget = bazelTargetManager.getSelectedTarget('run');
44 | if (selectedTarget) {
45 | debugController.execute(selectedTarget).catch(error => {
46 | vscode.window.showErrorMessage(`${error}`);
47 | });
48 | }
49 | }));
50 |
51 | }
--------------------------------------------------------------------------------
/src/controllers/commands/multi-prop-tree-item-commands.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { BazelTargetMultiProperty, BazelTargetMultiPropertyItem } from '../../models/bazel-target-multi-property';
26 | import { ExtensionUtils } from '../../services/extension-utils';
27 | import { BazelTargetTreeProvider } from '../../ui/bazel-target-tree-provider';
28 | import { showSimpleQuickPick } from '../../ui/quick-pick';
29 | import * as vscode from 'vscode';
30 |
31 | export function registerMultiPropTreeItemCommands(context: vscode.ExtensionContext,
32 | treeDataProvider: BazelTargetTreeProvider
33 | ) {
34 | const extensionName = ExtensionUtils.getExtensionName(context);
35 |
36 | context.subscriptions.push(
37 | vscode.commands.registerCommand(`${extensionName}.addToMultiPropTreeItem`, (property: BazelTargetMultiProperty) => {
38 |
39 | const loadQuickPickData = async (cancellationToken: vscode.CancellationToken): Promise => {
40 | try {
41 | const values = await property.getAvailableValues(cancellationToken);
42 |
43 | // If property should show history, add the history data to the values
44 | if (property.shouldShowHistory()) {
45 | const historyData: string[] = property.getHistory();
46 | values.unshift(...historyData);
47 | }
48 | return values;
49 | } catch (error) {
50 | return Promise.reject(error);
51 | }
52 | };
53 |
54 | showSimpleQuickPick(loadQuickPickData, (data: string) => {
55 | const values = property.toStringArray();
56 | values.push(data);
57 | property.add(data);
58 | treeDataProvider.refresh();
59 | }, `Loading items for ${property.label.toLowerCase()}...`);
60 | }),
61 | vscode.commands.registerCommand(`${extensionName}.editMultiPropTreeItem`, (item: BazelTargetMultiPropertyItem) => {
62 | vscode.window.showInputBox({
63 | value: item.get()
64 | }).then(data => {
65 | if (data !== undefined) {
66 | if (data.replace(/\s/g, '') === '') {
67 | item.remove();
68 | } else {
69 | item.update(data);
70 | }
71 | }
72 | treeDataProvider.refresh();
73 | });
74 | }),
75 | vscode.commands.registerCommand(`${extensionName}.removeMultiPropTreeItem`, (item: BazelTargetMultiPropertyItem) => {
76 | item.remove();
77 | treeDataProvider.refresh();
78 | }),
79 | vscode.commands.registerCommand(`${extensionName}.copyMultiPropTreeItem`, (item: BazelTargetMultiPropertyItem) => {
80 | vscode.env.clipboard.writeText(item.get());
81 | })
82 | );
83 | }
--------------------------------------------------------------------------------
/src/controllers/commands/single-prop-tree-item-commands.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { BazelTargetProperty } from '../../models/bazel-target-property';
26 | import { ExtensionUtils } from '../../services/extension-utils';
27 | import { BazelTargetTreeProvider } from '../../ui/bazel-target-tree-provider';
28 | import { showSimpleQuickPick } from '../../ui/quick-pick';
29 | import * as vscode from 'vscode';
30 |
31 | export function registerSinglePropTreeItemCommands(context: vscode.ExtensionContext, treeDataProvider: BazelTargetTreeProvider) {
32 | const extensionName = ExtensionUtils.getExtensionName(context);
33 | context.subscriptions.push(
34 | vscode.commands.registerCommand(`${extensionName}.copySinglePropTreeItem`, (property: BazelTargetProperty) => {
35 | vscode.env.clipboard.writeText(property.get());
36 | }),
37 | vscode.commands.registerCommand(`${extensionName}.editSinglePropTreeItem`, (property: BazelTargetProperty) => {
38 | const data: string[] = property.getHistory();
39 | showSimpleQuickPick(data, (data: string) => {
40 | property.update(data);
41 | treeDataProvider.refresh();
42 | });
43 | })
44 | );
45 | }
--------------------------------------------------------------------------------
/src/controllers/commands/tree-data-provider-commands.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { ExtensionUtils } from '../../services/extension-utils';
26 | import * as vscode from 'vscode';
27 |
28 | export function registerTreeDataProviderCommands(context: vscode.ExtensionContext) {
29 | const extensionName = ExtensionUtils.getExtensionName(context);
30 | vscode.commands.registerCommand(`${extensionName}.collapseAll`, () => {
31 | vscode.commands.executeCommand('workbench.actions.treeView.bluebazelView.collapseAll');
32 | });
33 | }
--------------------------------------------------------------------------------
/src/controllers/commands/user-commands.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { ConfigurationManager, UserCustomButton } from '../../services/configuration-manager';
26 | import { Console } from '../../services/console';
27 | import { ExtensionUtils } from '../../services/extension-utils';
28 | import { UserCommandsController } from '../user-commands-controller';
29 | import * as vscode from 'vscode';
30 |
31 | export function registerCustomButtons(context: vscode.ExtensionContext,
32 | configurationManager: ConfigurationManager,
33 | userCommandsController: UserCommandsController
34 | ): void {
35 | // Traverses through the configuration and registers commands with method names.
36 | const customButtons = configurationManager.getCustomButtons();
37 | if (customButtons === undefined) {
38 | return;
39 | }
40 | customButtons.forEach(section => {
41 | const buttons = section.buttons;
42 | if (buttons !== undefined) {
43 | buttons.forEach(button => {
44 | try {
45 | const disposableCommand = vscode.commands.registerCommand(button.methodName, async (command: string) => {
46 | await userCommandsController.runCustomTask(command);
47 | });
48 | context.subscriptions.push(disposableCommand);
49 | } catch (error) {
50 | Console.error(error);
51 | }
52 | });
53 | }
54 | });
55 | }
56 |
57 | export function registerUserCommands(context: vscode.ExtensionContext,
58 | configurationManager: ConfigurationManager,
59 | userCommandsController: UserCommandsController
60 | ): void {
61 | registerCustomButtons(context, configurationManager, userCommandsController);
62 |
63 | const extensionName = ExtensionUtils.getExtensionName(context);
64 | context.subscriptions.push(vscode.commands.registerCommand(`${extensionName}.customButton`, (button: UserCustomButton) => {
65 | const registeredCommand = button.methodName;
66 | vscode.commands.executeCommand(registeredCommand, button.command);
67 | }));
68 |
69 | }
--------------------------------------------------------------------------------
/src/controllers/target-controllers/any-action-controller.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { BazelTargetController } from './bazel-target-controller';
26 | import { BazelAction, BazelTarget } from '../../models/bazel-target';
27 | import { BazelTargetPropertyHistory } from '../../models/bazel-target-property-history';
28 | import { BazelTargetState, BazelTargetStateManager } from '../../models/bazel-target-state-manager';
29 | import { ConfigurationManager } from '../../services/configuration-manager';
30 | import { capitalizeFirstLetter, cleanAndFormat } from '../../services/string-utils';
31 | import { TaskService } from '../../services/task-service';
32 | import { showProgress } from '../../ui/progress';
33 | import * as vscode from 'vscode';
34 |
35 |
36 | export class AnyActionController implements BazelTargetController {
37 | private readonly quickPickHistory: Map;
38 | constructor(private readonly context: vscode.ExtensionContext,
39 | private readonly configurationManager: ConfigurationManager,
40 | private readonly taskService: TaskService,
41 | private readonly bazelTargetStateManager: BazelTargetStateManager
42 | ) {
43 | this.quickPickHistory = new Map();
44 | }
45 |
46 | public async execute(target: BazelTarget): Promise {
47 | try {
48 | this.bazelTargetStateManager.setTargetState(target, BazelTargetState.Executing);
49 | const executable = this.configurationManager.getExecutableCommand();
50 |
51 | await showProgress(`${capitalizeFirstLetter(target.action)}ing ${target.bazelPath}`, (cancellationToken) => {
52 | return this.taskService.runTask(
53 | `${target.action} ${target.bazelPath}`, // task name
54 | `${executable} ${target.action} ${target.bazelPath}`,
55 | this.configurationManager.isClearTerminalBeforeAction(),
56 | cancellationToken,
57 | target.id
58 | );
59 | });
60 | } catch (error) {
61 | return Promise.reject(error);
62 | } finally {
63 | this.bazelTargetStateManager.setTargetState(target, BazelTargetState.Idle);
64 | }
65 | }
66 |
67 | public async getExecuteCommand(target: BazelTarget): Promise {
68 | const executable = this.configurationManager.getExecutableCommand();
69 | const args = target.getBazelArgs();
70 | const configArgs = target.getConfigArgs();
71 | const envVars = target.getEnvVars();
72 | const command = cleanAndFormat(
73 | executable,
74 | target.action,
75 | args.toString(),
76 | configArgs.toString(),
77 | target.buildPath,
78 | envVars.toString()
79 | );
80 |
81 | return `${command}\n`;
82 | }
83 | }
--------------------------------------------------------------------------------
/src/controllers/target-controllers/bazel-target-controller-manager.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { AnyActionController } from './any-action-controller';
26 | import { BazelTargetController } from './bazel-target-controller';
27 | import { BuildController } from './build-controller';
28 | import { DebugController } from './debug-controller';
29 | import { RunController } from './run-controller';
30 | import { TestController } from './test-controller';
31 | import { BazelEnvironment } from '../../models/bazel-environment';
32 | import { BazelTargetManager } from '../../models/bazel-target-manager';
33 | import { BazelTargetStateManager } from '../../models/bazel-target-state-manager';
34 | import { BazelService } from '../../services/bazel-service';
35 | import { ConfigurationManager } from '../../services/configuration-manager';
36 | import { ShellService } from '../../services/shell-service';
37 | import { TaskService } from '../../services/task-service';
38 | import { BazelController } from '../bazel-controller';
39 | import * as vscode from 'vscode';
40 |
41 |
42 | export class BazelTargetControllerManager {
43 | private controllers: Map = new Map();
44 |
45 | constructor(context: vscode.ExtensionContext,
46 | configurationManager: ConfigurationManager,
47 | taskService: TaskService,
48 | shellService: ShellService,
49 | bazelService: BazelService,
50 | bazelController: BazelController,
51 | bazelEnvironment: BazelEnvironment,
52 | bazelTargetManager: BazelTargetManager,
53 | bazelTargetStateManager: BazelTargetStateManager
54 | ) {
55 | const buildController = new BuildController(context,
56 | configurationManager,
57 | taskService,
58 | bazelTargetManager,
59 | bazelTargetStateManager);
60 |
61 | const runController = new RunController(context,
62 | configurationManager,
63 | taskService,
64 | bazelService,
65 | buildController,
66 | bazelTargetStateManager);
67 |
68 | const testController = new TestController(context,
69 | configurationManager,
70 | taskService,
71 | bazelTargetStateManager);
72 |
73 | this.controllers.set('build', buildController);
74 | this.controllers.set('run', runController);
75 |
76 | this.controllers.set('test', testController);
77 |
78 | this.controllers.set('debug', new DebugController(context,
79 | configurationManager,
80 | taskService,
81 | bazelService,
82 | buildController,
83 | bazelTargetStateManager));
84 |
85 | // Coverage operates very similar to test, so use test controller
86 | this.controllers.set('coverage', testController);
87 |
88 | this.controllers.set('*', new AnyActionController(context,
89 | configurationManager,
90 | taskService,
91 | bazelTargetStateManager));
92 | }
93 |
94 | public getController(action: string): BazelTargetController | undefined {
95 | if (this.controllers.has(action))
96 | return this.controllers.get(action);
97 | return this.controllers.get('*');
98 | }
99 | }
--------------------------------------------------------------------------------
/src/controllers/target-controllers/bazel-target-controller.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { BazelTarget } from '../../models/bazel-target';
26 |
27 | export interface BazelTargetController {
28 | execute(target: BazelTarget): Promise;
29 | getExecuteCommand(target: BazelTarget): Promise;
30 | }
--------------------------------------------------------------------------------
/src/controllers/target-controllers/build-controller.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { BazelTargetController } from './bazel-target-controller';
26 | import { BazelTarget } from '../../models/bazel-target';
27 | import { BazelTargetManager } from '../../models/bazel-target-manager';
28 | import { BazelTargetState, BazelTargetStateManager } from '../../models/bazel-target-state-manager';
29 | import { BAZEL_BIN } from '../../services/bazel-parser';
30 | import { ConfigurationManager } from '../../services/configuration-manager';
31 | import { EnvVarsUtils } from '../../services/env-vars-utils';
32 | import { cleanAndFormat } from '../../services/string-utils';
33 | import { TaskService } from '../../services/task-service';
34 | import { showProgress } from '../../ui/progress';
35 | import * as path from 'path';
36 | import * as vscode from 'vscode';
37 |
38 |
39 |
40 | export const BUILD_RUN_TARGET_STR = '';
41 |
42 | export class BuildController implements BazelTargetController {
43 | constructor(private readonly context: vscode.ExtensionContext,
44 | private readonly configurationManager: ConfigurationManager,
45 | private readonly taskService: TaskService,
46 | private readonly bazelTargetManager: BazelTargetManager,
47 | private readonly bazelTargetStateManager: BazelTargetStateManager
48 | ) { }
49 |
50 | public async execute(target: BazelTarget): Promise {
51 | const actualTarget = this.getActualBuildTargetPath(target);
52 | if (!actualTarget) {
53 | vscode.window.showErrorMessage('Build failed. Could not find run target.');
54 | return;
55 | }
56 |
57 | const buildCommand = await this.getExecuteCommand(target);
58 | if (!buildCommand) {
59 | vscode.window.showErrorMessage('Build failed. Could not find run target.');
60 | return;
61 | }
62 |
63 | // Both the run and debug controllers can call build,
64 | // we don't want to change the state if it isn't idle.
65 | const shouldChangeState = this.bazelTargetStateManager.getTargetState(target) === BazelTargetState.Idle;
66 | try {
67 | if (shouldChangeState) {
68 | this.bazelTargetStateManager.setTargetState(target, BazelTargetState.Executing);
69 | }
70 | await showProgress(`Building ${actualTarget}`, (cancellationToken) => {
71 | return this.taskService.runTask(`${target.action} ${actualTarget}`,
72 | buildCommand, this.configurationManager.isClearTerminalBeforeAction(), cancellationToken, target.id);
73 | });
74 | } catch (error) {
75 | return Promise.reject(error);
76 | } finally {
77 | if (shouldChangeState) {
78 | this.bazelTargetStateManager.setTargetState(target, BazelTargetState.Idle);
79 | }
80 | }
81 | }
82 |
83 | public async getExecuteCommand(target: BazelTarget): Promise {
84 | const actualTarget = this.getActualBuildTargetPath(target);
85 | if (!actualTarget) {
86 | return undefined;
87 | }
88 |
89 | const executable = this.configurationManager.getExecutableCommand();
90 | const buildArgs = target.getBazelArgs().toString();
91 | const configArgs = target.getConfigArgs().toString();
92 | const buildEnvVars = EnvVarsUtils.toBuildEnvVars(target.getEnvVars().toStringArray());
93 | // Clean and format the command by removing extra spaces and empty strings
94 | const command = cleanAndFormat(
95 | executable,
96 | 'build',
97 | buildArgs,
98 | configArgs,
99 | actualTarget,
100 | buildEnvVars
101 | );
102 |
103 | return `${command}\n`;
104 | }
105 |
106 | private getActualBuildTargetPath(target: BazelTarget): string | undefined {
107 | let actualTarget = target.bazelPath;
108 | if (target.buildPath === BUILD_RUN_TARGET_STR) {
109 | // Find run target
110 | const runTarget = this.bazelTargetManager.getSelectedTarget('run');
111 | if (runTarget !== undefined &&
112 | typeof runTarget === 'object' &&
113 | runTarget !== null &&
114 | Object.keys(runTarget).includes('detail')) {
115 | actualTarget = path.relative(BAZEL_BIN, runTarget.buildPath);
116 | } else {
117 | return undefined;
118 | }
119 | }
120 | return actualTarget;
121 | }
122 |
123 | }
--------------------------------------------------------------------------------
/src/controllers/target-controllers/test-controller.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { BazelTargetController } from './bazel-target-controller';
26 | import { BazelTarget } from '../../models/bazel-target';
27 | import { BazelTargetState, BazelTargetStateManager } from '../../models/bazel-target-state-manager';
28 | import { ConfigurationManager } from '../../services/configuration-manager';
29 | import { EnvVarsUtils } from '../../services/env-vars-utils';
30 | import { capitalizeFirstLetter, cleanAndFormat } from '../../services/string-utils';
31 | import { TaskService } from '../../services/task-service';
32 | import { showProgress } from '../../ui/progress';
33 | import * as vscode from 'vscode';
34 |
35 |
36 | export class TestController implements BazelTargetController {
37 | constructor(private readonly context: vscode.ExtensionContext,
38 | private readonly configurationManager: ConfigurationManager,
39 | private readonly taskService: TaskService,
40 | private readonly bazelTargetStateManager: BazelTargetStateManager
41 | ) { }
42 |
43 | public async execute(target: BazelTarget) {
44 | const testCommand = await this.getExecuteCommand(target);
45 | if (!testCommand) {
46 | vscode.window.showErrorMessage('Test failed. Could not get test target.');
47 | return;
48 | }
49 |
50 | const taskLabel = `${target.action} ${target.bazelPath}`;
51 |
52 | return showProgress(`${capitalizeFirstLetter(target.action)}ing ${target.bazelPath}`, async (cancellationToken) => {
53 | try {
54 | this.bazelTargetStateManager.setTargetState(target, BazelTargetState.Executing);
55 | await this.taskService.runTask(taskLabel, testCommand,
56 | this.configurationManager.isClearTerminalBeforeAction(),
57 | cancellationToken, target.id);
58 | } catch (error) {
59 | return Promise.reject(error);
60 | } finally {
61 | this.bazelTargetStateManager.setTargetState(target, BazelTargetState.Idle);
62 | }
63 | });
64 | }
65 |
66 | public async getExecuteCommand(target: BazelTarget): Promise {
67 |
68 | if (!target) {
69 | return undefined;
70 | }
71 | const executable = this.configurationManager.getExecutableCommand();
72 | const bazelArgs = target.getBazelArgs();
73 | const configArgs = target.getConfigArgs();
74 | const envVars = EnvVarsUtils.toTestEnvVars(target.getEnvVars().toStringArray());
75 | const testArgs = target.getRunArgs();
76 |
77 | const bazelTarget = target.bazelPath;
78 | const command = cleanAndFormat(
79 | executable,
80 | 'test',
81 | bazelArgs.toString(),
82 | configArgs.toString(),
83 | envVars,
84 | bazelTarget,
85 | testArgs.toString()
86 | );
87 |
88 | return `${command}\n`;
89 | }
90 | }
--------------------------------------------------------------------------------
/src/controllers/workspace-events-controller.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { registerCustomButtons } from './commands/user-commands';
25 | import { UserCommandsController } from './user-commands-controller';
26 | import { ConfigurationManager } from '../services/configuration-manager';
27 | import { ExtensionUtils } from '../services/extension-utils';
28 | import { BazelTargetTreeProvider } from '../ui/bazel-target-tree-provider';
29 | import * as vscode from 'vscode';
30 |
31 | export class WorkspaceEventsController {
32 | constructor(private context: vscode.ExtensionContext,
33 | private readonly configurationManager: ConfigurationManager,
34 | private readonly userCommandsController: UserCommandsController,
35 | private readonly bazelTree: BazelTargetTreeProvider) {
36 | this.registerConfigurationChangeHandler();
37 | }
38 |
39 | private registerConfigurationChangeHandler() {
40 | vscode.workspace.onDidChangeConfiguration((e) => {
41 | if (e.affectsConfiguration(ExtensionUtils.getExtensionName(this.context))) {
42 | registerCustomButtons(this.context, this.configurationManager, this.userCommandsController);
43 | this.bazelTree.refresh();
44 | }
45 | });
46 | }
47 | }
--------------------------------------------------------------------------------
/src/languages/language-plugin.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { BazelTarget } from '../models/bazel-target';
25 | import * as vscode from 'vscode';
26 |
27 |
28 | export interface LanguagePlugin {
29 | supportedLanguages: string[];
30 |
31 | getDebugRunUnderCommand(port: number): string;
32 |
33 | getDebugEnvVars(target: BazelTarget): string[]
34 |
35 | createDebugDirectLaunchConfig(target: BazelTarget, cancellationToken?: vscode.CancellationToken): Promise;
36 |
37 | createDebugAttachConfig(target: BazelTarget, port: number, cancellationToken?: vscode.CancellationToken): Promise;
38 |
39 | getCodeLensTestRegex(): RegExp;
40 |
41 | getCodeLensRunRegex(): RegExp;
42 |
43 | }
--------------------------------------------------------------------------------
/src/languages/language-registry.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { LanguagePlugin } from './language-plugin';
25 | import { CppLanguagePlugin } from './plugins/cpp-language-plugin';
26 | import { GoLanguagePlugin } from './plugins/go-language-plugin';
27 | import { PythonLanguagePlugin } from './plugins/python-language-plugin';
28 | import { BazelEnvironment } from '../models/bazel-environment';
29 | import { BazelService } from '../services/bazel-service';
30 | import * as vscode from 'vscode';
31 |
32 |
33 | export class LanguageRegistry {
34 | private static plugins: { [language: string]: LanguagePlugin } = {};
35 |
36 | static registerPlugin(plugin: LanguagePlugin) {
37 | for (const language of plugin.supportedLanguages) {
38 | if (this.plugins[language]) {
39 | throw new Error(`Language plugin for '${language}' is already registered.`);
40 | }
41 | this.plugins[language] = plugin;
42 | }
43 | }
44 |
45 | static getPlugin(language: string | undefined): LanguagePlugin {
46 | if (!language || !this.plugins[language]) {
47 | throw new Error(`No language support for ${language}`);
48 | }
49 | return this.plugins[language];
50 | }
51 |
52 | static getLanguages(): string[] {
53 | return Object.keys(this.plugins);
54 | }
55 | }
56 |
57 | export function registerLanguages(context: vscode.ExtensionContext,
58 | bazelService: BazelService,
59 | bazelEnvironment: BazelEnvironment) {
60 |
61 | LanguageRegistry.registerPlugin(new CppLanguagePlugin(context, bazelService, bazelEnvironment.getEnvVars()));
62 | LanguageRegistry.registerPlugin(new GoLanguagePlugin(context, bazelService, bazelEnvironment.getEnvVars()));
63 | LanguageRegistry.registerPlugin(new PythonLanguagePlugin(context, bazelService, bazelEnvironment.getEnvVars()));
64 | }
65 |
--------------------------------------------------------------------------------
/src/languages/plugins/go-language-plugin.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { BazelTarget } from '../../models/bazel-target';
25 | import { BazelService } from '../../services/bazel-service';
26 | import { EnvVarsUtils } from '../../services/env-vars-utils';
27 | import { isRemoteSession } from '../../services/network-utils';
28 | import { LanguagePlugin } from '../language-plugin';
29 | import * as path from 'path';
30 | import * as vscode from 'vscode';
31 |
32 |
33 | export class GoLanguagePlugin implements LanguagePlugin {
34 | public readonly supportedLanguages: string[];
35 |
36 | constructor(private readonly context: vscode.ExtensionContext,
37 | private readonly bazelService: BazelService,
38 | private readonly setupEnvVars: string[]
39 | ) {
40 | this.supportedLanguages = ['go'];
41 | }
42 |
43 | public getDebugRunUnderCommand(port: number): string {
44 | return `dlv exec --headless --listen=:${port} --api-version=2`;
45 | }
46 |
47 | public getDebugEnvVars(target: BazelTarget): string[] {
48 | // This is necessary because bazel tests in go will call bzltestutils.Wrap and
49 | // spawn a child process which dlv is not connected to. Turn it off.
50 | return target.ruleType.includes('test') ? ['GO_TEST_WRAP=0'] : [];
51 | }
52 |
53 | public async createDebugDirectLaunchConfig(target: BazelTarget, _cancellationToken?: vscode.CancellationToken): Promise {
54 | const workingDirectory = '${workspaceFolder}';
55 | const targetPath = target.buildPath;//await this.bazelService.getBazelTargetBuildPath(target, cancellationToken);
56 | const programPath = path.join(workingDirectory, targetPath);
57 | const envVars = EnvVarsUtils.listToObject(target.getEnvVars().toStringArray());
58 | const args = target.getRunArgs().toString();
59 |
60 | return {
61 | name: `${targetPath} (Direct)`,
62 | type: 'go',
63 | request: 'launch',
64 | mode: 'exec',
65 | program: programPath,
66 | args: args.length > 0 ? args.split(' ') : [],
67 | stopOnEntry: false,
68 | cwd: workingDirectory,
69 | env: {...EnvVarsUtils.listToObject(this.setupEnvVars), ...envVars},
70 | console: 'integratedTerminal',
71 | substitutePath: [
72 | {
73 | from: '${workspaceFolder}',
74 | to: ''
75 | }
76 | ]
77 | };
78 | }
79 |
80 | public async createDebugAttachConfig(target: BazelTarget,
81 | port: number,
82 | _cancellationToken?: vscode.CancellationToken): Promise {
83 | const debugConfig = {
84 | name: `${target.label} (Attach)`,
85 | type: 'go',
86 | request: 'attach',
87 | mode: 'remote',
88 | host: '127.0.0.1',
89 | port: port, // Port where dlv is listening
90 | cwd: '${workspaceFolder}',
91 | trace: 'verbose', // Enable verbose logging for debugging
92 | showLog: true,
93 | } as vscode.DebugConfiguration;
94 |
95 | if (isRemoteSession()) {
96 | // Paths don't match up for vscode over ssh
97 | debugConfig.substitutePath = [ // This is necessary for test breakpoints to work
98 | {
99 | from: '${workspaceFolder}',
100 | to: ''
101 | }
102 | ];
103 | }
104 | return debugConfig;
105 | }
106 |
107 | /**
108 | * Regex to match test functions in Go.
109 | * Example matches:
110 | * func TestFunctionName(t *testing.T) {
111 | * func TestAnotherFunction(t *testing.T) {
112 | */
113 | public getCodeLensTestRegex(): RegExp {
114 | return /^func\s+(Test\w+)\(\w+\s+\*testing\.T\)/gm;
115 | }
116 |
117 | /**
118 | * Regex to match main function definitions in Go.
119 | * Example matches:
120 | * func main() {
121 | */
122 | public getCodeLensRunRegex(): RegExp {
123 | return /^func\s+(main)\s*\(\s*\)\s*\{/gm;
124 | }
125 |
126 | }
--------------------------------------------------------------------------------
/src/languages/plugins/python-language-plugin.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { BazelTarget } from '../../models/bazel-target';
25 | import { BazelService } from '../../services/bazel-service';
26 | import { Console } from '../../services/console';
27 | import { EnvVarsUtils } from '../../services/env-vars-utils';
28 | import { LanguagePlugin } from '../language-plugin';
29 | import * as fs from 'fs';
30 | import * as path from 'path';
31 | import * as vscode from 'vscode';
32 |
33 |
34 |
35 | export class PythonLanguagePlugin implements LanguagePlugin {
36 | public readonly supportedLanguages: string[];
37 |
38 | constructor(private readonly context: vscode.ExtensionContext,
39 | private readonly bazelService: BazelService,
40 | private readonly setupEnvVars: string[]
41 | ) {
42 | this.supportedLanguages = ['python'];
43 | }
44 |
45 | public getDebugRunUnderCommand(_port: number): string {
46 | throw new Error('Python debugpy does not support bazel debugging (try debugging directly)');
47 | }
48 |
49 | public getDebugEnvVars(_target: BazelTarget): string[] {
50 | return [];
51 | }
52 |
53 | public async createDebugDirectLaunchConfig(
54 | target: BazelTarget,
55 | cancellationToken?: vscode.CancellationToken
56 | ): Promise {
57 | let pythonFile = '';
58 | try {
59 | const runfiles = await this.bazelService.getRunfilesLocation(target, cancellationToken);
60 | pythonFile = this.findMainInRunfiles(runfiles);
61 | } catch (error) {
62 | return Promise.reject(error);
63 | }
64 |
65 | const args = target.getRunArgs().toString();
66 | const envVars = EnvVarsUtils.listToObject(target.getEnvVars().toStringArray());
67 |
68 | return {
69 | name: `${target.label} (Debug Python)`,
70 | type: 'python',
71 | request: 'launch',
72 | program: pythonFile, // Bazel-compiled runfile
73 | args: args.length > 0 ? args.split(' ') : [],
74 | pathMappings: [
75 | {
76 | localRoot: '${workspaceFolder}', // Directory containing the local source
77 | remoteRoot: '.' // Remote Bazel runfiles directory
78 | }
79 | ],
80 | stopOnEntry: false,
81 | cwd: '${workspaceFolder}',
82 | env: { ...EnvVarsUtils.listToObject(this.setupEnvVars), ...envVars },
83 | console: 'integratedTerminal',
84 | justMyCode: true
85 | } as vscode.DebugConfiguration;
86 | }
87 |
88 | public async createDebugAttachConfig(target: BazelTarget,
89 | port: number,
90 | _cancellationToken?: vscode.CancellationToken): Promise {
91 | return {
92 | name: `${target.label} (Attach)`,
93 | type: 'debugpy',
94 | request: 'attach',
95 | connect: {
96 | host: 'localhost',
97 | port: port // Port where debugpy is listening
98 | },
99 | pathMappings: [
100 | {
101 | localRoot: '${workspaceFolder}',
102 | remoteRoot: '.'
103 | }
104 | ],
105 | };
106 | }
107 |
108 | /**
109 | * Regex to match test functions in Python.
110 | * Example matches:
111 | * def test_function_name():
112 | * def test_another_function(param):
113 | */
114 | public getCodeLensTestRegex(): RegExp {
115 | return /(?:^|\s)def\s+(test_\w+)\(/gm;
116 | }
117 |
118 | /**
119 | * Regex to match main function definitions in Python.
120 | * Example matches:
121 | * def main():
122 | * def main(arg1, arg2):
123 | */
124 | public getCodeLensRunRegex(): RegExp {
125 | return /(?:^|\s)def\s+(main)\s*\(\s*\)/gm;
126 | }
127 |
128 | private findMainInRunfiles(runfilesPath: string): string {
129 | const files = fs.readdirSync(runfilesPath);
130 |
131 | for (const file of files) {
132 | const fullPath = path.join(runfilesPath, file);
133 | const stat = fs.statSync(fullPath);
134 | if (stat.isDirectory()) {
135 | try {
136 | // Recursively search subdirectories
137 | const mainFile = this.findMainInRunfiles(fullPath);
138 | if (mainFile) {
139 | return mainFile;
140 | }
141 | } catch (error) {
142 | // Continue searching other branches
143 | }
144 | } else if (file.endsWith('.py')) {
145 | // Check if the file contains `if __name__ == "__main__"`
146 | const content = fs.readFileSync(fullPath, 'utf-8');
147 | if (content.includes('if __name__ == "__main__"')) {
148 | Console.log(`Main function found in: ${fullPath}`);
149 | return fullPath;
150 | }
151 | }
152 | }
153 |
154 | // If no match found in this branch, throw an error
155 | throw new Error('No Python file with \'if __name__ == "__main__"\' found');
156 | }
157 |
158 |
159 | }
--------------------------------------------------------------------------------
/src/models/bazel-action-manager.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { BazelService } from '../services/bazel-service';
25 | import * as vscode from 'vscode';
26 |
27 | /**
28 | * Model for retrieving all possible commands in bazel.
29 | */
30 | export class BazelActionManager {
31 | private actions: string[] = [];
32 | private actionsPromise: Promise;
33 |
34 | constructor(private context: vscode.ExtensionContext,
35 | private readonly bazelService: BazelService,
36 | ) {
37 | this.actionsPromise = this.loadActions();
38 | }
39 |
40 | private async loadActions(): Promise {
41 | this.actions = await this.bazelService.fetchTargetActions();
42 | return this.actions;
43 | }
44 |
45 | public async getActions(): Promise {
46 | return this.actionsPromise;
47 | }
48 |
49 | public async refreshActions() {
50 | this.actions = await this.bazelService.fetchTargetActions();
51 | this.actionsPromise = Promise.resolve(this.actions);
52 | }
53 | }
--------------------------------------------------------------------------------
/src/models/bazel-environment.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { ConfigurationManager } from '../services/configuration-manager';
26 | import { EnvironmentService } from '../services/environment-service';
27 | import * as vscode from 'vscode';
28 | export class BazelEnvironment {
29 | private envVars: string[] = [];
30 |
31 | public static async create(context: vscode.ExtensionContext,
32 | configurationManager: ConfigurationManager,
33 | cancellationToken?: vscode.CancellationToken
34 | ): Promise {
35 | const instance = new BazelEnvironment();
36 | try {
37 | instance.envVars = await this.loadEnvVars(context, configurationManager, cancellationToken);
38 | return instance;
39 | } catch (error) {
40 | return Promise.reject(error);
41 | }
42 | }
43 |
44 | private static async loadEnvVars(context: vscode.ExtensionContext,
45 | configurationManager: ConfigurationManager,
46 | cancellationToken?: vscode.CancellationToken
47 | ): Promise {
48 | const result = EnvironmentService.fetchSetupEnvironment(context, configurationManager.getSetupEnvironmentCommand(), cancellationToken);
49 | context.workspaceState.update('setupEnvVars', result);
50 | return result;
51 | }
52 |
53 | // Methods to manage environment variables
54 | public getEnvVars(): string[] {
55 | return this.envVars;
56 | }
57 | }
--------------------------------------------------------------------------------
/src/models/bazel-target-multi-property.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { BazelTarget } from './bazel-target';
26 | import { BazelTargetPropertyHistory } from './bazel-target-property-history';
27 | import { v4 as uuidv4 } from 'uuid';
28 | import * as vscode from 'vscode';
29 |
30 | export class BazelTargetMultiPropertyItem {
31 | public readonly id: string;
32 | constructor(private readonly target: BazelTargetMultiProperty,
33 | public readonly label: string,
34 | id?: string
35 | ) {
36 | if (id === undefined) {
37 | this.id = uuidv4();
38 | } else {
39 | this.id = id;
40 | }
41 | }
42 |
43 | public remove() {
44 | this.target.remove(this);
45 | }
46 |
47 | public update(value: string) {
48 | this.target.replace(value, this);
49 | }
50 |
51 | public get(): string {
52 | return this.label;
53 | }
54 |
55 | public toJSON() {
56 | return {
57 | label: this.label,
58 | id: this.id
59 | };
60 | }
61 | }
62 | export class BazelTargetMultiProperty {
63 | public readonly id: string = '';
64 | private readonly history: BazelTargetPropertyHistory;
65 |
66 | constructor(
67 | private readonly context: vscode.ExtensionContext,
68 | public readonly label: string,
69 | public readonly name: string,
70 | target: BazelTarget,
71 | private readonly toStringFn: (bazelTargetProperty: BazelTargetMultiProperty) => string,
72 | private readonly availableValuesFn: (cancellationToken: vscode.CancellationToken) => Promise = (): Promise => { return Promise.resolve([]); },
73 | private readonly showHistory = true,
74 | ) {
75 | this.id = `${target.action}${name}For${target.id}`;
76 | this.history = new BazelTargetPropertyHistory(context, name, 10);
77 | }
78 |
79 | public clone(newTarget: BazelTarget): BazelTargetMultiProperty {
80 | const clonedProperty = new BazelTargetMultiProperty(
81 | this.context,
82 | this.label,
83 | this.name,
84 | newTarget, // Pass the new BazelTarget instance
85 | this.toStringFn,
86 | this.availableValuesFn,
87 | this.showHistory
88 | );
89 |
90 | // Copy all items
91 | const values = this.get().map(item => new BazelTargetMultiPropertyItem(clonedProperty, item.label));
92 | clonedProperty.update(values);
93 |
94 | return clonedProperty;
95 | }
96 |
97 | public add(value: string) {
98 | const values = this.get();
99 | values.push(new BazelTargetMultiPropertyItem(this, value));
100 | this.update(values);
101 | this.history.add(value);
102 | }
103 |
104 | public remove(item: BazelTargetMultiPropertyItem) {
105 | let values = this.get();
106 | values = values.filter(it => it.id !== item.id);
107 | this.update(values);
108 | }
109 |
110 | public replace(value: string, item: BazelTargetMultiPropertyItem) {
111 | let values = this.get();
112 | values = values.map(it => {
113 | if (it.id === item.id) {
114 | return new BazelTargetMultiPropertyItem(this, value, it.id);
115 | }
116 | return it;
117 | });
118 | this.history.add(value);
119 | this.update(values);
120 | }
121 |
122 | public update(values: BazelTargetMultiPropertyItem[]) {
123 | this.context.workspaceState.update(this.id, values);
124 | }
125 |
126 | public get(): BazelTargetMultiPropertyItem[] {
127 | const storedValues = this.context.workspaceState.get(this.id) || [];
128 |
129 | // Re-create BazelTargetMultiPropertyItem instances, passing 'this' as the reference
130 | const values = storedValues.map(value => new BazelTargetMultiPropertyItem(this, value.label, value.id));
131 | return values; // Return the re-instantiated items with references to 'this'
132 | }
133 |
134 | public shouldShowHistory(): boolean {
135 | return this.showHistory;
136 | }
137 |
138 | public getAvailableValues(cancellationToken: vscode.CancellationToken): Promise {
139 | return this.availableValuesFn(cancellationToken);
140 | }
141 |
142 | public getHistory(): string[] {
143 | return this.history.getHistory();
144 | }
145 |
146 | public toStringArray(): string[] {
147 | const values = this.get();
148 | const stringValues: string[] = [];
149 | values.forEach(item => {
150 | stringValues.push(item.get());
151 | });
152 | return stringValues;
153 | }
154 |
155 | public toString(): string {
156 | return this.toStringFn(this);
157 | }
158 | }
159 |
160 |
--------------------------------------------------------------------------------
/src/models/bazel-target-property-history.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import * as vscode from 'vscode';
26 | interface HistoryMap {
27 | [key: string]: string[]
28 | }
29 |
30 | export class BazelTargetPropertyHistory {
31 |
32 | private historyMap: HistoryMap = {};
33 | private readonly DEFAULT_TARGET: string = 'DEFAULT_TARGET';
34 | private readonly key: string;
35 | constructor(private readonly context: vscode.ExtensionContext,
36 | readonly name: string,
37 | readonly size: number) {
38 |
39 | this.key = `${name}History`;
40 | const res = this.context.workspaceState.get(this.key);
41 | if (res === undefined) {
42 | const newRes: HistoryMap = {};
43 | this.historyMap = newRes;
44 | this.context.workspaceState.update(this.key, this.historyMap);
45 | } else {
46 | this.historyMap = res;
47 | }
48 | }
49 |
50 | public getFirstHistoryItem(target?: string): string {
51 | target = target || this.DEFAULT_TARGET;
52 | const result = this.historyMap[target];
53 | if (result !== undefined && result.length > 0) {
54 | return result[0];
55 | }
56 | return '';
57 | }
58 |
59 | public getHistory(target?: string): string[] {
60 | target = target || this.DEFAULT_TARGET;
61 | if (this.historyMap[target] === undefined) {
62 | return [];
63 | }
64 | return this.historyMap[target];
65 | }
66 |
67 | public add(value: string, target?: string) {
68 | target = target || this.DEFAULT_TARGET;
69 | let history = this.historyMap[target];
70 | if (history === undefined) {
71 | history = [];
72 | }
73 |
74 | if (history.includes(value)) {
75 | // If this value is in the history, delete it, as we'll re-add it to the beginning.
76 | const index = history.indexOf(value);
77 | history.splice(index, 1);
78 | }
79 |
80 | history.unshift(value);
81 | // Remove the last element to keep history size reasonable.
82 | if (history.length > this.size) {
83 | history.pop();
84 | }
85 | this.historyMap[target] = history;
86 | this.context.workspaceState.update(this.key, this.historyMap);
87 | }
88 | }
--------------------------------------------------------------------------------
/src/models/bazel-target-property.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { BazelTarget } from './bazel-target';
26 | import { BazelTargetPropertyHistory } from './bazel-target-property-history';
27 | import * as vscode from 'vscode';
28 |
29 | export class BazelTargetProperty {
30 | public readonly id: string = '';
31 | private readonly history: BazelTargetPropertyHistory;
32 |
33 | constructor(
34 | private readonly context: vscode.ExtensionContext,
35 | public readonly label: string,
36 | public readonly name: string,
37 | target: BazelTarget,
38 | private readonly toStringFn: (bazelTargetProperty: BazelTargetProperty) => string
39 | ) {
40 | this.id = `${target.action}${name}For${target.id}`;
41 | this.history = new BazelTargetPropertyHistory(context, name, 10);
42 | }
43 |
44 | public clone(newTarget: BazelTarget): BazelTargetProperty {
45 | return new BazelTargetProperty(
46 | this.context,
47 | this.label,
48 | this.name,
49 | newTarget, // Pass the new BazelTarget instance
50 | this.toStringFn
51 | );
52 | }
53 |
54 | public update(value: string) {
55 | this.history.add(value);
56 | this.context.workspaceState.update(this.id, value);
57 | }
58 |
59 | public get(): string {
60 | const value = this.context.workspaceState.get(this.id) || '';
61 | return value;
62 | }
63 |
64 | public getHistory(): string[] {
65 | return this.history.getHistory();
66 | }
67 |
68 | public toString(): string {
69 | return this.toStringFn(this);
70 | }
71 | }
72 |
73 |
--------------------------------------------------------------------------------
/src/models/bazel-target-state-manager.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { BazelTarget } from './bazel-target';
26 | import { EventEmitter } from 'vscode';
27 |
28 | export enum BazelTargetState {
29 | Idle = 'idle',
30 | Executing = 'executing',
31 | Debugging = 'debugging'
32 | }
33 |
34 | export class BazelTargetStateManager {
35 | private targetStateMap: Map = new Map();
36 |
37 | // Event emitter to notify when target state changes
38 | private _onDidChangeTargetState: EventEmitter = new EventEmitter();
39 |
40 | // Event that consumers can subscribe to
41 | public readonly onDidChangeTargetState = this._onDidChangeTargetState.event;
42 |
43 | // Method to set the state of a target
44 | public setTargetState(target: BazelTarget, state: BazelTargetState): void {
45 | this.targetStateMap.set(target.id, state);
46 | // Emit event whenever the state is set
47 | this._onDidChangeTargetState.fire(target);
48 | }
49 |
50 | // Method to get the state of a target
51 | public getTargetState(target: BazelTarget): BazelTargetState {
52 | return this.targetStateMap.get(target.id) || BazelTargetState.Idle;
53 | }
54 | }
--------------------------------------------------------------------------------
/src/models/model-accessor.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { Model } from './model';
25 |
26 | export class ModelAccessor {
27 | public static getString(model: Model): string {
28 | const value = model.get();
29 | if (typeof value !== 'string') {
30 | return '';
31 | } else {
32 | return value;
33 | }
34 | }
35 |
36 | public static getWithDefault(model: Model, defaultValue?: T) {
37 | const value = model.get();
38 | if (value === undefined) {
39 | return defaultValue;
40 | }
41 | return value;
42 | }
43 |
44 | public static getStringArray(model: Model): string[] {
45 | const values = model.get();
46 | if (!values) {
47 | return [];
48 | }
49 | return values;
50 | }
51 | }
--------------------------------------------------------------------------------
/src/models/model.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | export interface Model {
26 | name: string;
27 | id: string;
28 | update(value: T): void;
29 | get(): T | undefined;
30 | }
--------------------------------------------------------------------------------
/src/models/workspace-state-manager.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { Console } from '../services/console';
26 | import { ExtensionUtils } from '../services/extension-utils';
27 | import * as vscode from 'vscode';
28 |
29 |
30 | export class WorkspaceStateManager {
31 | private versionChangeHappened = false;
32 | private majorVersionChangeHappened = false;
33 |
34 | constructor(private readonly context: vscode.ExtensionContext) {
35 | this.versionChangeHappened = this.checkVersionChange();
36 | this.majorVersionChangeHappened = this.checkVersionChange(true);
37 | }
38 |
39 |
40 | private checkVersionChange(majorVersionOnly = false): boolean {
41 | const version = ExtensionUtils.getExtensionVersion(this.context);
42 | const oldVersion = this.context.workspaceState.get('version', '');
43 | if (majorVersionOnly) {
44 | const majorOld = oldVersion.split('.')[0];
45 | const majorNew = version.split('.')[0];
46 | return majorOld !== majorNew;
47 | }
48 | return oldVersion !== version;
49 | }
50 |
51 | public versionChanged(): boolean {
52 | return this.versionChangeHappened;
53 | }
54 |
55 | public majorVersionChanged(): boolean {
56 | return this.majorVersionChangeHappened;
57 | }
58 |
59 | public refreshWorkspaceState() {
60 | if (this.majorVersionChanged()) {
61 | this.clearWorkspaceState();
62 | this.context.workspaceState.update('version', ExtensionUtils.getExtensionVersion(this.context));
63 | Console.info('Workspace state has been cleared due to major version bump.');
64 | }
65 | }
66 |
67 | private clearWorkspaceState() {
68 | const keys = this.context.workspaceState.keys();
69 | for (const key of keys) {
70 | this.context.workspaceState.update(key, undefined);
71 | }
72 | }
73 |
74 | public update(key: string, value: T) {
75 | this.context.workspaceState.update(key, value);
76 | }
77 |
78 | public get(key: string, defaultValue: T): T {
79 | return this.context.workspaceState.get(key, defaultValue);
80 | }
81 | }
--------------------------------------------------------------------------------
/src/services/bazel-rule-language-mapping.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | export const languageMapping: Map = new Map([
25 | // Go
26 | ['go_', 'go'],
27 |
28 | // Python
29 | ['py_', 'python'],
30 |
31 | // C and C++
32 | ['c_', 'c'],
33 | ['cc_', 'cpp'],
34 | ['cpp_', 'cpp'],
35 |
36 | // Java
37 | ['java_', 'java'],
38 |
39 | // JavaScript and TypeScript
40 | ['js_', 'javascript'],
41 | ['ts_', 'typescript'],
42 |
43 | // Scala
44 | ['scala_', 'scala'],
45 |
46 | // Protocol Buffers
47 | ['proto_', 'protobuf'],
48 |
49 | // Shell/Bash
50 | ['sh_', 'shellscript'],
51 |
52 | // JSON
53 | ['json_', 'json'],
54 |
55 | // HTML and CSS
56 | ['html_', 'html'],
57 | ['css_', 'css'],
58 |
59 | // Ruby
60 | ['rb_', 'ruby'],
61 |
62 | // PHP
63 | ['php_', 'php'],
64 |
65 | // Rust
66 | ['rs_', 'rust'],
67 |
68 | // Swift
69 | ['swift_', 'swift'],
70 |
71 | // Kotlin
72 | ['kt_', 'kotlin'],
73 | ['kts_', 'kotlin'],
74 |
75 | // Lua
76 | ['lua_', 'lua'],
77 |
78 | // SQL
79 | ['sql_', 'sql'],
80 |
81 | // Markdown
82 | ['md_', 'markdown'],
83 |
84 | // XML
85 | ['xml_', 'xml'],
86 |
87 | // Dart
88 | ['dart_', 'dart'],
89 |
90 | // Haskell
91 | ['hs_', 'haskell'],
92 |
93 | // Erlang
94 | ['erl_', 'erlang'],
95 | ['hrl_', 'erlang'],
96 |
97 | // Clojure
98 | ['clj_', 'clojure'],
99 | ['cljs_', 'clojure'],
100 |
101 | // R
102 | ['r_', 'r'],
103 |
104 | // Visual Basic
105 | ['vb_', 'vb'],
106 |
107 | // CoffeeScript
108 | ['coffee_', 'coffeescript'],
109 |
110 | // F#
111 | ['fsharp_', 'fsharp'],
112 |
113 | // Groovy
114 | ['groovy_', 'groovy'],
115 |
116 | // YAML
117 | ['yaml_', 'yaml'],
118 |
119 | // PowerShell
120 | ['powershell_', 'powershell'],
121 |
122 | // Batch Scripting
123 | ['batch_', 'bat'],
124 |
125 | // Makefile
126 | ['make_', 'makefile'],
127 |
128 | // Dockerfile
129 | ['docker_', 'dockerfile'],
130 |
131 | // Racket
132 | ['rkt_', 'racket'],
133 |
134 | // Lisp and Scheme
135 | ['lisp_', 'lisp'],
136 | ['scheme_', 'scheme'],
137 |
138 | // Vala
139 | ['vala_', 'vala'],
140 |
141 | // Objective-C and Objective-C++
142 | ['objc_', 'objective-c'],
143 | ['objcxx_', 'objective-cpp'],
144 |
145 | // Nim
146 | ['nim_', 'nim'],
147 |
148 | // Elixir
149 | ['elixir_', 'elixir'],
150 |
151 | // Haxe
152 | ['haxe_', 'haxe'],
153 |
154 | // Fortran
155 | ['fortran_', 'fortran'],
156 | ]);
157 |
158 | // Sort prefixes by length in descending order to prioritize longer, more specific prefixes
159 | export const sortedBazelRuleTypePrefixes: string[] = Array.from(languageMapping.keys()).sort((a, b) => b.length - a.length);
160 |
161 | export const extensionLanguageMapping: Map = new Map([
162 | // Go
163 | ['.go', 'go'],
164 |
165 | // Python
166 | ['.py', 'python'],
167 |
168 | // C and C++
169 | ['.c', 'c'],
170 | ['.cpp', 'cpp'],
171 | ['.cc', 'cpp'],
172 | ['.h', 'cpp'],
173 |
174 | // Java
175 | ['.java', 'java'],
176 |
177 | // JavaScript and TypeScript
178 | ['.js', 'javascript'],
179 | ['.jsx', 'javascript'],
180 | ['.ts', 'typescript'],
181 | ['.tsx', 'typescript'],
182 |
183 | // Scala
184 | ['.scala', 'scala'],
185 |
186 | // Protocol Buffers
187 | ['.proto', 'protobuf'],
188 |
189 | // Shell/Bash
190 | ['.sh', 'shellscript'],
191 |
192 | // JSON
193 | ['.json', 'json'],
194 |
195 | // HTML and CSS
196 | ['.html', 'html'],
197 | ['.css', 'css'],
198 |
199 | // Ruby
200 | ['.rb', 'ruby'],
201 |
202 | // PHP
203 | ['.php', 'php'],
204 |
205 | // Rust
206 | ['.rs', 'rust'],
207 |
208 | // Swift
209 | ['.swift', 'swift'],
210 |
211 | // Kotlin
212 | ['.kt', 'kotlin'],
213 | ['.kts', 'kotlin'],
214 |
215 | // Lua
216 | ['.lua', 'lua'],
217 |
218 | // SQL
219 | ['.sql', 'sql'],
220 |
221 | // Markdown
222 | ['.md', 'markdown'],
223 |
224 | // XML
225 | ['.xml', 'xml'],
226 |
227 | // Dart
228 | ['.dart', 'dart'],
229 |
230 | // Haskell
231 | ['.hs', 'haskell'],
232 |
233 | // Erlang
234 | ['.erl', 'erlang'],
235 | ['.hrl', 'erlang'],
236 |
237 | // Clojure
238 | ['.clj', 'clojure'],
239 | ['.cljs', 'clojure'],
240 |
241 | // R
242 | ['.r', 'r'],
243 |
244 | // Visual Basic
245 | ['.vb', 'vb'],
246 |
247 | // CoffeeScript
248 | ['.coffee', 'coffeescript'],
249 |
250 | // F#
251 | ['.fs', 'fsharp'],
252 |
253 | // Groovy
254 | ['.groovy', 'groovy'],
255 |
256 | // YAML
257 | ['.yaml', 'yaml'],
258 | ['.yml', 'yaml'],
259 |
260 | // PowerShell
261 | ['.ps1', 'powershell'],
262 |
263 | // Batch Scripting
264 | ['.bat', 'bat'],
265 |
266 | // Makefile
267 | ['Makefile', 'makefile'],
268 |
269 | // Dockerfile
270 | ['Dockerfile', 'dockerfile'],
271 |
272 | // Racket
273 | ['.rkt', 'racket'],
274 |
275 | // Lisp and Scheme
276 | ['.lisp', 'lisp'],
277 | ['.scm', 'scheme'],
278 |
279 | // Vala
280 | ['.vala', 'vala'],
281 |
282 | // Objective-C and Objective-C++
283 | ['.m', 'objective-c'],
284 | ['.mm', 'objective-cpp'],
285 |
286 | // Nim
287 | ['.nim', 'nim'],
288 |
289 | // Elixir
290 | ['.ex', 'elixir'],
291 | ['.exs', 'elixir'],
292 |
293 | // Haxe
294 | ['.hx', 'haxe'],
295 |
296 | // Fortran
297 | ['.f90', 'fortran'],
298 | ['.f95', 'fortran'],
299 | ['.for', 'fortran'],
300 | ]);
301 |
--------------------------------------------------------------------------------
/src/services/configuration-utils.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { Console } from './console';
25 | import { ExtensionUtils } from './extension-utils';
26 | import * as fs from 'fs';
27 | import * as path from 'path';
28 | import * as vscode from 'vscode';
29 | import { workspace, WorkspaceConfiguration } from 'vscode';
30 |
31 | export function getExtensionDefaultSettings(extensionName: string): JSON {
32 | const workspaceFolders = vscode.workspace.workspaceFolders;
33 | if (!workspaceFolders) {
34 | Console.error('No workspace folder found.');
35 | return JSON.parse('{}');
36 | }
37 |
38 | const defaultSettings = [];
39 | for (const folder of workspaceFolders) {
40 | const rootPath = folder.uri.fsPath;
41 |
42 | // Construct the path to the .vscode directory
43 | const defaultSettingsPath = path.join(rootPath, '.vscode', `${extensionName}.json`);
44 |
45 | // If this default settings file does not exist,
46 | // skip this workspace folder.
47 | if (!fs.existsSync(defaultSettingsPath)) {
48 | continue;
49 | }
50 |
51 | try {
52 | const fileContent = fs.readFileSync(defaultSettingsPath, 'utf8');
53 | defaultSettings.push(JSON.parse(fileContent));
54 | } catch (error) {
55 | Console.error('Failed to parse default settings', error);
56 | }
57 | }
58 |
59 |
60 | // Assign the array to a dictionary
61 | const contents = Object.assign({}, ...defaultSettings);
62 | const keyPrefix = `${extensionName}.`;
63 | // Remove the extension name from the front of every key
64 | Object.keys(contents).forEach((oldKey) => {
65 | // Remove the extension name from the prefix of the settings
66 | if (oldKey.includes(keyPrefix)) {
67 | const newKey = oldKey.replace(keyPrefix, '');
68 | contents[newKey] = contents[oldKey];
69 | }
70 | delete contents[oldKey];
71 | });
72 |
73 | // Return the settings as a key-value paired object
74 | return contents;
75 | }
76 |
77 | export class MergedConfiguration implements WorkspaceConfiguration {
78 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
79 | private defaultConfig: any;
80 | constructor(private readonly context: vscode.ExtensionContext,
81 | defaultConfig: JSON) {
82 | // Additional initialization if needed
83 | this.defaultConfig = defaultConfig;
84 | }
85 |
86 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
87 | readonly [key: string]: any;
88 |
89 | has(section: string): boolean {
90 | return this.getUserSettings().has(section) || section in this.defaultConfig;
91 | }
92 |
93 | inspect(section: string): { key: string; defaultValue?: T | undefined; globalValue?: T | undefined; workspaceValue?: T | undefined; workspaceFolderValue?: T | undefined; defaultLanguageValue?: T | undefined; globalLanguageValue?: T | undefined; workspaceLanguageValue?: T | undefined; workspaceFolderLanguageValue?: T | undefined; languageIds?: string[] | undefined; } | undefined {
94 | return this.getUserSettings().inspect(section);
95 | }
96 |
97 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
98 | update(section: string, value: any, configurationTarget?: boolean | vscode.ConfigurationTarget | undefined, overrideInLanguage?: boolean | undefined): Thenable {
99 | return this.getUserSettings().update(section, value, configurationTarget, overrideInLanguage);
100 | }
101 |
102 | get(section: string, defaultValue?: T): T | undefined {
103 | const settingValue = this.getUserSettings().get(section);
104 | const settingsInspection = this.getUserSettings().inspect(section);
105 | const isModifiedByUser = settingValue !== undefined &&
106 | (settingsInspection?.globalValue !== undefined ||
107 | settingsInspection?.workspaceFolderValue !== undefined ||
108 | settingsInspection?.workspaceValue !== undefined);
109 | if (isModifiedByUser) {
110 | return settingValue;
111 | } else if (section in this.defaultConfig) {
112 | return this.defaultConfig[section] as T;
113 | } else if (defaultValue) {
114 | return defaultValue;
115 | } else {
116 | return settingValue;
117 | }
118 | }
119 |
120 | getUserSettings(): WorkspaceConfiguration {
121 | const extensionName = ExtensionUtils.getExtensionName(this.context);
122 | return workspace.getConfiguration(extensionName);
123 | }
124 | }
--------------------------------------------------------------------------------
/src/services/console.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { ExtensionUtils } from './extension-utils';
25 | import * as vscode from 'vscode';
26 |
27 | export class Console {
28 | // Static instance for singleton pattern
29 | private static instance: Console;
30 |
31 | private readonly prefix: string;
32 | private constructor(context: vscode.ExtensionContext) {
33 | this.prefix = `[${ExtensionUtils.getExtensionName(context)}]`;
34 | }
35 |
36 | // Initialize the singleton instance with the context (to be called once in extension activate)
37 | public static initialize(context: vscode.ExtensionContext): void {
38 | if (!Console.instance) {
39 | Console.instance = new Console(context);
40 | }
41 | }
42 |
43 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
44 | public static log(message?: any, ...optionalParams: any[]) {
45 | console.log(Console.instance.prefix, message, ...optionalParams);
46 | }
47 |
48 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
49 | public static info(message?: any, ...optionalParams: any[]) {
50 | console.info(Console.instance.prefix, message, ...optionalParams);
51 | }
52 |
53 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
54 | public static warn(message?: any, ...optionalParams: any[]) {
55 | console.warn(Console.instance.prefix, message, ...optionalParams);
56 | }
57 |
58 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
59 | public static error(message?: any, ...optionalParams: any[]) {
60 | console.error(Console.instance.prefix, message, ...optionalParams);
61 | }
62 |
63 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
64 | public static debug(message?: any, ...optionalParams: any[]) {
65 | console.debug(Console.instance.prefix, message, ...optionalParams);
66 | }
67 |
68 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
69 | public static time(message?: any) {
70 | console.time(`${Console.instance.prefix} ${message}`);
71 | }
72 |
73 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
74 | public static timeEnd(message?: any) {
75 | console.timeEnd(`${Console.instance.prefix} ${message}`);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/services/env-vars-utils.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | export class EnvVarsUtils {
26 | /**
27 | * Converts a list of environement variables into a list of objects.
28 | * @param envVars A list of environment variables in the form of ['A=first', 'B=second', ...].
29 | * @returns A list of objects in the form of [{name: 'A', value: 'first}, {name: 'B', value: 'second'}, ...].
30 | */
31 | public static listToArrayOfObjects(envVars: string[]): Array<{ name: string; value: string }> {
32 | const vars: Array<{ name: string; value: string }> = [];
33 |
34 | envVars.forEach((item) => {
35 | const index = item.indexOf('=');
36 | if (index !== -1) {
37 | const name = item.substring(0, index); // Everything before the first '=' is the name
38 | const value = item.substring(index + 1); // Everything after the first '=' is the value
39 | const nameValuePair = {
40 | name: name,
41 | value: value
42 | };
43 | vars.push(nameValuePair);
44 | }
45 | });
46 |
47 | return vars;
48 | }
49 |
50 |
51 | /**
52 | * Converts a list of environment variables into an object literal or a map.
53 | * @param envVars A list of environment variables in the form of ['A=first', 'B=second', ...].
54 | * @returns An object literal or map in the form of {A: 'first', B: 'second', ...}.
55 | */
56 | public static listToObject(envVars: string[]): { [key: string]: string } {
57 | const envVariables: { [key: string]: string } = {};
58 |
59 | envVars.forEach((item) => {
60 | const index = item.indexOf('=');
61 | if (index !== -1) {
62 | const key = item.substring(0, index);
63 | const value = item.substring(index + 1); // Capture everything after the first '=' as the value
64 | envVariables[key] = value;
65 | }
66 | });
67 |
68 | return envVariables;
69 | }
70 |
71 | /**
72 | * Converts a list of environment variables into bazel speific build environment variables.
73 | * @param envVars A list of environment variables in the form of ['A=first', 'B=second', ...].
74 | * @returns A concatenated string of all the environment variables suitable for bazel build args
75 | * in the form of '--action_env=A=first --action_env=B=second --action_env=...'.
76 | */
77 | public static toBuildEnvVars(envVars: string[]): string {
78 | let vars = '';
79 | const set = envVars;
80 | set.forEach((value) => {
81 | vars += `--action_env=${value} `;
82 | });
83 | return vars;
84 | }
85 |
86 | /**
87 | * Converts a list of environment variables into run environment variables.
88 | * @param envVars A list of environment variables in the form of ['A=first', 'B=second', ...].
89 | * @returns A concatenated string of all the environment variables suitable for run args
90 | * in the form of 'export A=first && export B=second && export ...'.
91 | */
92 | public static toRunEnvVars(envVars: string[]): string {
93 | let vars = '';
94 | const set = envVars;
95 | set.forEach((value) => {
96 | vars += `export ${value} && `;
97 | });
98 |
99 | return vars;
100 | }
101 |
102 | /**
103 | * Converts a list of environment variables into bazel speific test environment variables.
104 | * @param envVars A list of environment variables in the form of ['A=first', 'B=second', ...].
105 | * @returns A concatenated string of all the environment variables suitable for bazel test args
106 | * in the form of '--test_env=A=first --test_env=B=second --test_env=...'.
107 | */
108 | public static toTestEnvVars(envVars: string[]): string {
109 | let vars = '';
110 | const set = envVars;
111 | set.forEach((value) => {
112 | vars += `--test_env=${value} `;
113 | });
114 | return vars;
115 | }
116 | }
--------------------------------------------------------------------------------
/src/services/environment-service.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { Console } from './console';
26 | import { ExtensionUtils } from './extension-utils';
27 | import { ShellService } from './shell-service';
28 | import { WorkspaceService } from './workspace-service';
29 | import * as vscode from 'vscode';
30 |
31 |
32 | export class EnvironmentService {
33 |
34 | public static async fetchSetupEnvironment(
35 | context: vscode.ExtensionContext,
36 | envSetupCommand: string,
37 | cancellationToken?: vscode.CancellationToken
38 | ): Promise {
39 | const extName = ExtensionUtils.getExtensionName(context);
40 | const envDelimiter = `---${extName} setup---`;
41 |
42 | if (envSetupCommand) {
43 | try {
44 | // Run the setup command, ensuring it prints the environment variables
45 | const result = await ShellService.run(
46 | `${envSetupCommand} && echo ${envDelimiter} && env`,
47 | WorkspaceService.getInstance().getWorkspaceFolder().uri.path,
48 | {},
49 | cancellationToken
50 | );
51 |
52 | // Remove everything before the delimiter, then split the output by newlines
53 | const env = result.stdout
54 | .replace(new RegExp(`[\\s\\S]*?${envDelimiter}\n`, 'g'), '')
55 | .split('\n');
56 |
57 | const envArray: string[] = [];
58 | let currentVariable = '';
59 |
60 | for (const line of env) {
61 | // Look for the first '=' to avoid issues with values containing '='
62 | const index = line.indexOf('=');
63 | if (index !== -1) {
64 | if (currentVariable) {
65 | envArray.push(currentVariable); // Push previous variable
66 | }
67 | currentVariable = line; // Start new variable
68 | } else if (currentVariable) {
69 | // Handle case where the variable is spread over multiple lines (unlikely for environment variables)
70 | currentVariable += `\n${line}`;
71 | }
72 | }
73 |
74 | // Push the last variable
75 | if (currentVariable) {
76 | envArray.push(currentVariable);
77 | }
78 |
79 | return envArray;
80 | } catch (error) {
81 | // Log the error for debugging purposes
82 | Console.error('Error fetching setup environment:', error);
83 | return Promise.reject(error);
84 | }
85 | }
86 |
87 | // Return an empty array if no setup command is provided
88 | return [];
89 | }
90 |
91 | }
--------------------------------------------------------------------------------
/src/services/extension-utils.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import * as vscode from 'vscode';
25 |
26 | /**
27 | * Utility class for retrieving extension-specific information.
28 | */
29 | export class ExtensionUtils {
30 | /**
31 | * Gets the name of the extension dynamically.
32 | * @param context The extension context.
33 | * @returns The extension name.
34 | */
35 | public static getExtensionName(context: vscode.ExtensionContext): string {
36 | return context.extension.packageJSON.name;
37 | }
38 |
39 | public static getExtensionDisplayName(context: vscode.ExtensionContext): string {
40 | return context.extension.packageJSON.displayName;
41 | }
42 |
43 | public static getPublisherName(context: vscode.ExtensionContext): string {
44 | return context.extension.packageJSON.publisher;
45 | }
46 |
47 | public static getExtensionVersion(context: vscode.ExtensionContext): string {
48 | return context.extension.packageJSON.version;
49 | }
50 |
51 | }
--------------------------------------------------------------------------------
/src/services/file-watcher-service.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import * as vscode from 'vscode';
26 |
27 | export class FileWatcherService {
28 | private watchers: vscode.FileSystemWatcher[] = [];
29 | private allAffectedFiles = new Set(); // Preserve all affected files globally
30 |
31 | constructor(private context: vscode.ExtensionContext) {}
32 |
33 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
34 | private static debounce void>(func: T, wait: number): T {
35 | let timeout: NodeJS.Timeout;
36 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
37 | return ((...args: any[]) => {
38 | clearTimeout(timeout);
39 | timeout = setTimeout(() => func(...args), wait);
40 | }) as T;
41 | }
42 |
43 | /**
44 | * Adds a watcher for a specific file pattern and fires a single event with affected file names when any matching files are created, updated, or deleted.
45 | * @param pattern Glob pattern to match files
46 | * @param onFilesChanged Callback triggered when any files matching the pattern are created, changed, or deleted.
47 | */
48 | public watch(
49 | pattern: string,
50 | onFilesChanged: (affectedFiles: string[]) => void
51 | ): void {
52 | // Debounced callback to process the collected file paths
53 | const processEvents = FileWatcherService.debounce(() => {
54 | if (this.allAffectedFiles.size > 0) {
55 | onFilesChanged(Array.from(this.allAffectedFiles)); // Pass all files
56 | this.allAffectedFiles.clear(); // Clear after processing
57 | }
58 | }, 500);
59 |
60 | const watcher = vscode.workspace.createFileSystemWatcher(pattern);
61 |
62 | // Collect affected files for each event and ensure they persist across debounce calls
63 | const addAffectedFile = (uri: vscode.Uri) => {
64 | this.allAffectedFiles.add(uri.fsPath); // Add to global set
65 | processEvents(); // Trigger the debounced callback
66 | };
67 |
68 | watcher.onDidCreate(addAffectedFile, this.context.subscriptions);
69 | watcher.onDidChange(addAffectedFile, this.context.subscriptions);
70 | watcher.onDidDelete(addAffectedFile, this.context.subscriptions);
71 |
72 | this.watchers.push(watcher);
73 | this.context.subscriptions.push(watcher);
74 | }
75 |
76 | /**
77 | * Disposes of all file watchers to release resources.
78 | */
79 | public dispose(): void {
80 | this.watchers.forEach((watcher) => watcher.dispose());
81 | this.watchers = [];
82 | }
83 | }
84 |
85 |
--------------------------------------------------------------------------------
/src/services/icon-service.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import * as fs from 'fs';
26 | import * as os from 'os';
27 | import * as path from 'path';
28 | import * as vscode from 'vscode';
29 |
30 | type IconDefinition = {
31 | iconPath?: string;
32 | fontCharacter?: string;
33 | fontColor?: string;
34 | fontSize?: string;
35 | fontId?: string;
36 | };
37 |
38 | type IconTheme = {
39 | iconDefinitions: { [key: string]: IconDefinition };
40 | fileExtensions?: { [key: string]: string };
41 | fileNames?: { [key: string]: string };
42 | languageIds?: { [key: string]: string };
43 | };
44 |
45 | /**
46 | * Service to handle icon theme parsing and retrieval.
47 | */
48 | export class IconService {
49 | private iconTheme: IconTheme | null = null;
50 | private iconThemePath: string | undefined;
51 |
52 | constructor() {
53 | this.loadIconTheme();
54 | }
55 |
56 | /**
57 | * Load and parse the active icon theme.
58 | */
59 | private async loadIconTheme() {
60 | const iconThemeId = vscode.workspace.getConfiguration('workbench').get('iconTheme') as string | undefined;
61 | if (!iconThemeId) {
62 | return Promise.reject(new Error('No icon theme found'));
63 | }
64 |
65 | // Define potential paths for finding the active icon theme
66 | const searchPaths = [
67 | path.join(vscode.env.appRoot, 'extensions'), // Built-in extensions in VSCode app root
68 | path.join(os.homedir(), '.vscode', 'extensions'), // User's extensions folder
69 | path.join(os.homedir(), '.vscode-server', 'extensions'), // VSCode server for remote
70 | path.join(os.homedir(), '.vscode-oss', 'extensions') // OSS version of VSCode
71 | ];
72 |
73 | // Try to find the theme in each search path
74 |
75 | for (const searchPath of searchPaths) {
76 | this.iconThemePath = this.findIconThemeFile(searchPath, iconThemeId);
77 | if (this.iconThemePath) {
78 | break;
79 | }
80 | }
81 |
82 | if (!this.iconThemePath) {
83 | return Promise.reject(new Error('No icon theme path found'));
84 | }
85 |
86 | try {
87 | // Read and parse the icon theme JSON file
88 | const themeContent = await fs.promises.readFile(this.iconThemePath, 'utf-8');
89 | this.iconTheme = JSON.parse(themeContent) as IconTheme;
90 | } catch (error) {
91 | return Promise.reject(error);
92 | }
93 | }
94 |
95 | /**
96 | * Get the icon path for a given language.
97 | * @param language The language ID (e.g., 'typescript', 'javascript').
98 | * @returns The icon path or undefined if not found.
99 | */
100 | public getIcon(language?: string): string | undefined {
101 | if (!this.iconTheme) {
102 | return undefined;
103 | }
104 |
105 | const iconPath = path.dirname(this.iconThemePath || '');
106 |
107 | if (language !== undefined) {
108 | // Check for the language ID icon
109 | const iconId = this.iconTheme.languageIds?.[language];
110 | if (iconId && this.iconTheme.iconDefinitions[iconId]) {
111 | return path.join(iconPath, this.iconTheme.iconDefinitions[iconId].iconPath || '');
112 | }
113 | } else {
114 | // Check for the special case where language is not defined
115 | const folderIconId = this.iconTheme.iconDefinitions?._folder;
116 | if (folderIconId) {
117 | return path.join(iconPath, this.iconTheme.iconDefinitions['_folder'].iconPath || '');
118 | }
119 | }
120 |
121 | // Fallback to default file icon
122 | const defaultIcon = this.iconTheme.iconDefinitions['_file'];
123 | return path.join(iconPath, defaultIcon?.iconPath || '');
124 | }
125 |
126 | /**
127 | * Recursively finds the icon theme file in a given directory.
128 | * @param dirPath The directory to search in.
129 | * @param themeId The ID of the theme to look for.
130 | * @returns The path to the icon theme file if found, otherwise undefined.
131 | */
132 | private findIconThemeFile(dirPath: string, themeId: string): string | undefined {
133 | if (!fs.existsSync(dirPath)) {
134 | return undefined;
135 | }
136 |
137 | const files = fs.readdirSync(dirPath, { withFileTypes: true });
138 | for (const file of files) {
139 | const fullPath = path.join(dirPath, file.name);
140 |
141 | if (file.isDirectory()) {
142 | // Only continue searching if the themeId is in the directory path
143 | if (fullPath.includes(themeId)) {
144 | const iconThemeFile = this.findIconThemeFile(fullPath, themeId);
145 | if (iconThemeFile) {
146 | return iconThemeFile;
147 | }
148 | }
149 | } else if (
150 | file.isFile() &&
151 | file.name.includes('icon-theme') &&
152 | file.name.endsWith('.json')
153 | ) {
154 | return fullPath;
155 | }
156 | }
157 | return undefined;
158 | }
159 |
160 | }
161 |
--------------------------------------------------------------------------------
/src/services/network-utils.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import * as net from 'net';
26 | import * as vscode from 'vscode';
27 |
28 | export async function getAvailablePort(cancellationToken?: vscode.CancellationToken): Promise {
29 | return new Promise((resolve, reject) => {
30 | const server = net.createServer();
31 | // Handle cancellation
32 | if (cancellationToken) {
33 | const disposable = cancellationToken.onCancellationRequested(() => {
34 | server.close();
35 | disposable.dispose();
36 | reject(new Error('Operation cancelled'));
37 | });
38 | }
39 |
40 | // Let the OS assign an available port by listening on port 0
41 | server.listen(0, '127.0.0.1', () => {
42 | const address = server.address();
43 | if (address && typeof address === 'object') {
44 | const port = address.port;
45 | server.close((err) => {
46 | if (err) {
47 | reject(err);
48 | } else {
49 | resolve(port);
50 | }
51 | });
52 | } else {
53 | reject(new Error('Failed to get server address'));
54 | }
55 | });
56 |
57 | server.on('error', (err) => {
58 | reject(err);
59 | });
60 | });
61 | }
62 |
63 | function checkPortAvailable(port: number, host: string): Promise {
64 | return new Promise((resolve, reject) => {
65 | // Create a server instead of a client connection
66 | const server = net.createServer();
67 |
68 | server.once('error', (err: NodeJS.ErrnoException) => {
69 | server.close();
70 |
71 | if (err.code === 'EADDRINUSE') {
72 | // Port is in use, which means the debug server is likely running
73 | resolve();
74 | } else {
75 | reject(err);
76 | }
77 | });
78 |
79 | server.once('listening', () => {
80 | // If we can listen, the port is free (debug server isn't running yet)
81 | server.close();
82 | reject(new Error('Port is not in use'));
83 | });
84 |
85 | // Try to bind to the port
86 | server.listen(port, host);
87 | });
88 | }
89 |
90 |
91 | export async function waitForPort(
92 | port: number,
93 | cancellationToken: vscode.CancellationToken,
94 | pollingIntervalMs = 50,
95 | host = '127.0.0.1',
96 | ): Promise {
97 |
98 | while (!cancellationToken.isCancellationRequested) {
99 | try {
100 | await checkPortAvailable(port, host);
101 | return; // Port is listening
102 | } catch (error) {
103 | // Port is not available yet, wait for the interval
104 | await new Promise((resolve) => setTimeout(resolve, pollingIntervalMs));
105 | }
106 | }
107 |
108 | // If the cancellation was requested, throw an error or simply return
109 | throw new Error(`Waiting for port ${port} was cancelled.`);
110 | }
111 |
112 | export function isRemoteSession(): boolean {
113 | return vscode.env.remoteName !== undefined;
114 | }
115 |
--------------------------------------------------------------------------------
/src/services/shell-service.ts:
--------------------------------------------------------------------------------
1 |
2 | ////////////////////////////////////////////////////////////////////////////////////
3 | // MIT License
4 | //
5 | // Copyright (c) 2021-2024 NVIDIA Corporation
6 | //
7 | // Permission is hereby granted, free of charge, to any person obtaining a copy
8 | // of this software and associated documentation files (the "Software"), to deal
9 | // in the Software without restriction, including without limitation the rights
10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the Software is
12 | // furnished to do so, subject to the following conditions:
13 | //
14 | // The above copyright notice and this permission notice shall be included in all
15 | // copies or substantial portions of the Software.
16 | //
17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | // SOFTWARE.
24 | ////////////////////////////////////////////////////////////////////////////////////
25 |
26 | import * as child from 'child_process';
27 | import * as vscode from 'vscode';
28 |
29 | export interface ProcessOutput {
30 | stdout: string,
31 | stderr: string,
32 | exitCode: number
33 | }
34 |
35 | export class ShellService {
36 |
37 | constructor(private readonly workspaceFolder: vscode.WorkspaceFolder,
38 | private readonly outputChannel: vscode.OutputChannel,
39 | private readonly setupEnvVars: {[key: string]: string}
40 | ) { }
41 |
42 | public static async run(
43 | cmd: string,
44 | cwd: string,
45 | setupEnvVars: { [key: string]: string },
46 | cancellationToken?: vscode.CancellationToken,
47 | outputChannel?: vscode.OutputChannel
48 | ): Promise {
49 | return new Promise((resolve, reject) => {
50 | const execOptions: child.ExecOptions = {
51 | cwd: cwd,
52 | shell: 'bash',
53 | maxBuffer: Number.MAX_SAFE_INTEGER,
54 | windowsHide: false,
55 | env: { ...process.env, ...setupEnvVars }
56 | };
57 |
58 | const proc = child.exec(cmd, execOptions);
59 |
60 | let stdout = '';
61 | let stderr = '';
62 |
63 | // Capture stdout line-by-line
64 | proc.stdout?.on('data', (data: string) => {
65 | stdout += data;
66 | const lines = data.split('\n'); // Split the incoming data into lines
67 | lines.forEach(line => {
68 | if (outputChannel) {
69 | outputChannel.appendLine(line); // Append each line to the output channel
70 | }
71 | });
72 | });
73 |
74 | // Capture stderr line-by-line
75 | proc.stderr?.on('data', (data: string) => {
76 | stderr += data;
77 | const lines = data.split('\n'); // Split the incoming data into lines
78 | lines.forEach(line => {
79 | if (outputChannel) {
80 | outputChannel.appendLine(line); // Append each line to the output channel
81 | }
82 | });
83 | });
84 |
85 | proc.on('close', (code) => {
86 | if (code !== 0) {
87 | reject(new Error(`Error running ${cmd} exited with code: ${code}`));
88 | }
89 | resolve({ stdout: stdout.trim(), stderr: stderr.trim(), exitCode: code || 0 });
90 | });
91 |
92 | // Handle process errors
93 | proc.on('error', (err) => {
94 | reject(err);
95 | });
96 |
97 | // Handle cancellation
98 | if (cancellationToken) {
99 | cancellationToken.onCancellationRequested(() => {
100 | proc.kill();
101 | reject(new Error(`${cmd} cancelled.`));
102 | });
103 | }
104 | });
105 | }
106 |
107 | public async runShellCommand(cmd: string, cancellationToken?: vscode.CancellationToken): Promise<{ stdout: string, stderr: string }> {
108 | return ShellService.run(cmd, this.workspaceFolder.uri.path, this.setupEnvVars, cancellationToken, this.outputChannel);
109 | }
110 | }
--------------------------------------------------------------------------------
/src/services/string-utils.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | export function cleanAndFormat(...args: string[]): string {
26 | return args
27 | .filter(arg => arg.trim() !== '') // Remove empty or whitespace-only strings
28 | .map(arg => arg.trim()) // Trim spaces from each string
29 | .join(' '); // Join the cleaned parts with a single space
30 | }
31 |
32 | export function capitalizeFirstLetter(str: string): string {
33 | if (str === undefined) {
34 | return '';
35 | }
36 |
37 | if (str.length < 1) {
38 | return str;
39 | }
40 | return str.charAt(0).toUpperCase() + str.slice(1);
41 | }
42 |
43 | export function createHashFromIds(elements: { id: string }[]): string {
44 | // Combine all IDs into a single string
45 | const combinedIds = elements.map(element => element.id).join(',');
46 |
47 | // Generate a simple hash using a checksum approach
48 | let hash = 0;
49 | for (let i = 0; i < combinedIds.length; i++) {
50 | const char = combinedIds.charCodeAt(i);
51 | hash = (hash << 5) - hash + char; // Bitwise operations for hashing
52 | hash |= 0; // Convert to 32-bit integer
53 | }
54 |
55 | // Convert the hash to a hexadecimal string
56 | return hash.toString(16);
57 | }
--------------------------------------------------------------------------------
/src/services/task-service.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { EnvVarsUtils } from './env-vars-utils';
26 | import { ExtensionUtils } from './extension-utils';
27 | import { clearTerminal } from '../ui/terminal';
28 | import * as vscode from 'vscode';
29 |
30 |
31 | export class CustomTaskProvider implements vscode.TaskProvider {
32 | static readonly type = 'bluebazelTask';
33 | private tasks: vscode.Task[] = [];
34 |
35 | provideTasks(): vscode.Task[] {
36 | return this.tasks;
37 | }
38 |
39 | resolveTask(task: vscode.Task): vscode.Task | undefined {
40 | const definition = task.definition as { type: string; label: string };
41 | if (definition.type === CustomTaskProvider.type) {
42 | return task;
43 | }
44 | return undefined;
45 | }
46 | }
47 |
48 | export class TaskService {
49 |
50 | constructor(private readonly context: vscode.ExtensionContext,
51 | private readonly workspaceFolder: vscode.WorkspaceFolder,
52 | private readonly setupEnvVars: string[]) {
53 | const customTaskProvider = vscode.tasks.registerTaskProvider(CustomTaskProvider.type, new CustomTaskProvider());
54 | context.subscriptions.push(customTaskProvider);
55 | }
56 |
57 |
58 | public async runTask(taskName: string,
59 | command: string,
60 | clearTerminalFirst: boolean,
61 | cancellationToken?: vscode.CancellationToken,
62 | id = '',
63 | envVars: { [key: string]: string } = {},
64 | executionType: 'shell' | 'process' = 'shell',
65 | resolveOn: 'onDidStartTask' | 'onDidEndTask' = 'onDidEndTask',
66 | problemMatcher = '$gcc') {
67 | const workspaceFolder = this.workspaceFolder;
68 |
69 | const envVarsObj = { ...EnvVarsUtils.listToObject(this.setupEnvVars), ...envVars };
70 | let execution: vscode.ShellExecution | vscode.ProcessExecution | vscode.CustomExecution;
71 | if (executionType === 'shell') {
72 | execution = new vscode.ShellExecution(command, {
73 | cwd: workspaceFolder.uri.path, env: envVarsObj,
74 | executable: '/bin/bash', // Ensure bash is used as the shell
75 | shellArgs: ['-c'] });
76 | } else {
77 | const args = command.split(' ');
78 | execution = new vscode.ProcessExecution(args[0], args.slice(1), { cwd: workspaceFolder.uri.path, env: envVarsObj });
79 | }
80 |
81 | // const taskType = `${CustomTaskProvider.type}-${taskName}-${id}`; // Dynamically set the task type
82 | const taskType = CustomTaskProvider.type;
83 | const definition = {
84 | type: taskType,
85 | label: taskName,
86 | id: id
87 | };
88 | const task = new vscode.Task(
89 | definition,
90 | workspaceFolder,
91 | taskName,
92 | ExtensionUtils.getExtensionDisplayName(this.context),
93 | execution,
94 | problemMatcher // Adjust this as necessary
95 | );
96 |
97 | task.presentationOptions = {
98 | reveal: vscode.TaskRevealKind.Always,
99 | panel: vscode.TaskPanelKind.Dedicated
100 | };
101 | if (clearTerminalFirst) {
102 | clearTerminal();
103 | }
104 |
105 | const taskExecution = await vscode.tasks.executeTask(task);
106 |
107 | return new Promise((resolve, reject) => {
108 | // if (resolveOn === 'onDidEndTask') {
109 | const disposable = vscode.tasks.onDidEndTask(e => {
110 | if (e.execution === taskExecution) {
111 | disposable.dispose();
112 | resolve(e.execution);
113 | }
114 | });
115 | // }
116 | if (resolveOn === 'onDidStartTask') {
117 | const disposable = vscode.tasks.onDidStartTask(e => {
118 | if (e.execution === taskExecution) {
119 | disposable.dispose();
120 | resolve(e.execution);
121 | }
122 | });
123 | }
124 |
125 | cancellationToken?.onCancellationRequested(() => {
126 | taskExecution.terminate();
127 | reject(new Error(`${taskName} cancelled.`));
128 | });
129 | });
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/src/services/workspace-service.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import * as fs from 'fs';
26 | import * as path from 'path';
27 | import * as vscode from 'vscode';
28 |
29 | export class WorkspaceService {
30 | // Static instance for singleton pattern
31 | private static instance: WorkspaceService;
32 |
33 | // Cached workspace folder
34 | private workspaceFolder: vscode.WorkspaceFolder;
35 |
36 | // Private constructor to prevent direct instantiation
37 | private constructor() {
38 | this.workspaceFolder = this.initializeWorkspaceFolder();
39 | }
40 |
41 | // Static method to get the singleton instance
42 | public static getInstance(): WorkspaceService {
43 | if (!WorkspaceService.instance) {
44 | WorkspaceService.instance = new WorkspaceService();
45 | }
46 | return WorkspaceService.instance;
47 | }
48 |
49 | // Method to initialize and cache the workspace folder
50 | private initializeWorkspaceFolder(): vscode.WorkspaceFolder {
51 | const paths = vscode.workspace.workspaceFolders;
52 | if (paths && paths.length > 0) {
53 | return paths[0];
54 | } else {
55 | vscode.window.showErrorMessage('Could not find workspace.');
56 | return {
57 | uri: vscode.Uri.file('.'),
58 | index: 0,
59 | name: 'none'
60 | };
61 | }
62 | }
63 |
64 | // Public method to get the cached workspace folder
65 | public getWorkspaceFolder(): vscode.WorkspaceFolder {
66 | return this.workspaceFolder;
67 | }
68 |
69 | public async getSubdirectoryPaths(root = '') {
70 | const all = '/' + path.join('/', root, '...');
71 | const absoluteRoot = path.join(WorkspaceService.getInstance().getWorkspaceFolder().uri.path, root);
72 |
73 | return fs.promises.readdir(absoluteRoot, { withFileTypes: true }).then((data) => {
74 | const res: string[] = new Array(data.length + 1);
75 | let index = 0;
76 | res[index++] = all;
77 | // The first entry is always all.
78 | return Promise.all(data.map(async (element) => {
79 | if (element.isDirectory() && element.name[0] !== '.') {
80 | res[index++] = '/' + path.join('/', root, element.name);
81 | }
82 | })).then(() => { return res.slice(0, index); });
83 | });
84 | }
85 | }
--------------------------------------------------------------------------------
/src/test/runTest.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import * as path from 'path';
26 | import { runTests } from 'vscode-test';
27 |
28 |
29 | async function main() {
30 | try {
31 | // The folder containing the Extension Manifest package.json
32 | // Passed to `--extensionDevelopmentPath`
33 | const extensionDevelopmentPath = path.resolve(__dirname, '../../');
34 |
35 | // The path to test runner
36 | // Passed to --extensionTestsPath
37 | const extensionTestsPath = path.resolve(__dirname, './suite/index');
38 |
39 | // Download VS Code, unzip it and run the integration test
40 | await runTests({ extensionDevelopmentPath, extensionTestsPath });
41 | } catch (err) {
42 | console.error('Failed to run tests');
43 | process.exit(1);
44 | }
45 | }
46 |
47 | main();
48 |
--------------------------------------------------------------------------------
/src/test/suite/extension.test.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import * as assert from 'assert';
25 | import * as vscode from 'vscode';
26 |
27 | suite('Extension E2E Tests', () => {
28 | suiteSetup(async () => {
29 | const extension = vscode.extensions.getExtension('NVIDIA.bluebazel');
30 | assert.notStrictEqual(extension, undefined);
31 | await extension?.activate();
32 | });
33 |
34 | test('Commands are registered', () => {
35 | // Test if commands are correctly registered
36 | const extension = vscode.extensions.getExtension('NVIDIA.bluebazel');
37 | assert.notStrictEqual(extension, undefined);
38 | if (extension === undefined) {
39 | return false;
40 | }
41 | vscode.commands.getCommands(true).then((registeredCommands: string[]) => {
42 | const expectedCommands = extension.packageJSON.commands;
43 | for (const cmd of expectedCommands) {
44 | assert.ok(registeredCommands.includes(cmd), `Command '${cmd}' is not registered.`);
45 | }
46 | });
47 | });
48 |
49 | });
--------------------------------------------------------------------------------
/src/test/suite/index.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import * as glob from 'glob';
26 | import * as Mocha from 'mocha';
27 | import * as path from 'path';
28 |
29 | export function run(): Promise {
30 | // Create the mocha test
31 | const mocha = new Mocha({
32 | ui: 'tdd',
33 | color: true
34 | });
35 |
36 | const testsRoot = path.resolve(__dirname, '..');
37 |
38 | return new Promise((c, e) => {
39 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
40 | if (err) {
41 | return e(err);
42 | }
43 |
44 | // Add files to the test suite
45 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));
46 |
47 | try {
48 | // Run the mocha test
49 | mocha.run(failures => {
50 | if (failures > 0) {
51 | e(new Error(`${failures} tests failed.`));
52 | } else {
53 | c();
54 | }
55 | });
56 | } catch (err) {
57 | console.error(err);
58 | e(err);
59 | }
60 | });
61 | });
62 | }
63 |
--------------------------------------------------------------------------------
/src/test/suite/services/bazel-parser.test.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { BAZEL_BIN, BazelParser } from '../../../services/bazel-parser';
25 | import * as assert from 'assert';
26 | import * as fsPromises from 'fs/promises';
27 | import * as os from 'os';
28 | import * as path from 'path';
29 | import * as vscode from 'vscode';
30 |
31 | async function createTempDir(): Promise {
32 | const tempDir = path.join(os.tmpdir(), 'bazel-test-');
33 | return await fsPromises.mkdtemp(tempDir);
34 | }
35 |
36 | async function createBazelFiles(
37 | tempDir: string,
38 | workspacePaths: string[] = [],
39 | buildFilePaths: { [dir: string]: string } = {}
40 | ): Promise<{ workspace: string[]; build: string[] }> {
41 | const workspaceFiles: string[] = [];
42 | const buildFiles: string[] = [];
43 |
44 | for (const workspace of workspacePaths) {
45 | const workspacePath = path.join(tempDir, workspace);
46 | await fsPromises.mkdir(path.dirname(workspacePath), { recursive: true });
47 | await fsPromises.writeFile(workspacePath, '# WORKSPACE file');
48 | workspaceFiles.push(workspacePath);
49 | }
50 |
51 | for (const [dir, content] of Object.entries(buildFilePaths)) {
52 | const buildFilePath = path.join(tempDir, dir, 'BUILD');
53 | await fsPromises.mkdir(path.dirname(buildFilePath), { recursive: true });
54 | await fsPromises.writeFile(buildFilePath, content);
55 | buildFiles.push(buildFilePath);
56 | }
57 |
58 | return { workspace: workspaceFiles, build: buildFiles };
59 | }
60 |
61 | suite('BazelParser', () => {
62 | let tempDir: string;
63 |
64 | setup(async () => {
65 | tempDir = await createTempDir();
66 | });
67 |
68 | teardown(async () => {
69 | await fsPromises.rm(tempDir, { recursive: true, force: true });
70 | });
71 |
72 | test('should find all workspace and build files', async () => {
73 | const { workspace, build } = await createBazelFiles(tempDir, ['WORKSPACE'], {
74 | 'src': `
75 | py_binary(
76 | name = "test_target",
77 | srcs = ["test.py"],
78 | )
79 | `,
80 | });
81 |
82 | const result = await BazelParser.findBazelBuildFiles(tempDir);
83 |
84 | assert.deepStrictEqual(result.workspace.sort(), workspace.sort());
85 | assert.deepStrictEqual(result.build.sort(), build.sort());
86 | });
87 |
88 | test('should parse build files with correct bazel paths', async () => {
89 | const workspaceFile = 'WORKSPACE';
90 | const buildContent = `
91 | cc_library(
92 | name = "test_lib",
93 | srcs = ["lib.cpp"],
94 | )
95 |
96 | py_binary(
97 | name = "test_bin",
98 | srcs = ["main.py"],
99 | )
100 | `;
101 | const { build } = await createBazelFiles(tempDir, [workspaceFile], { 'src': buildContent });
102 |
103 | const result = await BazelParser.parseBazelBuildFileTargets(build[0], tempDir);
104 |
105 | assert.strictEqual(result.targets.length, 2);
106 |
107 | assert.deepStrictEqual(result.targets[0], {
108 | name: 'test_lib',
109 | ruleType: 'cc_library',
110 | srcExtensions: ['.cpp'],
111 | bazelPath: '//src:test_lib',
112 | buildPath: path.join(BAZEL_BIN, 'src', 'test_lib'),
113 | });
114 |
115 | assert.deepStrictEqual(result.targets[1], {
116 | name: 'test_bin',
117 | ruleType: 'py_binary',
118 | srcExtensions: ['.py'],
119 | bazelPath: '//src:test_bin',
120 | buildPath: path.join(BAZEL_BIN, 'src', 'test_bin'),
121 | });
122 | });
123 |
124 | test('should handle multiple workspace files correctly', async () => {
125 | const { workspace, build } = await createBazelFiles(tempDir, ['root/WORKSPACE', 'subdir/WORKSPACE'], {
126 | 'subdir/src': `
127 | py_binary(
128 | name = "sub_target",
129 | srcs = ["sub_main.py"],
130 | )
131 | `,
132 | });
133 |
134 | const resultWithoutPackage = await BazelParser.parseAllBazelBuildFilesTargets(tempDir, path.join(tempDir, 'root'), '.*', false);
135 |
136 | assert.strictEqual(resultWithoutPackage.length, 1);
137 |
138 | const result = await BazelParser.parseAllBazelBuildFilesTargets(tempDir, path.join(tempDir, 'root'), '.*', true);
139 |
140 | assert.strictEqual(result.length, 2);
141 | assert.strictEqual(result[0].bazelPath, '//src:sub_target');
142 | assert.strictEqual(result[0].buildPath, path.join(BAZEL_BIN, 'src', 'sub_target'));
143 | });
144 |
145 | test('should ignore directories without WORKSPACE or BUILD files', async () => {
146 | const result = await BazelParser.findBazelBuildFiles(tempDir);
147 |
148 | assert.deepStrictEqual(result, { workspace: [], build: [] });
149 | });
150 |
151 | test('should support cancellation tokens', async () => {
152 | const cancellationToken = new vscode.CancellationTokenSource();
153 | cancellationToken.cancel();
154 |
155 | const task = BazelParser.parseAllBazelBuildFilesTargets(tempDir, tempDir, '.*', true, cancellationToken.token);
156 |
157 | await assert.rejects(task, /cancelled/);
158 | });
159 |
160 | test('should parse srcs and target names correctly', async () => {
161 | const buildContent = `
162 | cc_library(
163 | name = "test_target",
164 | srcs = ["test.cpp", "utils.cpp"],
165 | )
166 | `;
167 |
168 | const { build } = await createBazelFiles(tempDir, ['WORKSPACE'], { 'src': buildContent });
169 |
170 | const result = await BazelParser.parseBazelBuildFileTargets(build[0], tempDir);
171 |
172 | assert.strictEqual(result.targets.length, 1);
173 | assert.strictEqual(result.targets[0].name, 'test_target');
174 | assert.deepStrictEqual(result.targets[0].srcExtensions, ['.cpp', '.cpp']);
175 | });
176 | });
177 |
--------------------------------------------------------------------------------
/src/test/suite/services/bazel-service.test.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { BazelTarget } from '../../../models/bazel-target';
25 | import { BazelService } from '../../../services/bazel-service';
26 | import { ConfigurationManager } from '../../../services/configuration-manager';
27 | import { ShellService } from '../../../services/shell-service';
28 | import { WorkspaceService } from '../../../services/workspace-service';
29 | import * as assert from 'assert';
30 | import * as fs from 'fs';
31 | import * as sinon from 'sinon';
32 | import * as vscode from 'vscode';
33 |
34 |
35 | suite('BazelService Tests', () => {
36 | let bazelService: BazelService;
37 | let mockContext: vscode.ExtensionContext;
38 | let mockConfigurationManager: sinon.SinonStubbedInstance;
39 | let mockShellService: sinon.SinonStubbedInstance;
40 | let mockWorkspaceService: sinon.SinonStubbedInstance;
41 |
42 | setup(() => {
43 | // Mock dependencies
44 | mockContext = {
45 | workspaceState: {
46 | get: (key: string) => undefined,
47 | update: async (key: string, value: unknown) => Promise.resolve(),
48 | },
49 | } as unknown as vscode.ExtensionContext;
50 | mockConfigurationManager = sinon.createStubInstance(ConfigurationManager);
51 | mockShellService = sinon.createStubInstance(ShellService);
52 | mockWorkspaceService = sinon.createStubInstance(WorkspaceService);
53 |
54 | // Initialize BazelService
55 | bazelService = new BazelService(mockContext, mockConfigurationManager, mockShellService);
56 | console.log(bazelService);
57 | });
58 |
59 | teardown(() => {
60 | sinon.restore();
61 | });
62 |
63 | test('fetchTargetActions should return actions requiring a target', async () => {
64 | const actions = await bazelService.fetchTargetActions();
65 | assert.deepStrictEqual(actions, [
66 | 'aquery',
67 | 'build',
68 | 'coverage',
69 | 'cquery',
70 | 'mobile-install',
71 | 'print_action',
72 | 'query',
73 | 'run',
74 | 'test'
75 | ]);
76 | });
77 |
78 | test('formatBazelTargetFromPath should correctly format a target path', () => {
79 | const targetPath = 'bazel-bin/src/test_target';
80 | const result = BazelService.formatBazelTargetFromPath(targetPath);
81 | assert.strictEqual(result, '//src:test_target');
82 | });
83 |
84 | test('fetchAllTargets should call the appropriate fetch method', async () => {
85 | // Mock methods
86 | mockConfigurationManager.shouldFetchTargetsUsingQuery.returns(false);
87 | sinon.stub(bazelService, 'fetchAllTargetsFromBuildFiles').resolves([]);
88 | sinon.stub(bazelService, 'fetchAllTargetsFromQuery').resolves([]);
89 |
90 | // Call fetchAllTargets
91 | await bazelService.fetchAllTargets();
92 |
93 | // Ensure the correct method was called
94 | sinon.assert.calledOnce(bazelService.fetchAllTargetsFromBuildFiles as sinon.SinonStub);
95 | sinon.assert.notCalled(bazelService.fetchAllTargetsFromQuery as sinon.SinonStub);
96 | });
97 |
98 | test('fetchAllTargetsByAction should categorize targets correctly', async () => {
99 | // Mock fetchAllTargets
100 | sinon.stub(bazelService, 'fetchAllTargets').resolves([
101 | {
102 | label: 'test_target',
103 | ruleType: 'cc_test',
104 | bazelPath: '//src:test_target',
105 | buildPath: '/bazel-bin/src/test_target',
106 | } as BazelTarget,
107 | ]);
108 |
109 | const result = await bazelService.fetchAllTargetsByAction();
110 |
111 | // Verify categorization
112 | assert.strictEqual(result.get('test')?.length, 1);
113 | assert.strictEqual(result.get('build')?.length, 1);
114 | assert.strictEqual(result.get('run')?.length, 1);
115 | });
116 |
117 | test('fetchAllTargetsFromQuery should parse query results', async () => {
118 | // Mock ShellService results
119 | mockShellService.runShellCommand.resolves({
120 | stdout: 'cc_test package //src:test_target\ncc_binary package //src:test_binary',
121 | stderr: '',
122 | });
123 |
124 | const result = await bazelService.fetchAllTargetsFromQuery();
125 | assert.strictEqual(result.length, 5);
126 |
127 | // Verify target parsing
128 | assert.strictEqual(result[0].label, 'test_target');
129 | assert.strictEqual(result[0].ruleType, 'cc_test');
130 | assert.strictEqual(result[0].bazelPath, '//src:test_target');
131 | assert.strictEqual(result[0].buildPath, '/bazel-bin/src/test_target');
132 | });
133 |
134 | test('findWorkspaceRoot should find the correct workspace directory', () => {
135 | // Mock filesystem structure
136 | const mockFs = sinon.stub(fs, 'existsSync');
137 | mockFs.withArgs(sinon.match(/WORKSPACE/)).returns(true);
138 |
139 | const result = BazelService['findWorkspaceRoot']('/mock/path/to/project');
140 | assert.strictEqual(result, '/mock/path/to/project');
141 |
142 | mockFs.restore();
143 | });
144 | });
145 |
--------------------------------------------------------------------------------
/src/ui/bazel-target-quick-pick-item.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import { BazelTarget } from '../models/bazel-target';
26 | import * as vscode from 'vscode';
27 |
28 | export interface BazelTargetQuickPickItem extends vscode.QuickPickItem {
29 | target?: BazelTarget;
30 | }
--------------------------------------------------------------------------------
/src/ui/code-lens-provider-utils.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { UnifiedCodeLensProvider } from './code-lens-providers/unified-code-lens-provider';
25 | import { BazelService } from '../services/bazel-service';
26 | import * as vscode from 'vscode';
27 |
28 | export function registerCodeLensProviders(context: vscode.ExtensionContext, bazelService: BazelService) {
29 | const testProvider = new UnifiedCodeLensProvider(context, bazelService);
30 |
31 | vscode.languages.registerCodeLensProvider({ language: 'go', scheme: 'file' }, testProvider);
32 | vscode.languages.registerCodeLensProvider({ language: 'cpp', scheme: 'file' }, testProvider);
33 | vscode.languages.registerCodeLensProvider({ language: 'c', scheme: 'file' }, testProvider);
34 | vscode.languages.registerCodeLensProvider({ language: 'python', scheme: 'file' }, testProvider);
35 | }
--------------------------------------------------------------------------------
/src/ui/code-lens-providers/unified-code-lens-provider.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import { LanguageRegistry } from '../../languages/language-registry';
25 | import { BazelAction, BazelTarget } from '../../models/bazel-target';
26 | import { BazelService } from '../../services/bazel-service';
27 | import { Console } from '../../services/console';
28 | import { ExtensionUtils } from '../../services/extension-utils';
29 | import * as vscode from 'vscode';
30 |
31 | enum PatternType {
32 | Run,
33 | Test
34 | }
35 | interface Pattern {
36 | type: PatternType;
37 | language: string;
38 | regex: RegExp;
39 | }
40 |
41 | export class UnifiedCodeLensProvider implements vscode.CodeLensProvider {
42 |
43 | private readonly regexPatterns: Pattern[];
44 |
45 | constructor(
46 | private readonly context: vscode.ExtensionContext,
47 | private readonly bazelService: BazelService
48 | ) {
49 | this.regexPatterns = [];
50 | const languages = LanguageRegistry.getLanguages();
51 | const testRegexes = languages.map(language => {
52 | try {
53 | return {
54 | language: language,
55 | type: PatternType.Test,
56 | regex: LanguageRegistry.getPlugin(language).getCodeLensTestRegex()
57 | };
58 | } catch (error) {
59 | return undefined;
60 | }
61 | }).filter(Boolean) as Pattern[];
62 |
63 | const runRegexes = languages.map(language => {
64 | try {
65 | return {
66 | language: language,
67 | type: PatternType.Run,
68 | regex: LanguageRegistry.getPlugin(language).getCodeLensRunRegex()
69 | };
70 | } catch (error) {
71 | return undefined;
72 | }
73 | }).filter(Boolean) as Pattern[];
74 |
75 | this.regexPatterns.push(...testRegexes);
76 | this.regexPatterns.push(...runRegexes);
77 | }
78 |
79 | public provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.CodeLens[] {
80 | // Match the correct regex based on the document's language
81 | const codeLenses: vscode.CodeLens[] = [];
82 |
83 | this.regexPatterns
84 | .filter(pattern => pattern.language === document.languageId)
85 | .forEach(pattern => {
86 | const lenses = this.processRegexPattern(document, pattern, token);
87 | codeLenses.push(...lenses);
88 | });
89 |
90 | return codeLenses;
91 | }
92 |
93 | private processRegexPattern(document: vscode.TextDocument, pattern: Pattern, _token: vscode.CancellationToken): vscode.CodeLens[] {
94 | const text = document.getText();
95 | const language = document.languageId; // Detect the language of the document
96 | const codeLenses: vscode.CodeLens[] = [];
97 |
98 | const extensionName = ExtensionUtils.getExtensionName(this.context);
99 | const extensionDisplayName = ExtensionUtils.getExtensionDisplayName(this.context);
100 |
101 | const { regex } = pattern;
102 | let match;
103 |
104 |
105 | let action: BazelAction = 'run';
106 | if (pattern.type === PatternType.Run) {
107 | action = 'run';
108 | } else if (pattern.type === PatternType.Test) {
109 | action = 'test';
110 | }
111 |
112 | while ((match = regex.exec(text)) !== null) {
113 | let functionName = '';
114 | if (language === 'cpp' || language === 'c') {
115 | // Combine FixtureName and TestName for C++/C tests
116 | const fixtureName = match[2];
117 | const testName = match[3];
118 | functionName = `${fixtureName}.${testName}`;
119 | } else {
120 | // Use captured test function name for other languages
121 | functionName = match[1] || match[2];
122 | }
123 | const line = document.lineAt(document.positionAt(match.index).line);
124 | const targets = BazelService.extractBazelTargetsAssociatedWithSourceFile(document.fileName);
125 |
126 | if (targets.length === 0) {
127 | continue;
128 | }
129 |
130 | Console.info(`Installing code lens provider for ${action} on ${functionName}...`);
131 |
132 | const realTargets = targets.map(target => {
133 | return new BazelTarget(this.context, this.bazelService, target.label, target.bazelPath, target.buildPath, action, target.ruleType);
134 | });
135 |
136 | const target = realTargets[0];
137 |
138 | // Modify run arguments for the specific function
139 | if (pattern.type === PatternType.Test) {
140 | target.getBazelArgs().add(`--test_filter=${functionName}`);
141 | }
142 | codeLenses.push(
143 | new vscode.CodeLens(line.range, {
144 | title: `${extensionName} ${action}`,
145 | tooltip: extensionDisplayName,
146 | command: `${extensionName}.executeTarget`,
147 | arguments: [target],
148 | })
149 | );
150 |
151 | const debugTarget = target.clone(true);
152 | debugTarget.getBazelArgs().add('--compilation_mode=dbg');
153 |
154 | codeLenses.push(
155 | new vscode.CodeLens(line.range, {
156 | title: `${extensionName} debug`,
157 | tooltip: extensionDisplayName,
158 | command: `${extensionName}.debugTarget`,
159 | arguments: [debugTarget],
160 | })
161 | );
162 | }
163 | return codeLenses;
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/src/ui/progress.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import * as vscode from 'vscode';
25 |
26 | function createSpinnerUpdater(updateCallback: (spinner: string) => void) {
27 | const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
28 | let spinnerIndex = 0;
29 | let interval: NodeJS.Timeout;
30 |
31 | const start = () => {
32 | interval = setInterval(() => {
33 | const spinner = spinnerFrames[spinnerIndex];
34 | updateCallback(spinner);
35 | spinnerIndex = (spinnerIndex + 1) % spinnerFrames.length;
36 | }, 100);
37 | };
38 |
39 | const stop = () => {
40 | if (interval) clearInterval(interval);
41 | };
42 |
43 | return { start, stop };
44 | }
45 |
46 | async function showProgressWindow(
47 | title: string,
48 | longMethodPromise: Promise,
49 | cancellationSource: vscode.CancellationTokenSource
50 | ): Promise {
51 | return new Promise((resolve, reject) => {
52 | vscode.window.withProgress(
53 | {
54 | location: vscode.ProgressLocation.Notification,
55 | title: title,
56 | cancellable: true,
57 | },
58 | async (progress, cancellationToken) => {
59 | const disposable = cancellationToken.onCancellationRequested(() => {
60 | disposable.dispose();
61 | cancellationSource.cancel(); // Propagate cancellation
62 | });
63 |
64 | const spinnerUpdater = createSpinnerUpdater((spinner) => {
65 | progress.report({ increment: undefined, message: `${spinner}` });
66 | });
67 |
68 | try {
69 | spinnerUpdater.start();
70 | const result = await longMethodPromise;
71 | spinnerUpdater.stop();
72 | progress.report({ increment: undefined, message: 'Finished' });
73 | resolve(result);
74 | } catch (error) {
75 | progress.report({ increment: undefined, message: 'Cancelled' });
76 | reject(error);
77 | } finally {
78 | spinnerUpdater.stop();
79 | }
80 | }
81 | );
82 | });
83 | }
84 |
85 | export async function showProgressStatus(
86 | title: string,
87 | longMethodPromise: Promise,
88 | cancellationSource: vscode.CancellationTokenSource
89 | ): Promise {
90 | const statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100);
91 |
92 | statusBarItem.text = `$(sync~spin) ${title}`;
93 |
94 | const cancelCommand = `${title}.cancel`;
95 | // Register the cancel command
96 | const disposable = vscode.commands.registerCommand(cancelCommand, () => {
97 | disposable.dispose();
98 | cancellationSource.cancel(); // Trigger cancellation
99 | });
100 |
101 | try {
102 | // Configure the status bar item
103 | statusBarItem.tooltip = 'Click to cancel';
104 | statusBarItem.command = cancelCommand;
105 | statusBarItem.show();
106 |
107 | // Await the long-running task
108 | const result = await longMethodPromise;
109 |
110 | statusBarItem.text = `${title} Completed`;
111 | setTimeout(() => statusBarItem.dispose(), 2000);
112 |
113 | return result;
114 | } catch (error) {
115 | statusBarItem.text = `${title} Cancelled`;
116 | setTimeout(() => statusBarItem.dispose(), 2000);
117 | throw error;
118 | } finally {
119 | statusBarItem.dispose();
120 | disposable.dispose();
121 | }
122 | }
123 |
124 | export async function showProgress(
125 | title: string,
126 | longMethod: (token: vscode.CancellationToken) => Promise,
127 | cancellationSource?: vscode.CancellationTokenSource,
128 | quiet = false
129 | ): Promise {
130 |
131 | if (cancellationSource === undefined) {
132 | cancellationSource = new vscode.CancellationTokenSource();
133 | }
134 |
135 | const longMethodPromise = longMethod(cancellationSource.token);
136 |
137 |
138 | // Start both the status bar and progress window
139 | const statusPromise = showProgressStatus(title, longMethodPromise, cancellationSource);
140 | const promises = [statusPromise];
141 | if (!quiet) {
142 | const progressWindowPromise = showProgressWindow(title, longMethodPromise, cancellationSource);
143 | promises.push(progressWindowPromise);
144 | }
145 | // Ensure that cancellation or completion of one cancels/cleans up the other
146 | try {
147 | const result = await Promise.all(promises);
148 | return result[0]; // Return the actual result
149 | } catch (error) {
150 | cancellationSource.cancel(); // Ensure both are canceled
151 | throw error;
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/src/ui/quick-pick.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 |
25 | import * as vscode from 'vscode';
26 |
27 |
28 | // Overload signatures
29 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
30 | export function showSimpleQuickPick(quickPickData: string[], onChange: (data: any) => void): void;
31 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
32 | export function showSimpleQuickPick(loadQuickPickData: (cancellationToken: vscode.CancellationToken) => Promise, onChange: (data: any) => void, loadingLabel: string): void;
33 |
34 | // Actual implementation
35 | export function showSimpleQuickPick(
36 | quickPickDataOrLoader: string[] | ((cancellationToken: vscode.CancellationToken) => Promise),
37 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
38 | onChange: (data: any) => void,
39 | loadingLabel = 'Loading...'
40 | ): void {
41 | // Create the QuickPick with a loading message
42 | const quickPick = vscode.window.createQuickPick();
43 | const cancellationTokenSource = new vscode.CancellationTokenSource();
44 | quickPick.placeholder = loadingLabel;
45 | quickPick.items = [{ label: `$(sync~spin) ${loadingLabel}` }];
46 | quickPick.ignoreFocusOut = true;
47 |
48 | // Show the QuickPick immediately
49 | quickPick.show();
50 |
51 | // Determine if quickPickDataOrLoader is an array or a function returning a Promise
52 | let loadQuickPickData: Promise;
53 | if (Array.isArray(quickPickDataOrLoader)) {
54 | // If it's an array, wrap it in a resolved promise
55 | loadQuickPickData = Promise.resolve(quickPickDataOrLoader);
56 | } else {
57 | // Otherwise, it's a function, so call it to get the promise
58 | loadQuickPickData = quickPickDataOrLoader(cancellationTokenSource.token);
59 | }
60 |
61 | // Load the actual data asynchronously
62 | loadQuickPickData.then(quickPickData => {
63 | quickPick.placeholder = '';
64 | // Once data is loaded, populate the QuickPick items
65 | const quickItems: vscode.QuickPickItem[] = [{ label: '' }];
66 | quickPickData.forEach(arg => {
67 | if (arg !== undefined && arg.trim().length > 0) {
68 | quickItems.push({ label: arg });
69 | }
70 | });
71 |
72 | // Set the loaded items in the QuickPick
73 | quickPick.items = quickItems;
74 |
75 | // Handle value change (updating the first item with user input)
76 | quickPick.onDidChangeValue(value => {
77 | quickItems[0].label = value;
78 | quickPick.items = quickItems;
79 | });
80 |
81 | // Handle selection change
82 | quickPick.onDidChangeSelection(items => {
83 | const item = items[0];
84 | quickPick.value = item.label;
85 | quickPick.hide();
86 | vscode.window.showInputBox({ value: item.label }).then(data => {
87 | if (data !== undefined) {
88 | onChange(data);
89 | }
90 | });
91 | });
92 |
93 | quickPick.onDidHide(() => {
94 | cancellationTokenSource.cancel();
95 | cancellationTokenSource.dispose();
96 | quickPick.dispose();
97 | });
98 |
99 | }).catch(err => {
100 | // Handle any errors in loading the data
101 | vscode.window.showErrorMessage(`Error loading data: ${err}`);
102 | quickPick.hide();
103 | });
104 | }
105 |
--------------------------------------------------------------------------------
/src/ui/terminal.ts:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | // MIT License
3 | //
4 | // Copyright (c) 2021-2024 NVIDIA Corporation
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////////
24 | import * as vscode from 'vscode';
25 |
26 | export async function clearTerminal() {
27 | await vscode.commands.executeCommand('workbench.action.terminal.clear');
28 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "ES2019",
5 | "outDir": "out",
6 | "lib": [
7 | "ES2019"
8 | ],
9 | "sourceMap": true,
10 | "strict": true,
11 | },
12 | "exclude": [
13 | "node_modules",
14 | ".vscode-test"
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------