From 539e9e312bec43a4d7fd467dc34b19b6add69ab8 Mon Sep 17 00:00:00 2001 From: Alexey Date: Sat, 25 Feb 2017 09:01:15 +0300 Subject: [PATCH] Added the `cargoCwd` configuration parameter. (#111) --- doc/cargo_command_execution.md | 135 +++++++++--------- package.json | 10 +- .../cargo/output_channel_task_manager.ts | 59 ++++++-- src/components/cargo/terminal_task_manager.ts | 12 ++ .../configuration/configuration_manager.ts | 6 + 5 files changed, 139 insertions(+), 83 deletions(-) diff --git a/doc/cargo_command_execution.md b/doc/cargo_command_execution.md index be97bbc..4994f43 100644 --- a/doc/cargo_command_execution.md +++ b/doc/cargo_command_execution.md @@ -1,94 +1,104 @@ # Cargo Command Execution Page -The extension allows a developer to execute any of built-in cargo commands. +The extension allows a developer to execute any of the inbuilt Cargo commands. These commands are: -* bench -* build -* check -* clean -* clippy -* doc -* new -* run -* test -* update +* `bench` +* `build` +* `check` +* `clean` +* `clippy` +* `doc` +* `new` +* `run` +* `test` +* `update` -These commands available through the command palette (CTRL+P). - -These commands have prefix `"Cargo: "`. +These commands are available through the command palette (Ctrl+Shift+P) and have the prefix `"Cargo: "`. ## Execute Command On Save -The extension supports executing a command after saving the document opened in the active text document. +The extension supports executing some of these commands after saving the active document. + +The `"rust.actionOnSave"` configuration parameter specifies which command to execute. + +The possible values are: + +* `"build"` - executes `"Cargo: Build"` +* `"check"` - executes `"Cargo: Check"` +* `"clippy"` - executes `"Cargo: Clippy"` +* `"run"` - executes `"Cargo: Run"` +* `"test"` - executes `"Cargo: Test"` +* `null` - the extension does nothing (default) + +## Finding Out Cargo.toml -The `"rust.actionOnSave"` configuration parameter specifies a command to execute. +Before executing the command, the extension needs to find out which `Cargo.toml` to use. The extension uses the following algorithm: -The possible values: +* Try to determine the current working directory from the active text editor -* `"build"` - the extension executes `"Cargo: Build"` -* `"check"` - the extension executes `"Cargo: Check"` -* `"clippy"` - the extension executes `"Cargo: Clippy"` -* `"run"` - the extension executes `"Cargo: Run"` -* `"test"` - the extension executes `"Cargo: Test"` -* `null` - the extension does nothing + If all of the following conditions are met: -By default, it is `null`. + * There is an active text editor + * A file opened in the editor is within the workspace (the directory opened in VS Code) + * There is a `Cargo.toml` in the same directory as the active file or in any of the parent directories within the workspace -## Current Working Directory Determination + Then use the `Cargo.toml` file that was found. -The extension executes a cargo command in some directory. To find out which directory the extension should use, the extension uses the following algorithm: +* Try using the previous `Cargo.toml` file +* Try using the `Cargo.toml` from the workspace -* Try making out the current working directory from the active text editor +If the extension fails to find a `Cargo.toml`, an error message is shown. - If all of the conditions are met: +## Finding Out The Working Directory - * There is an active text editor - * A file opened in the editor is in the workspace (the opened directory) - * There is a `Cargo.toml` file near the file or in the parent directories within the workspace +Before executing a Cargo command, the extension must find out which directory to execute the command in. - Then use the directory containing the `Cargo.toml` file. +The extension supports the `"rust.cargoCwd"` configuration parameter with the following possible values: -* Try using the previous current working directory -* Try using the workspace +* `"/some/path"` - the extension uses the specified path as the command's working directory +* `null` - the directory containing the chosen `Cargo.toml` is used as Cargo's working directory (default `cargo` behavior) ## Configuration Parameters ### Cargo Path -The `"rust.cargoPath"` configuration parameter specifies a path to the cargo's executable. +The `"rust.cargoPath"` configuration parameter specifies a path to the `cargo` executable with the following possible values: -The possible values: +* `"/some/path"` - the extension would try to use the path +* `null` - the extension would try to use `cargo` from the `PATH` environment variable. -* `"Some path"` - the extension would try to use the path -* `null` - the extension would try to use cargo from the `PATH` variable of the environment. - -If cargo isn't available the extension can't execute a cargo command. +If `cargo` isn't available, the extension can't execute any Cargo commands. ### Cargo Environment -The `"rust.cargoEnv"` configuration parameter specifies an environment which would be added to the general environment for executing a cargo command. +The `"rust.cargoEnv"` configuration parameter specifies an environment variable which would be added to the general environment when executing a Cargo command. -The possible values: +The possible values are: -* Some object (`{ "RUST_BACKTRACE": 1 }`) +* `{ "Some": object }` * `null` +#### Examples + +```json +"rust.cargoEnv": { "RUST_BACKTRACE": 1 } +``` + ### Setting An Action To Handle Starting A New Command If There Is Another Command Running -The `"rust.actionOnStartingCommandIfThereIsRunningCommand"` configuration parameter specifies what the extension should do in case of starting a new command if there is another command running. +The `"rust.actionOnStartingCommandIfThereIsRunningCommand"` configuration parameter specifies what the extension should do in case of starting a new command if there is a previous command running. The possible values are: -* `"Stop running command"` - the extension will stop another running command and start a new one +* `"Stop running command"` - the extension will stop the previous running command and start a new one * `"Ignore new command"` - the extension will ignore a request to start a new command * `"Show dialog to let me decide"` - the extension will show an information box to let the user decide whether or not to stop a running command - ### Passing Arguments -The extension supports several configuration parameters: +The extension supports several configuration parameters used to pass arguments on to the appropriate commands: * `"rust.buildArgs"` * `"rust.checkArgs"` @@ -96,13 +106,9 @@ The extension supports several configuration parameters: * `"rust.runArgs"` * `"rust.testArgs"` -The type of these configuration parameters is an array of strings. - -These configuration parameters specify arguments which are passed to an appropriate command. +These parameters each take an array of strings. For example, you could configure the extension to execute `cargo build --features some_feature`. -It is useful when you want the extension to execute `cargo build --features some_feature`. - -These configuration parameters are used when one of the following commands is invoked: +These parameters are used when one of the following commands is invoked: * `"Cargo: Build"` * `"Cargo: Check"` @@ -126,11 +132,10 @@ The extension supports several configuration parameters: * `"rust.customRunConfigurations"` * `"rust.customTestConfigurations"` -The type of these configuration parameters is an array of objects. -The object must have the following fields: +The type of these parameters is an array of objects and each object must have the following fields: -* `"title"` - a string. It is shown as the label of a quick pick item if a cargo command has several custom configurations -* `"args"` - an array of strings. If a custom configuration is chosen, a cargo command is executed with the arguments from the custom configuration +* `"title"` - a string. It is shown as the label of a quick pick item if a Cargo command has more than one custom configuration +* `"args"` - an array of strings. If a custom configuration is chosen, a Cargo command is executed with the arguments that were defined These configuration parameters are used when one of the following commands is invoked: @@ -140,17 +145,13 @@ These configuration parameters are used when one of the following commands is in * `"Cargo: Run using custom configuration"` * `"Cargo: Test using custom configuration"` -If any of the following commands is invoked, the extension decides what to do. - -If none of the custom configurations for the command is defined the extension shows an error message. - -If only one custom configuration for the command is defined the extension executes the command with the arguments from the custom configuration. - -If many custom configurations for the command are defined the extension shows a quick pick with titles of the custom configurations to let a developer decide. - -If a developer cancels the quick pick the extension does nothing. +When one of these commands is invoked, the extension decides what to do: -If a developer chooses an item the extension executes the command with the arguments from the chosen configuration. +* If there are no custom configurations defined for the command, the extension shows an error message. +* If only one custom configuration for the command is defined, the extension executes the customized command. +* If more than one custom configuration is defined, the extension shows a quick pick view, listing the title of each configuration to let the developer decide. +* If a developer cancels the quick pick, the extension does nothing. +* If a developer chooses an item, the extension executes the customized command. #### Examples diff --git a/package.json b/package.json index e489a5c..fd4c34e 100644 --- a/package.json +++ b/package.json @@ -222,6 +222,14 @@ "default": null, "description": "Specifies custom variables to set when running cargo. Useful for crates which use env vars in their build.rs (like openssl-sys)." }, + "rust.cargoCwd": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Specifies the path of the directory where a cargo command would be executed" + }, "rust.executeCargoCommandInTerminal": { "type": "boolean", "default": false, @@ -494,4 +502,4 @@ "elegant-spinner": "1.0.1", "vscode-languageclient": "3.0.4" } -} \ No newline at end of file +} diff --git a/src/components/cargo/output_channel_task_manager.ts b/src/components/cargo/output_channel_task_manager.ts index 5b08df7..5b13a47 100644 --- a/src/components/cargo/output_channel_task_manager.ts +++ b/src/components/cargo/output_channel_task_manager.ts @@ -1,3 +1,5 @@ +import { join } from 'path'; + import { DiagnosticCollection, languages, window } from 'vscode'; import { ConfigurationManager } from '../configuration/configuration_manager'; @@ -53,25 +55,51 @@ export class OutputChannelTaskManager { cwd: string, parseOutput: boolean ): Promise { - function extendArgs(): void { - if (parseOutput) { - // Prepend arguments with arguments making cargo print output in JSON. - switch (command) { - case 'build': - case 'check': - case 'clippy': - case 'test': - case 'run': - args = ['--message-format', 'json'].concat(args); - break; - } + const cargoCwd = this.configurationManager.getCargoCwd(); + + /** + * Prepends the manifest path to arguments + * if the command should be executed in a directory + * which differs from the directory containing Cargo.toml. + */ + function prependArgsWithManifestPathIfRequired(): void { + if (cargoCwd === undefined || cargoCwd === cwd) { + return; + } + + const manifestPath = join(cwd, 'Cargo.toml'); + + args = ['--manifest-path', manifestPath].concat(args); + } + + function prependArgsWithMessageFormatIfRequired(): void { + if (!parseOutput) { + return; } - // Prepare arguments with a command - args = [command].concat(args); + // Prepend arguments with arguments making cargo print output in JSON. + switch (command) { + case 'build': + case 'check': + case 'clippy': + case 'test': + case 'run': + args = ['--message-format', 'json'].concat(args); + break; + } } - extendArgs(); + prependArgsWithMessageFormatIfRequired(); + + prependArgsWithManifestPathIfRequired(); + + // Prepend arguments with a command. + args = [command].concat(args); + + // Change cwd if the user specified custom cwd. + if (cargoCwd !== undefined) { + cwd = cargoCwd; + } this.runningTask = new Task( this.configurationManager, @@ -82,6 +110,7 @@ export class OutputChannelTaskManager { this.runningTask.setStarted(() => { this.channel.clear(); + this.channel.append(`Working directory: ${cwd}\n`); this.channel.append(`Started cargo ${args.join(' ')}\n\n`); this.diagnostics.clear(); diff --git a/src/components/cargo/terminal_task_manager.ts b/src/components/cargo/terminal_task_manager.ts index a733e77..3ed4460 100644 --- a/src/components/cargo/terminal_task_manager.ts +++ b/src/components/cargo/terminal_task_manager.ts @@ -1,3 +1,5 @@ +import { join } from 'path'; + import { ExtensionContext, Terminal, window, workspace } from 'vscode'; import { CommandStartHandleResult, Helper } from './helper'; @@ -80,6 +82,16 @@ export class TerminalTaskManager { setEnvironmentVariables(); + const cargoCwd = this.configurationManager.getCargoCwd(); + + if (cargoCwd !== undefined && cargoCwd !== cwd) { + const manifestPath = join(cwd, 'Cargo.toml'); + + args = ['--manifest-path', manifestPath].concat(args); + + cwd = cargoCwd; + } + // Change the current directory to a specified directory this.runningTerminal.sendText(`cd "${cwd}"`); diff --git a/src/components/configuration/configuration_manager.ts b/src/components/configuration/configuration_manager.ts index e46f73f..591c6bf 100644 --- a/src/components/configuration/configuration_manager.ts +++ b/src/components/configuration/configuration_manager.ts @@ -82,6 +82,12 @@ export class ConfigurationManager { return cargoEnv || {}; } + public getCargoCwd(): string | undefined { + const cargoCwd = ConfigurationManager.getPathConfigParameter('cargoCwd'); + + return cargoCwd; + } + public getCargoPath(): string { const rustsymPath = ConfigurationManager.getPathConfigParameter('cargoPath');