From 7b79d24ad5b251c0806a07aa7769e824f3c37fec Mon Sep 17 00:00:00 2001 From: vsrs Date: Thu, 2 Jul 2020 19:47:40 +0300 Subject: [PATCH 1/7] Add runnable env support. --- editors/code/package.json | 29 +++++++++++++++++++++++++++++ editors/code/src/config.ts | 6 ++++++ editors/code/src/debug.ts | 16 ++++++++++------ editors/code/src/run.ts | 29 ++++++++++++++++++++++++----- 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/editors/code/package.json b/editors/code/package.json index af0a5c851f3..7c8b2fbece0 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -344,6 +344,35 @@ "default": null, "description": "Custom cargo runner extension ID." }, + "rust-analyzer.runnableEnv": { + "anyOf": [ + { + "type": "null" + }, + { + "type": "array", + "items": { + "type": "object", + "properties": { + "mask": { + "type": "string", + "description": "Runnable name mask" + }, + "env": { + "type": "object", + "description": "Variables in form of { \"key\": \"value\"}" + } + } + } + }, + { + "type": "object", + "description": "Variables in form of { \"key\": \"value\"}" + } + ], + "default": null, + "description": "Environment variables passed to the runnable launched using `Test ` or `Debug` lens or `rust-analyzer.run` command." + }, "rust-analyzer.inlayHints.enable": { "type": "boolean", "default": true, diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index fc95a7de6b8..a317aabcb1c 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -5,6 +5,8 @@ export type UpdatesChannel = "stable" | "nightly"; export const NIGHTLY_TAG = "nightly"; +export type RunnableEnvCfg = Record | [{ mask?: string, env: Record; }] + export class Config { readonly extensionId = "matklad.rust-analyzer"; @@ -114,6 +116,10 @@ export class Config { return this.get("cargoRunner"); } + get runnableEnv() { + return this.get("runnableEnv"); + } + get debug() { // "/rustc/" used by suggestions only. const { ["/rustc/"]: _, ...sourceFileMap } = this.get>("debug.sourceFileMap"); diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts index 61c12dbe074..525d26923ae 100644 --- a/editors/code/src/debug.ts +++ b/editors/code/src/debug.ts @@ -5,9 +5,10 @@ import * as ra from './lsp_ext'; import { Cargo } from './toolchain'; import { Ctx } from "./ctx"; +import { prepareEnv } from "./run"; const debugOutput = vscode.window.createOutputChannel("Debug"); -type DebugConfigProvider = (config: ra.Runnable, executable: string, sourceFileMap?: Record) => vscode.DebugConfiguration; +type DebugConfigProvider = (config: ra.Runnable, executable: string, env: Record, sourceFileMap?: Record) => vscode.DebugConfiguration; export async function makeDebugConfig(ctx: Ctx, runnable: ra.Runnable): Promise { const scope = ctx.activeRustEditor?.document.uri; @@ -92,7 +93,8 @@ async function getDebugConfiguration(ctx: Ctx, runnable: ra.Runnable): Promise { return executable; } -function getLldbDebugConfig(runnable: ra.Runnable, executable: string, sourceFileMap?: Record): vscode.DebugConfiguration { +function getLldbDebugConfig(runnable: ra.Runnable, executable: string, env: Record, sourceFileMap?: Record): vscode.DebugConfiguration { return { type: "lldb", request: "launch", @@ -130,11 +132,12 @@ function getLldbDebugConfig(runnable: ra.Runnable, executable: string, sourceFil args: runnable.args.executableArgs, cwd: runnable.args.workspaceRoot, sourceMap: sourceFileMap, - sourceLanguages: ["rust"] + sourceLanguages: ["rust"], + env }; } -function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, sourceFileMap?: Record): vscode.DebugConfiguration { +function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, env: Record, sourceFileMap?: Record): vscode.DebugConfiguration { return { type: (os.platform() === "win32") ? "cppvsdbg" : "cppdbg", request: "launch", @@ -142,6 +145,7 @@ function getCppvsDebugConfig(runnable: ra.Runnable, executable: string, sourceFi program: executable, args: runnable.args.executableArgs, cwd: runnable.args.workspaceRoot, - sourceFileMap: sourceFileMap, + sourceFileMap, + env, }; } diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts index e1430e31f76..d7c7c489c98 100644 --- a/editors/code/src/run.ts +++ b/editors/code/src/run.ts @@ -96,6 +96,28 @@ export class RunnableQuickPick implements vscode.QuickPickItem { } } +export function prepareEnv(runnable: ra.Runnable, config: Config): Record { + const env: Record = { "RUST_BACKTRACE": "short" }; + + if (runnable.args.expectTest) { + env["UPDATE_EXPECT"] = "1"; + } + + if (config.runnableEnv) { + if (Array.isArray(config.runnableEnv)) { + for (const it of config.runnableEnv) { + if (!it.mask || new RegExp(it.mask).test(runnable.label)) { + Object.assign(env, it.env); + } + } + } else { + Object.assign(env, config.runnableEnv as Record); + } + } + + return env; +} + export async function createTask(runnable: ra.Runnable, config: Config): Promise { if (runnable.kind !== "cargo") { // rust-analyzer supports only one kind, "cargo" @@ -108,16 +130,13 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise if (runnable.args.executableArgs.length > 0) { args.push('--', ...runnable.args.executableArgs); } - const env: { [key: string]: string } = { "RUST_BACKTRACE": "short" }; - if (runnable.args.expectTest) { - env["UPDATE_EXPECT"] = "1"; - } + const definition: tasks.CargoTaskDefinition = { type: tasks.TASK_TYPE, command: args[0], // run, test, etc... args: args.slice(1), cwd: runnable.args.workspaceRoot, - env: Object.assign({}, process.env as { [key: string]: string }, env), + env: prepareEnv(runnable, config), }; const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate() From 271abb7bc43f11c9b9e9c1353b162d9d267b1d21 Mon Sep 17 00:00:00 2001 From: vsrs Date: Thu, 2 Jul 2020 21:33:26 +0300 Subject: [PATCH 2/7] Add tests --- editors/code/src/config.ts | 4 +- editors/code/src/debug.ts | 2 +- editors/code/src/run.ts | 14 +-- editors/code/tests/unit/runnable_env.test.ts | 118 +++++++++++++++++++ 4 files changed, 128 insertions(+), 10 deletions(-) create mode 100644 editors/code/tests/unit/runnable_env.test.ts diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index a317aabcb1c..3257275c56f 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -5,7 +5,7 @@ export type UpdatesChannel = "stable" | "nightly"; export const NIGHTLY_TAG = "nightly"; -export type RunnableEnvCfg = Record | [{ mask?: string, env: Record; }] +export type RunnableEnvCfg = undefined | Record | { mask?: string, env: Record; }[]; export class Config { readonly extensionId = "matklad.rust-analyzer"; @@ -117,7 +117,7 @@ export class Config { } get runnableEnv() { - return this.get("runnableEnv"); + return this.get("runnableEnv"); } get debug() { diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts index 525d26923ae..bd92c5b6d73 100644 --- a/editors/code/src/debug.ts +++ b/editors/code/src/debug.ts @@ -93,7 +93,7 @@ async function getDebugConfiguration(ctx: Ctx, runnable: ra.Runnable): Promise { +export function prepareEnv(runnable: ra.Runnable, runnableEnvCfg: RunnableEnvCfg): Record { const env: Record = { "RUST_BACKTRACE": "short" }; if (runnable.args.expectTest) { env["UPDATE_EXPECT"] = "1"; } - if (config.runnableEnv) { - if (Array.isArray(config.runnableEnv)) { - for (const it of config.runnableEnv) { + if (runnableEnvCfg) { + if (Array.isArray(runnableEnvCfg)) { + for (const it of runnableEnvCfg) { if (!it.mask || new RegExp(it.mask).test(runnable.label)) { Object.assign(env, it.env); } } } else { - Object.assign(env, config.runnableEnv as Record); + Object.assign(env, runnableEnvCfg as Record); } } @@ -136,7 +136,7 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise command: args[0], // run, test, etc... args: args.slice(1), cwd: runnable.args.workspaceRoot, - env: prepareEnv(runnable, config), + env: prepareEnv(runnable, config.runnableEnv), }; const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate() diff --git a/editors/code/tests/unit/runnable_env.test.ts b/editors/code/tests/unit/runnable_env.test.ts new file mode 100644 index 00000000000..979d497dd9b --- /dev/null +++ b/editors/code/tests/unit/runnable_env.test.ts @@ -0,0 +1,118 @@ +import * as assert from 'assert'; +import { prepareEnv } from '../../src/run'; +import { RunnableEnvCfg } from '../../src/config'; +import * as ra from '../../src/lsp_ext'; + +function make_runnable(label: string): ra.Runnable { + return { + label, + kind: "cargo", + args: { + cargoArgs: [], + executableArgs: [] + } + } +} + +function fakePrepareEnv(runnable_name: string, config: RunnableEnvCfg) : Record { + const runnable = make_runnable(runnable_name); + return prepareEnv(runnable, config); +} + +suite('Runnable env', () => { + test('Global config works', () => { + const bin_env = fakePrepareEnv("run project_name", {"GLOBAL": "g"}); + assert.equal(bin_env["GLOBAL"], "g"); + + const test_env = fakePrepareEnv("test some::mod::test_name", {"GLOBAL": "g"}); + assert.equal(test_env["GLOBAL"], "g"); + }); + + test('null mask works', () => { + const config = [ + { + env: { DATA: "data" } + } + ]; + const bin_env = fakePrepareEnv("run project_name", config); + assert.equal(bin_env["DATA"], "data"); + + const test_env = fakePrepareEnv("test some::mod::test_name", config); + assert.equal(test_env["DATA"], "data"); + }); + + test('order works', () => { + const config = [ + { + env: { DATA: "data" } + }, + { + env: { DATA: "newdata" } + } + ]; + const bin_env = fakePrepareEnv("run project_name", config); + assert.equal(bin_env["DATA"], "newdata"); + + const test_env = fakePrepareEnv("test some::mod::test_name", config); + assert.equal(test_env["DATA"], "newdata"); + }); + + test('mask works', () => { + const config = [ + { + env: { DATA: "data" } + }, + { + mask: "^run", + env: { DATA: "rundata" } + }, + { + mask: "special_test$", + env: { DATA: "special_test" } + } + ]; + const bin_env = fakePrepareEnv("run project_name", config); + assert.equal(bin_env["DATA"], "rundata"); + + const test_env = fakePrepareEnv("test some::mod::test_name", config); + assert.equal(test_env["DATA"], "data"); + + const special_test_env = fakePrepareEnv("test some::mod::special_test", config); + assert.equal(special_test_env["DATA"], "special_test"); + }); + + test('exact test name works', () => { + const config = [ + { + env: { DATA: "data" } + }, + { + mask: "some::mod::test_name", + env: { DATA: "test special" } + } + ]; + const test_env = fakePrepareEnv("test some::mod::test_name", config); + assert.equal(test_env["DATA"], "test special"); + + const special_test_env = fakePrepareEnv("test some::mod::another_test", config); + assert.equal(special_test_env["DATA"], "data"); + }); + + test('test mod name works', () => { + const config = [ + { + env: { DATA: "data" } + }, + { + mask: "some::mod", + env: { DATA: "mod special" } + } + ]; + const test_env = fakePrepareEnv("test some::mod::test_name", config); + assert.equal(test_env["DATA"], "mod special"); + + const special_test_env = fakePrepareEnv("test some::mod::another_test", config); + assert.equal(special_test_env["DATA"], "mod special"); + }); + +}); From 611fad275fb7f3c2ec018b5539444b6649285228 Mon Sep 17 00:00:00 2001 From: vsrs Date: Thu, 2 Jul 2020 22:08:33 +0300 Subject: [PATCH 3/7] code linting --- editors/code/src/config.ts | 2 +- editors/code/src/run.ts | 2 +- editors/code/tests/unit/runnable_env.test.ts | 60 ++++++++++---------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 3257275c56f..23975c72616 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -5,7 +5,7 @@ export type UpdatesChannel = "stable" | "nightly"; export const NIGHTLY_TAG = "nightly"; -export type RunnableEnvCfg = undefined | Record | { mask?: string, env: Record; }[]; +export type RunnableEnvCfg = undefined | Record | { mask?: string; env: Record }[]; export class Config { readonly extensionId = "matklad.rust-analyzer"; diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts index 4a5c6ad4125..c0995461417 100644 --- a/editors/code/src/run.ts +++ b/editors/code/src/run.ts @@ -111,7 +111,7 @@ export function prepareEnv(runnable: ra.Runnable, runnableEnvCfg: RunnableEnvCfg } } } else { - Object.assign(env, runnableEnvCfg as Record); + Object.assign(env, runnableEnvCfg); } } diff --git a/editors/code/tests/unit/runnable_env.test.ts b/editors/code/tests/unit/runnable_env.test.ts index 979d497dd9b..f2f53e91ad9 100644 --- a/editors/code/tests/unit/runnable_env.test.ts +++ b/editors/code/tests/unit/runnable_env.test.ts @@ -3,7 +3,7 @@ import { prepareEnv } from '../../src/run'; import { RunnableEnvCfg } from '../../src/config'; import * as ra from '../../src/lsp_ext'; -function make_runnable(label: string): ra.Runnable { +function makeRunnable(label: string): ra.Runnable { return { label, kind: "cargo", @@ -11,21 +11,21 @@ function make_runnable(label: string): ra.Runnable { cargoArgs: [], executableArgs: [] } - } + }; } -function fakePrepareEnv(runnable_name: string, config: RunnableEnvCfg) : Record { - const runnable = make_runnable(runnable_name); +function fakePrepareEnv(runnableName: string, config: RunnableEnvCfg): Record { + const runnable = makeRunnable(runnableName); return prepareEnv(runnable, config); } suite('Runnable env', () => { test('Global config works', () => { - const bin_env = fakePrepareEnv("run project_name", {"GLOBAL": "g"}); - assert.equal(bin_env["GLOBAL"], "g"); + const binEnv = fakePrepareEnv("run project_name", { "GLOBAL": "g" }); + assert.equal(binEnv["GLOBAL"], "g"); - const test_env = fakePrepareEnv("test some::mod::test_name", {"GLOBAL": "g"}); - assert.equal(test_env["GLOBAL"], "g"); + const testEnv = fakePrepareEnv("test some::mod::test_name", { "GLOBAL": "g" }); + assert.equal(testEnv["GLOBAL"], "g"); }); test('null mask works', () => { @@ -34,11 +34,11 @@ suite('Runnable env', () => { env: { DATA: "data" } } ]; - const bin_env = fakePrepareEnv("run project_name", config); - assert.equal(bin_env["DATA"], "data"); + const binEnv = fakePrepareEnv("run project_name", config); + assert.equal(binEnv["DATA"], "data"); - const test_env = fakePrepareEnv("test some::mod::test_name", config); - assert.equal(test_env["DATA"], "data"); + const testEnv = fakePrepareEnv("test some::mod::test_name", config); + assert.equal(testEnv["DATA"], "data"); }); test('order works', () => { @@ -50,11 +50,11 @@ suite('Runnable env', () => { env: { DATA: "newdata" } } ]; - const bin_env = fakePrepareEnv("run project_name", config); - assert.equal(bin_env["DATA"], "newdata"); + const binEnv = fakePrepareEnv("run project_name", config); + assert.equal(binEnv["DATA"], "newdata"); - const test_env = fakePrepareEnv("test some::mod::test_name", config); - assert.equal(test_env["DATA"], "newdata"); + const testEnv = fakePrepareEnv("test some::mod::test_name", config); + assert.equal(testEnv["DATA"], "newdata"); }); test('mask works', () => { @@ -71,14 +71,14 @@ suite('Runnable env', () => { env: { DATA: "special_test" } } ]; - const bin_env = fakePrepareEnv("run project_name", config); - assert.equal(bin_env["DATA"], "rundata"); + const binEnv = fakePrepareEnv("run project_name", config); + assert.equal(binEnv["DATA"], "rundata"); - const test_env = fakePrepareEnv("test some::mod::test_name", config); - assert.equal(test_env["DATA"], "data"); + const testEnv = fakePrepareEnv("test some::mod::test_name", config); + assert.equal(testEnv["DATA"], "data"); - const special_test_env = fakePrepareEnv("test some::mod::special_test", config); - assert.equal(special_test_env["DATA"], "special_test"); + const specialTestEnv = fakePrepareEnv("test some::mod::special_test", config); + assert.equal(specialTestEnv["DATA"], "special_test"); }); test('exact test name works', () => { @@ -91,11 +91,11 @@ suite('Runnable env', () => { env: { DATA: "test special" } } ]; - const test_env = fakePrepareEnv("test some::mod::test_name", config); - assert.equal(test_env["DATA"], "test special"); + const testEnv = fakePrepareEnv("test some::mod::test_name", config); + assert.equal(testEnv["DATA"], "test special"); - const special_test_env = fakePrepareEnv("test some::mod::another_test", config); - assert.equal(special_test_env["DATA"], "data"); + const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); + assert.equal(specialTestEnv["DATA"], "data"); }); test('test mod name works', () => { @@ -108,11 +108,11 @@ suite('Runnable env', () => { env: { DATA: "mod special" } } ]; - const test_env = fakePrepareEnv("test some::mod::test_name", config); - assert.equal(test_env["DATA"], "mod special"); + const testEnv = fakePrepareEnv("test some::mod::test_name", config); + assert.equal(testEnv["DATA"], "mod special"); - const special_test_env = fakePrepareEnv("test some::mod::another_test", config); - assert.equal(special_test_env["DATA"], "mod special"); + const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); + assert.equal(specialTestEnv["DATA"], "mod special"); }); }); From bebbfa1a29062a3e9304c80080316d8c4937e5bc Mon Sep 17 00:00:00 2001 From: vsrs Date: Fri, 3 Jul 2020 14:56:30 +0300 Subject: [PATCH 4/7] Fix workspaceRoot --- editors/code/src/run.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts index c0995461417..de68f27aec5 100644 --- a/editors/code/src/run.ts +++ b/editors/code/src/run.ts @@ -103,6 +103,8 @@ export function prepareEnv(runnable: ra.Runnable, runnableEnvCfg: RunnableEnvCfg env["UPDATE_EXPECT"] = "1"; } + Object.assign(env, process.env as { [key: string]: string }); + if (runnableEnvCfg) { if (Array.isArray(runnableEnvCfg)) { for (const it of runnableEnvCfg) { @@ -135,7 +137,7 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise type: tasks.TASK_TYPE, command: args[0], // run, test, etc... args: args.slice(1), - cwd: runnable.args.workspaceRoot, + cwd: runnable.args.workspaceRoot || ".", env: prepareEnv(runnable, config.runnableEnv), }; From fd94a10be1e2656837b3b7c7d26f291c2c8cced6 Mon Sep 17 00:00:00 2001 From: vsrs Date: Fri, 3 Jul 2020 16:01:13 +0300 Subject: [PATCH 5/7] Add docs --- docs/user/manual.adoc | 58 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index b763958fee8..ede21ed9b23 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -109,18 +109,6 @@ Here are some useful self-diagnostic commands: * To log all LSP requests, add `"rust-analyzer.trace.server": "verbose"` to the settings and look for `Server Trace` in the panel. * To enable client-side logging, add `"rust-analyzer.trace.extension": true` to the settings and open the `Console` tab of VS Code developer tools. -==== Special `when` clause context for keybindings. -You may use `inRustProject` context to configure keybindings for rust projects only. For example: -[source,json] ----- -{ - "key": "ctrl+i", - "command": "rust-analyzer.toggleInlayHints", - "when": "inRustProject" -} ----- -More about `when` clause contexts https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts[here]. - === rust-analyzer Language Server Binary Other editors generally require the `rust-analyzer` binary to be in `$PATH`. @@ -337,3 +325,49 @@ They are usually triggered by a shortcut or by clicking a light bulb icon in the Cursor position or selection is signified by `┃` character. include::./generated_assists.adoc[] + +== Editor Features +=== VS Code +==== Special `when` clause context for keybindings. +You may use `inRustProject` context to configure keybindings for rust projects only. For example: +[source,json] +---- +{ + "key": "ctrl+i", + "command": "rust-analyzer.toggleInlayHints", + "when": "inRustProject" +} +---- +More about `when` clause contexts https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts[here]. + +=== Setting runnable environment variables +You can use "rust-analyzer.runnableEnv" setting to define runnable environment-specific substitution variables. +The simplest way for all runnables in a bunch: +[source,jsonc] +--- +"rust-analyzer.runnableEnv": { + "RUN_SLOW_TESTS": "1" +} +--- + +Or it is possible to specify vars more granularly: +[source,jsonc] +--- +"rust-analyzer.runnableEnv": [ + { + // "mask": null, // null mask means that this rule will be applied for all runnables + env: { + "APP_ID": "1", + "APP_DATA": "asdf" + } + }, + { + "mask": "test_name", + "env": { + "APP_ID": "2", // overwrites only APP_ID + } + } +] +--- + +You can use any valid RegExp as a mask. Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively. From 8b2a44dc3f40926c3893eb029480384227b36de5 Mon Sep 17 00:00:00 2001 From: vsrs Date: Fri, 3 Jul 2020 16:03:01 +0300 Subject: [PATCH 6/7] remove --- --- docs/user/manual.adoc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index ede21ed9b23..ee29be0bb6b 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -343,16 +343,14 @@ More about `when` clause contexts https://code.visualstudio.com/docs/getstarted/ === Setting runnable environment variables You can use "rust-analyzer.runnableEnv" setting to define runnable environment-specific substitution variables. The simplest way for all runnables in a bunch: -[source,jsonc] ---- +```jsonc "rust-analyzer.runnableEnv": { "RUN_SLOW_TESTS": "1" } ---- +``` Or it is possible to specify vars more granularly: -[source,jsonc] ---- +```jsonc "rust-analyzer.runnableEnv": [ { // "mask": null, // null mask means that this rule will be applied for all runnables @@ -368,6 +366,6 @@ Or it is possible to specify vars more granularly: } } ] ---- +``` You can use any valid RegExp as a mask. Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively. From 188d24024cd2770822d3e525be3ea330e79625c8 Mon Sep 17 00:00:00 2001 From: vsrs Date: Fri, 3 Jul 2020 16:07:28 +0300 Subject: [PATCH 7/7] Fix tag level --- docs/user/manual.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index ee29be0bb6b..7816287e400 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -340,7 +340,7 @@ You may use `inRustProject` context to configure keybindings for rust projects o ---- More about `when` clause contexts https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts[here]. -=== Setting runnable environment variables +==== Setting runnable environment variables You can use "rust-analyzer.runnableEnv" setting to define runnable environment-specific substitution variables. The simplest way for all runnables in a bunch: ```jsonc