mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 12:29:21 +00:00
editor/code: Enable noUncheckedIndexedAccess
ts option
https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess
This commit is contained in:
parent
bb35d8fa8e
commit
72a3883a71
14 changed files with 124 additions and 52 deletions
|
@ -2,6 +2,7 @@ import * as vscode from "vscode";
|
||||||
|
|
||||||
import { Ctx, Disposable } from "./ctx";
|
import { Ctx, Disposable } from "./ctx";
|
||||||
import { RustEditor, isRustEditor } from "./util";
|
import { RustEditor, isRustEditor } from "./util";
|
||||||
|
import { unwrapUndefinable } from "./undefinable";
|
||||||
|
|
||||||
// FIXME: consider implementing this via the Tree View API?
|
// FIXME: consider implementing this via the Tree View API?
|
||||||
// https://code.visualstudio.com/api/extension-guides/tree-view
|
// https://code.visualstudio.com/api/extension-guides/tree-view
|
||||||
|
@ -164,8 +165,9 @@ export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProv
|
||||||
if (!parsedRange) return;
|
if (!parsedRange) return;
|
||||||
|
|
||||||
const [begin, end] = parsedRange.slice(1).map((off) => this.positionAt(doc, +off));
|
const [begin, end] = parsedRange.slice(1).map((off) => this.positionAt(doc, +off));
|
||||||
|
const actualBegin = unwrapUndefinable(begin);
|
||||||
return new vscode.Range(begin, end);
|
const actualEnd = unwrapUndefinable(end);
|
||||||
|
return new vscode.Range(actualBegin, actualEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memoize the last value, otherwise the CPU is at 100% single core
|
// Memoize the last value, otherwise the CPU is at 100% single core
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { WorkspaceEdit } from "vscode";
|
||||||
import { Config, prepareVSCodeConfig } from "./config";
|
import { Config, prepareVSCodeConfig } from "./config";
|
||||||
import { randomUUID } from "crypto";
|
import { randomUUID } from "crypto";
|
||||||
import { sep as pathSeparator } from "path";
|
import { sep as pathSeparator } from "path";
|
||||||
|
import { unwrapUndefinable } from "./undefinable";
|
||||||
|
|
||||||
export interface Env {
|
export interface Env {
|
||||||
[name: string]: string;
|
[name: string]: string;
|
||||||
|
@ -323,10 +324,12 @@ export async function createClient(
|
||||||
}
|
}
|
||||||
for (const [group, { index, items }] of groups) {
|
for (const [group, { index, items }] of groups) {
|
||||||
if (items.length === 1) {
|
if (items.length === 1) {
|
||||||
result[index] = items[0];
|
const item = unwrapUndefinable(items[0]);
|
||||||
|
result[index] = item;
|
||||||
} else {
|
} else {
|
||||||
const action = new vscode.CodeAction(group);
|
const action = new vscode.CodeAction(group);
|
||||||
action.kind = items[0].kind;
|
const item = unwrapUndefinable(items[0]);
|
||||||
|
action.kind = item.kind;
|
||||||
action.command = {
|
action.command = {
|
||||||
command: "rust-analyzer.applyActionGroup",
|
command: "rust-analyzer.applyActionGroup",
|
||||||
title: "",
|
title: "",
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { startDebugSession, makeDebugConfig } from "./debug";
|
||||||
import { LanguageClient } from "vscode-languageclient/node";
|
import { LanguageClient } from "vscode-languageclient/node";
|
||||||
import { LINKED_COMMANDS } from "./client";
|
import { LINKED_COMMANDS } from "./client";
|
||||||
import { DependencyId } from "./dependencies_provider";
|
import { DependencyId } from "./dependencies_provider";
|
||||||
|
import { unwrapUndefinable } from "./undefinable";
|
||||||
|
|
||||||
export * from "./ast_inspector";
|
export * from "./ast_inspector";
|
||||||
export * from "./run";
|
export * from "./run";
|
||||||
|
@ -129,7 +130,8 @@ export function matchingBrace(ctx: CtxInit): Cmd {
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
editor.selections = editor.selections.map((sel, idx) => {
|
editor.selections = editor.selections.map((sel, idx) => {
|
||||||
const active = client.protocol2CodeConverter.asPosition(response[idx]);
|
const position = unwrapUndefinable(response[idx]);
|
||||||
|
const active = client.protocol2CodeConverter.asPosition(position);
|
||||||
const anchor = sel.isEmpty ? active : sel.anchor;
|
const anchor = sel.isEmpty ? active : sel.anchor;
|
||||||
return new vscode.Selection(anchor, active);
|
return new vscode.Selection(anchor, active);
|
||||||
});
|
});
|
||||||
|
@ -231,7 +233,7 @@ export function parentModule(ctx: CtxInit): Cmd {
|
||||||
if (!locations) return;
|
if (!locations) return;
|
||||||
|
|
||||||
if (locations.length === 1) {
|
if (locations.length === 1) {
|
||||||
const loc = locations[0];
|
const loc = unwrapUndefinable(locations[0]);
|
||||||
|
|
||||||
const uri = client.protocol2CodeConverter.asUri(loc.targetUri);
|
const uri = client.protocol2CodeConverter.asUri(loc.targetUri);
|
||||||
const range = client.protocol2CodeConverter.asRange(loc.targetRange);
|
const range = client.protocol2CodeConverter.asRange(loc.targetRange);
|
||||||
|
@ -331,7 +333,13 @@ async function revealParentChain(document: RustDocument, ctx: CtxInit) {
|
||||||
} while (!ctx.dependencies?.contains(documentPath));
|
} while (!ctx.dependencies?.contains(documentPath));
|
||||||
parentChain.reverse();
|
parentChain.reverse();
|
||||||
for (const idx in parentChain) {
|
for (const idx in parentChain) {
|
||||||
await ctx.treeView?.reveal(parentChain[idx], { select: true, expand: true });
|
const treeView = ctx.treeView;
|
||||||
|
if (!treeView) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dependency = unwrapUndefinable(parentChain[idx]);
|
||||||
|
await treeView.reveal(dependency, { select: true, expand: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import * as path from "path";
|
||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import { Env } from "./client";
|
import { Env } from "./client";
|
||||||
import { log } from "./util";
|
import { log } from "./util";
|
||||||
|
import { expectNotUndefined, unwrapUndefinable } from "./undefinable";
|
||||||
|
|
||||||
export type RunnableEnvCfg =
|
export type RunnableEnvCfg =
|
||||||
| undefined
|
| undefined
|
||||||
|
@ -338,7 +339,7 @@ export function substituteVariablesInEnv(env: Env): Env {
|
||||||
const depRe = new RegExp(/\${(?<depName>.+?)}/g);
|
const depRe = new RegExp(/\${(?<depName>.+?)}/g);
|
||||||
let match = undefined;
|
let match = undefined;
|
||||||
while ((match = depRe.exec(value))) {
|
while ((match = depRe.exec(value))) {
|
||||||
const depName = match.groups!.depName;
|
const depName = unwrapUndefinable(match.groups?.depName);
|
||||||
deps.add(depName);
|
deps.add(depName);
|
||||||
// `depName` at this point can have a form of `expression` or
|
// `depName` at this point can have a form of `expression` or
|
||||||
// `prefix:expression`
|
// `prefix:expression`
|
||||||
|
@ -356,7 +357,7 @@ export function substituteVariablesInEnv(env: Env): Env {
|
||||||
if (match) {
|
if (match) {
|
||||||
const { prefix, body } = match.groups!;
|
const { prefix, body } = match.groups!;
|
||||||
if (prefix === "env") {
|
if (prefix === "env") {
|
||||||
const envName = body;
|
const envName = unwrapUndefinable(body);
|
||||||
envWithDeps[dep] = {
|
envWithDeps[dep] = {
|
||||||
value: process.env[envName] ?? "",
|
value: process.env[envName] ?? "",
|
||||||
deps: [],
|
deps: [],
|
||||||
|
@ -384,13 +385,12 @@ export function substituteVariablesInEnv(env: Env): Env {
|
||||||
do {
|
do {
|
||||||
leftToResolveSize = toResolve.size;
|
leftToResolveSize = toResolve.size;
|
||||||
for (const key of toResolve) {
|
for (const key of toResolve) {
|
||||||
if (envWithDeps[key].deps.every((dep) => resolved.has(dep))) {
|
const item = unwrapUndefinable(envWithDeps[key]);
|
||||||
envWithDeps[key].value = envWithDeps[key].value.replace(
|
if (item.deps.every((dep) => resolved.has(dep))) {
|
||||||
/\${(?<depName>.+?)}/g,
|
item.value = item.value.replace(/\${(?<depName>.+?)}/g, (_wholeMatch, depName) => {
|
||||||
(_wholeMatch, depName) => {
|
const item = unwrapUndefinable(envWithDeps[depName]);
|
||||||
return envWithDeps[depName].value;
|
return item.value;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
resolved.add(key);
|
resolved.add(key);
|
||||||
toResolve.delete(key);
|
toResolve.delete(key);
|
||||||
}
|
}
|
||||||
|
@ -399,7 +399,8 @@ export function substituteVariablesInEnv(env: Env): Env {
|
||||||
|
|
||||||
const resolvedEnv: Env = {};
|
const resolvedEnv: Env = {};
|
||||||
for (const key of Object.keys(env)) {
|
for (const key of Object.keys(env)) {
|
||||||
resolvedEnv[key] = envWithDeps[`env:${key}`].value;
|
const item = unwrapUndefinable(envWithDeps[`env:${key}`]);
|
||||||
|
resolvedEnv[key] = item.value;
|
||||||
}
|
}
|
||||||
return resolvedEnv;
|
return resolvedEnv;
|
||||||
}
|
}
|
||||||
|
@ -418,20 +419,19 @@ function substituteVSCodeVariableInString(val: string): string {
|
||||||
function computeVscodeVar(varName: string): string | null {
|
function computeVscodeVar(varName: string): string | null {
|
||||||
const workspaceFolder = () => {
|
const workspaceFolder = () => {
|
||||||
const folders = vscode.workspace.workspaceFolders ?? [];
|
const folders = vscode.workspace.workspaceFolders ?? [];
|
||||||
if (folders.length === 1) {
|
const folder = folders[0];
|
||||||
// TODO: support for remote workspaces?
|
// TODO: support for remote workspaces?
|
||||||
return folders[0].uri.fsPath;
|
const fsPath: string =
|
||||||
} else if (folders.length > 1) {
|
folder === undefined
|
||||||
// could use currently opened document to detect the correct
|
? // no workspace opened
|
||||||
|
""
|
||||||
|
: // could use currently opened document to detect the correct
|
||||||
// workspace. However, that would be determined by the document
|
// workspace. However, that would be determined by the document
|
||||||
// user has opened on Editor startup. Could lead to
|
// user has opened on Editor startup. Could lead to
|
||||||
// unpredictable workspace selection in practice.
|
// unpredictable workspace selection in practice.
|
||||||
// It's better to pick the first one
|
// It's better to pick the first one
|
||||||
return folders[0].uri.fsPath;
|
folder.uri.fsPath;
|
||||||
} else {
|
return fsPath;
|
||||||
// no workspace opened
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
// https://code.visualstudio.com/docs/editor/variables-reference
|
// https://code.visualstudio.com/docs/editor/variables-reference
|
||||||
const supportedVariables: { [k: string]: () => string } = {
|
const supportedVariables: { [k: string]: () => string } = {
|
||||||
|
@ -454,7 +454,11 @@ function computeVscodeVar(varName: string): string | null {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (varName in supportedVariables) {
|
if (varName in supportedVariables) {
|
||||||
return supportedVariables[varName]();
|
const fn = expectNotUndefined(
|
||||||
|
supportedVariables[varName],
|
||||||
|
`${varName} should not be undefined here`
|
||||||
|
);
|
||||||
|
return fn();
|
||||||
} else {
|
} else {
|
||||||
// return "${" + varName + "}";
|
// return "${" + varName + "}";
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import * as ra from "./lsp_ext";
|
||||||
import { Cargo, getRustcId, getSysroot } from "./toolchain";
|
import { Cargo, getRustcId, getSysroot } from "./toolchain";
|
||||||
import { Ctx } from "./ctx";
|
import { Ctx } from "./ctx";
|
||||||
import { prepareEnv } from "./run";
|
import { prepareEnv } from "./run";
|
||||||
|
import { unwrapUndefinable } from "./undefinable";
|
||||||
|
|
||||||
const debugOutput = vscode.window.createOutputChannel("Debug");
|
const debugOutput = vscode.window.createOutputChannel("Debug");
|
||||||
type DebugConfigProvider = (
|
type DebugConfigProvider = (
|
||||||
|
@ -105,12 +106,13 @@ async function getDebugConfiguration(
|
||||||
const workspaceFolders = vscode.workspace.workspaceFolders!;
|
const workspaceFolders = vscode.workspace.workspaceFolders!;
|
||||||
const isMultiFolderWorkspace = workspaceFolders.length > 1;
|
const isMultiFolderWorkspace = workspaceFolders.length > 1;
|
||||||
const firstWorkspace = workspaceFolders[0];
|
const firstWorkspace = workspaceFolders[0];
|
||||||
const workspace =
|
const maybeWorkspace =
|
||||||
!isMultiFolderWorkspace || !runnable.args.workspaceRoot
|
!isMultiFolderWorkspace || !runnable.args.workspaceRoot
|
||||||
? firstWorkspace
|
? firstWorkspace
|
||||||
: workspaceFolders.find((w) => runnable.args.workspaceRoot?.includes(w.uri.fsPath)) ||
|
: workspaceFolders.find((w) => runnable.args.workspaceRoot?.includes(w.uri.fsPath)) ||
|
||||||
firstWorkspace;
|
firstWorkspace;
|
||||||
|
|
||||||
|
const workspace = unwrapUndefinable(maybeWorkspace);
|
||||||
const wsFolder = path.normalize(workspace.uri.fsPath);
|
const wsFolder = path.normalize(workspace.uri.fsPath);
|
||||||
const workspaceQualifier = isMultiFolderWorkspace ? `:${workspace.name}` : "";
|
const workspaceQualifier = isMultiFolderWorkspace ? `:${workspace.name}` : "";
|
||||||
function simplifyPath(p: string): string {
|
function simplifyPath(p: string): string {
|
||||||
|
@ -130,12 +132,8 @@ async function getDebugConfiguration(
|
||||||
sourceFileMap[`/rustc/${commitHash}/`] = rustlib;
|
sourceFileMap[`/rustc/${commitHash}/`] = rustlib;
|
||||||
}
|
}
|
||||||
|
|
||||||
const debugConfig = knownEngines[debugEngine.id](
|
const provider = unwrapUndefinable(knownEngines[debugEngine.id]);
|
||||||
runnable,
|
const debugConfig = provider(runnable, simplifyPath(executable), env, sourceFileMap);
|
||||||
simplifyPath(executable),
|
|
||||||
env,
|
|
||||||
sourceFileMap
|
|
||||||
);
|
|
||||||
if (debugConfig.type in debugOptions.engineSettings) {
|
if (debugConfig.type in debugOptions.engineSettings) {
|
||||||
const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type];
|
const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type];
|
||||||
for (var key in settingsMap) {
|
for (var key in settingsMap) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import * as fs from "fs";
|
||||||
import { CtxInit } from "./ctx";
|
import { CtxInit } from "./ctx";
|
||||||
import * as ra from "./lsp_ext";
|
import * as ra from "./lsp_ext";
|
||||||
import { FetchDependencyListResult } from "./lsp_ext";
|
import { FetchDependencyListResult } from "./lsp_ext";
|
||||||
|
import { unwrapUndefinable } from "./undefinable";
|
||||||
|
|
||||||
export class RustDependenciesProvider
|
export class RustDependenciesProvider
|
||||||
implements vscode.TreeDataProvider<Dependency | DependencyFile>
|
implements vscode.TreeDataProvider<Dependency | DependencyFile>
|
||||||
|
@ -49,7 +50,12 @@ export class RustDependenciesProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
getTreeItem(element: Dependency | DependencyFile): vscode.TreeItem | Thenable<vscode.TreeItem> {
|
getTreeItem(element: Dependency | DependencyFile): vscode.TreeItem | Thenable<vscode.TreeItem> {
|
||||||
if (element.id! in this.dependenciesMap) return this.dependenciesMap[element.id!];
|
const dependenciesMap = this.dependenciesMap;
|
||||||
|
const elementId = element.id!;
|
||||||
|
if (elementId in dependenciesMap) {
|
||||||
|
const dependency = unwrapUndefinable(dependenciesMap[elementId]);
|
||||||
|
return dependency;
|
||||||
|
}
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import * as anser from "anser";
|
||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import { ProviderResult, Range, TextEditorDecorationType, ThemeColor, window } from "vscode";
|
import { ProviderResult, Range, TextEditorDecorationType, ThemeColor, window } from "vscode";
|
||||||
import { Ctx } from "./ctx";
|
import { Ctx } from "./ctx";
|
||||||
|
import { unwrapUndefinable } from "./undefinable";
|
||||||
|
|
||||||
export const URI_SCHEME = "rust-analyzer-diagnostics-view";
|
export const URI_SCHEME = "rust-analyzer-diagnostics-view";
|
||||||
|
|
||||||
|
@ -195,7 +196,8 @@ export class AnsiDecorationProvider implements vscode.Disposable {
|
||||||
// anser won't return both the RGB and the color name at the same time,
|
// anser won't return both the RGB and the color name at the same time,
|
||||||
// so just fake a single foreground control char with the palette number:
|
// so just fake a single foreground control char with the palette number:
|
||||||
const spans = anser.ansiToJson(`\x1b[38;5;${paletteColor}m`);
|
const spans = anser.ansiToJson(`\x1b[38;5;${paletteColor}m`);
|
||||||
const rgb = spans[1].fg;
|
const span = unwrapUndefinable(spans[1]);
|
||||||
|
const rgb = span.fg;
|
||||||
|
|
||||||
if (rgb) {
|
if (rgb) {
|
||||||
return `rgb(${rgb})`;
|
return `rgb(${rgb})`;
|
||||||
|
|
19
editors/code/src/nullable.ts
Normal file
19
editors/code/src/nullable.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
export type NotNull<T> = T extends null ? never : T;
|
||||||
|
|
||||||
|
export type Nullable<T> = T | null;
|
||||||
|
|
||||||
|
function isNotNull<T>(input: Nullable<T>): input is NotNull<T> {
|
||||||
|
return input !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function expectNotNull<T>(input: Nullable<T>, msg: string): NotNull<T> {
|
||||||
|
if (isNotNull(input)) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new TypeError(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unwrapNullable<T>(input: Nullable<T>): NotNull<T> {
|
||||||
|
return expectNotNull(input, `unwrapping \`null\``);
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import * as tasks from "./tasks";
|
||||||
import { CtxInit } from "./ctx";
|
import { CtxInit } from "./ctx";
|
||||||
import { makeDebugConfig } from "./debug";
|
import { makeDebugConfig } from "./debug";
|
||||||
import { Config, RunnableEnvCfg } from "./config";
|
import { Config, RunnableEnvCfg } from "./config";
|
||||||
|
import { unwrapUndefinable } from "./undefinable";
|
||||||
|
|
||||||
const quickPickButtons = [
|
const quickPickButtons = [
|
||||||
{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configuration." },
|
{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configuration." },
|
||||||
|
@ -68,12 +69,14 @@ export async function selectRunnable(
|
||||||
quickPick.onDidHide(() => close()),
|
quickPick.onDidHide(() => close()),
|
||||||
quickPick.onDidAccept(() => close(quickPick.selectedItems[0])),
|
quickPick.onDidAccept(() => close(quickPick.selectedItems[0])),
|
||||||
quickPick.onDidTriggerButton(async (_button) => {
|
quickPick.onDidTriggerButton(async (_button) => {
|
||||||
await makeDebugConfig(ctx, quickPick.activeItems[0].runnable);
|
const runnable = unwrapUndefinable(quickPick.activeItems[0]).runnable;
|
||||||
|
await makeDebugConfig(ctx, runnable);
|
||||||
close();
|
close();
|
||||||
}),
|
}),
|
||||||
quickPick.onDidChangeActive((active) => {
|
quickPick.onDidChangeActive((activeList) => {
|
||||||
if (showButtons && active.length > 0) {
|
if (showButtons && activeList.length > 0) {
|
||||||
if (active[0].label.startsWith("cargo")) {
|
const active = unwrapUndefinable(activeList[0]);
|
||||||
|
if (active.label.startsWith("cargo")) {
|
||||||
// save button makes no sense for `cargo test` or `cargo check`
|
// save button makes no sense for `cargo test` or `cargo check`
|
||||||
quickPick.buttons = [];
|
quickPick.buttons = [];
|
||||||
} else if (quickPick.buttons.length === 0) {
|
} else if (quickPick.buttons.length === 0) {
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
|
|
||||||
import { assert } from "./util";
|
import { assert } from "./util";
|
||||||
|
import { unwrapUndefinable } from "./undefinable";
|
||||||
|
|
||||||
export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) {
|
export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) {
|
||||||
if (edit.entries().length === 1) {
|
if (edit.entries().length === 1) {
|
||||||
const [uri, edits] = edit.entries()[0];
|
const [uri, edits] = unwrapUndefinable(edit.entries()[0]);
|
||||||
const editor = await editorFromUri(uri);
|
const editor = await editorFromUri(uri);
|
||||||
if (editor) await applySnippetTextEdits(editor, edits);
|
if (editor) await applySnippetTextEdits(editor, edits);
|
||||||
return;
|
return;
|
||||||
|
@ -68,7 +69,8 @@ export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vs
|
||||||
});
|
});
|
||||||
if (selections.length > 0) editor.selections = selections;
|
if (selections.length > 0) editor.selections = selections;
|
||||||
if (selections.length === 1) {
|
if (selections.length === 1) {
|
||||||
editor.revealRange(selections[0], vscode.TextEditorRevealType.InCenterIfOutsideViewport);
|
const selection = unwrapUndefinable(selections[0]);
|
||||||
|
editor.revealRange(selection, vscode.TextEditorRevealType.InCenterIfOutsideViewport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import * as vscode from "vscode";
|
||||||
import * as toolchain from "./toolchain";
|
import * as toolchain from "./toolchain";
|
||||||
import { Config } from "./config";
|
import { Config } from "./config";
|
||||||
import { log } from "./util";
|
import { log } from "./util";
|
||||||
|
import { unwrapUndefinable } from "./undefinable";
|
||||||
|
|
||||||
// This ends up as the `type` key in tasks.json. RLS also uses `cargo` and
|
// This ends up as the `type` key in tasks.json. RLS also uses `cargo` and
|
||||||
// our configuration should be compatible with it so use the same key.
|
// our configuration should be compatible with it so use the same key.
|
||||||
|
@ -120,7 +121,8 @@ export async function buildCargoTask(
|
||||||
|
|
||||||
const fullCommand = [...cargoCommand, ...args];
|
const fullCommand = [...cargoCommand, ...args];
|
||||||
|
|
||||||
exec = new vscode.ProcessExecution(fullCommand[0], fullCommand.slice(1), definition);
|
const processName = unwrapUndefinable(fullCommand[0]);
|
||||||
|
exec = new vscode.ProcessExecution(processName, fullCommand.slice(1), definition);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new vscode.Task(
|
return new vscode.Task(
|
||||||
|
|
|
@ -4,6 +4,8 @@ import * as path from "path";
|
||||||
import * as readline from "readline";
|
import * as readline from "readline";
|
||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import { execute, log, memoizeAsync } from "./util";
|
import { execute, log, memoizeAsync } from "./util";
|
||||||
|
import { unwrapNullable } from "./nullable";
|
||||||
|
import { unwrapUndefinable } from "./undefinable";
|
||||||
|
|
||||||
interface CompilationArtifact {
|
interface CompilationArtifact {
|
||||||
fileName: string;
|
fileName: string;
|
||||||
|
@ -93,7 +95,8 @@ export class Cargo {
|
||||||
throw new Error("Multiple compilation artifacts are not supported.");
|
throw new Error("Multiple compilation artifacts are not supported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return artifacts[0].fileName;
|
const artifact = unwrapUndefinable(artifacts[0]);
|
||||||
|
return artifact.fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async runCargo(
|
private async runCargo(
|
||||||
|
@ -142,7 +145,9 @@ export async function getRustcId(dir: string): Promise<string> {
|
||||||
const data = await execute(`${rustcPath} -V -v`, { cwd: dir });
|
const data = await execute(`${rustcPath} -V -v`, { cwd: dir });
|
||||||
const rx = /commit-hash:\s(.*)$/m;
|
const rx = /commit-hash:\s(.*)$/m;
|
||||||
|
|
||||||
return rx.exec(data)![1];
|
const result = unwrapNullable(rx.exec(data));
|
||||||
|
const first = unwrapUndefinable(result[1]);
|
||||||
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Mirrors `toolchain::cargo()` implementation */
|
/** Mirrors `toolchain::cargo()` implementation */
|
||||||
|
|
19
editors/code/src/undefinable.ts
Normal file
19
editors/code/src/undefinable.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
export type NotUndefined<T> = T extends undefined ? never : T;
|
||||||
|
|
||||||
|
export type Undefinable<T> = T | undefined;
|
||||||
|
|
||||||
|
function isNotUndefined<T>(input: Undefinable<T>): input is NotUndefined<T> {
|
||||||
|
return input !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function expectNotUndefined<T>(input: Undefinable<T>, msg: string): NotUndefined<T> {
|
||||||
|
if (isNotUndefined(input)) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new TypeError(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unwrapUndefinable<T>(input: Undefinable<T>): NotUndefined<T> {
|
||||||
|
return expectNotUndefined(input, `unwrapping \`undefined\``);
|
||||||
|
}
|
|
@ -14,8 +14,7 @@
|
||||||
// to update typescript version without any code change.
|
// to update typescript version without any code change.
|
||||||
"useUnknownInCatchVariables": false,
|
"useUnknownInCatchVariables": false,
|
||||||
"exactOptionalPropertyTypes": false,
|
"exactOptionalPropertyTypes": false,
|
||||||
"noPropertyAccessFromIndexSignature": false,
|
"noPropertyAccessFromIndexSignature": false
|
||||||
"noUncheckedIndexedAccess": false
|
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", ".vscode-test"],
|
"exclude": ["node_modules", ".vscode-test"],
|
||||||
"include": ["src", "tests"]
|
"include": ["src", "tests"]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue