From d01fc6405b45ed0fafd68f0f874068ed404ab976 Mon Sep 17 00:00:00 2001 From: bruno-ortiz Date: Fri, 25 Feb 2022 21:37:55 -0300 Subject: [PATCH] Creating rust dependencies tree view --- editors/code/package.json | 10 +++- editors/code/src/commands.ts | 2 +- editors/code/src/ctx.ts | 10 ++-- editors/code/src/toolchain.ts | 99 +++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 6 deletions(-) diff --git a/editors/code/package.json b/editors/code/package.json index 0efc191d7480..b009e381ec9f 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -285,6 +285,14 @@ "title": "Clear flycheck diagnostics", "category": "rust-analyzer" }, + { + "command": "rust-analyzer.revealDependency", + "title": "Reveal File" + }, + { + "command": "rust-analyzer.openFile", + "title": "Open File" + }, { "command": "rust-analyzer.revealDependency", "title": "Reveal File" @@ -1975,4 +1983,4 @@ } ] } -} +} \ No newline at end of file diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 7fe32754c903..fb6778b687f4 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -8,7 +8,7 @@ import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets"; import { spawnSync } from "child_process"; import { RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run"; import { AstInspector } from "./ast_inspector"; -import { isRustDocument, isCargoTomlDocument, sleep, isRustEditor, RustEditor } from "./util"; +import { isRustDocument, isCargoTomlDocument, sleep, isRustEditor, RustEditor } from './util'; import { startDebugSession, makeDebugConfig } from "./debug"; import { LanguageClient } from "vscode-languageclient/node"; import { LINKED_COMMANDS } from "./client"; diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index d62716c26db3..ce70dfd2f669 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -3,8 +3,8 @@ import * as lc from "vscode-languageclient/node"; import * as ra from "./lsp_ext"; import * as path from "path"; -import {Config, prepareVSCodeConfig} from "./config"; -import {createClient} from "./client"; +import {Config, prepareVSCodeConfig} from './config'; +import {createClient} from './client'; import { executeDiscoverProject, isRustDocument, @@ -12,8 +12,10 @@ import { LazyOutputChannel, log, RustEditor, -} from "./util"; -import {ServerStatusParams} from "./lsp_ext"; +} from './util'; +import {ServerStatusParams} from './lsp_ext'; +import { Dependency, DependencyFile, RustDependenciesProvider, DependencyId } from './dependencies_provider'; +import { execRevealDependency } from './commands'; import { Dependency, DependencyFile, diff --git a/editors/code/src/toolchain.ts b/editors/code/src/toolchain.ts index 771f6bcba458..6b40cb678c39 100644 --- a/editors/code/src/toolchain.ts +++ b/editors/code/src/toolchain.ts @@ -98,6 +98,43 @@ export class Cargo { return artifacts[0].fileName; } + async crates(): Promise { + const pathToCargo = await cargoPath(); + return await new Promise((resolve, reject) => { + const crates: Crate[] = []; + + const cargo = cp.spawn(pathToCargo, ['tree', '--prefix', 'none'], { + stdio: ['ignore', 'pipe', 'pipe'], + cwd: this.rootFolder + }); + const rl = readline.createInterface({ input: cargo.stdout }); + rl.on('line', line => { + const match = line.match(TREE_LINE_PATTERN); + if (match) { + const name = match[1]; + const version = match[2]; + const extraInfo = match[3]; + // ignore duplicates '(*)' and path dependencies + if (this.shouldIgnore(extraInfo)) { + return; + } + crates.push({ name, version }); + } + }); + cargo.on('exit', (exitCode, _) => { + if (exitCode === 0) + resolve(crates); + else + reject(new Error(`exit code: ${exitCode}.`)); + }); + + }); + } + + private shouldIgnore(extraInfo: string): boolean { + return extraInfo !== undefined && (extraInfo === '*' || path.isAbsolute(extraInfo)); + } + private async runCargo( cargoArgs: string[], onStdoutJson: (obj: any) => void, @@ -129,6 +166,58 @@ export class Cargo { } } +export async function activeToolchain(): Promise { + const pathToRustup = await rustupPath(); + return await new Promise((resolve, reject) => { + const execution = cp.spawn(pathToRustup, ['show', 'active-toolchain'], { + stdio: ['ignore', 'pipe', 'pipe'], + cwd: os.homedir() + }); + const rl = readline.createInterface({ input: execution.stdout }); + + let currToolchain: string | undefined = undefined; + rl.on('line', line => { + const match = line.match(TOOLCHAIN_PATTERN); + if (match) { + currToolchain = match[1]; + } + }); + execution.on('exit', (exitCode, _) => { + if (exitCode === 0 && currToolchain) + resolve(currToolchain); + else + reject(new Error(`exit code: ${exitCode}.`)); + }); + + }); +} + +export async function rustVersion(): Promise { + const pathToRustup = await rustupPath(); + return await new Promise((resolve, reject) => { + const execution = cp.spawn(pathToRustup, ['show', 'active-toolchain'], { + stdio: ['ignore', 'pipe', 'pipe'], + cwd: os.homedir() + }); + const rl = readline.createInterface({ input: execution.stdout }); + + let currToolchain: string | undefined = undefined; + rl.on('line', line => { + const match = line.match(TOOLCHAIN_PATTERN); + if (match) { + currToolchain = match[1]; + } + }); + execution.on('exit', (exitCode, _) => { + if (exitCode === 1 && currToolchain) + resolve(currToolchain); + else + reject(new Error(`exit code: ${exitCode}.`)); + }); + + }); +} + /** Mirrors `project_model::sysroot::discover_sysroot_dir()` implementation*/ export async function getSysroot(dir: string): Promise { const rustcPath = await getPathForExecutable("rustc"); @@ -147,6 +236,16 @@ export async function getRustcId(dir: string): Promise { return rx.exec(data)![1]; } +export async function getRustcVersion(dir: string): Promise { + const rustcPath = await getPathForExecutable("rustc"); + + // do not memoize the result because the toolchain may change between runs + const data = await execute(`${rustcPath} -V`, { cwd: dir }); + const rx = /(\d\.\d+\.\d+)/; + + return rx.exec(data)![1]; +} + /** Mirrors `toolchain::cargo()` implementation */ export function cargoPath(): Promise { return getPathForExecutable("cargo");