aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/util.ts
diff options
context:
space:
mode:
Diffstat (limited to 'editors/code/src/util.ts')
-rw-r--r--editors/code/src/util.ts64
1 files changed, 54 insertions, 10 deletions
diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts
index 352ef9162..970fedb37 100644
--- a/editors/code/src/util.ts
+++ b/editors/code/src/util.ts
@@ -2,6 +2,7 @@ import * as lc from "vscode-languageclient";
2import * as vscode from "vscode"; 2import * as vscode from "vscode";
3import { strict as nativeAssert } from "assert"; 3import { strict as nativeAssert } from "assert";
4import { spawnSync } from "child_process"; 4import { spawnSync } from "child_process";
5import { inspect } from "util";
5 6
6export function assert(condition: boolean, explanation: string): asserts condition { 7export function assert(condition: boolean, explanation: string): asserts condition {
7 try { 8 try {
@@ -14,22 +15,46 @@ export function assert(condition: boolean, explanation: string): asserts conditi
14 15
15export const log = new class { 16export const log = new class {
16 private enabled = true; 17 private enabled = true;
18 private readonly output = vscode.window.createOutputChannel("Rust Analyzer Client");
17 19
18 setEnabled(yes: boolean): void { 20 setEnabled(yes: boolean): void {
19 log.enabled = yes; 21 log.enabled = yes;
20 } 22 }
21 23
22 debug(message?: any, ...optionalParams: any[]): void { 24 // Hint: the type [T, ...T[]] means a non-empty array
25 debug(...msg: [unknown, ...unknown[]]): void {
23 if (!log.enabled) return; 26 if (!log.enabled) return;
24 // eslint-disable-next-line no-console 27 log.write("DEBUG", ...msg);
25 console.log(message, ...optionalParams); 28 log.output.toString();
26 } 29 }
27 30
28 error(message?: any, ...optionalParams: any[]): void { 31 info(...msg: [unknown, ...unknown[]]): void {
29 if (!log.enabled) return; 32 log.write("INFO", ...msg);
33 }
34
35 warn(...msg: [unknown, ...unknown[]]): void {
36 debugger;
37 log.write("WARN", ...msg);
38 }
39
40 error(...msg: [unknown, ...unknown[]]): void {
30 debugger; 41 debugger;
31 // eslint-disable-next-line no-console 42 log.write("ERROR", ...msg);
32 console.error(message, ...optionalParams); 43 log.output.show(true);
44 }
45
46 private write(label: string, ...messageParts: unknown[]): void {
47 const message = messageParts.map(log.stringify).join(" ");
48 const dateTime = new Date().toLocaleString();
49 log.output.appendLine(`${label} [${dateTime}]: ${message}`);
50 }
51
52 private stringify(val: unknown): string {
53 if (typeof val === "string") return val;
54 return inspect(val, {
55 colors: false,
56 depth: 6, // heuristic
57 });
33 } 58 }
34}; 59};
35 60
@@ -47,7 +72,7 @@ export async function sendRequestWithRetry<TParam, TRet>(
47 ); 72 );
48 } catch (error) { 73 } catch (error) {
49 if (delay === null) { 74 if (delay === null) {
50 log.error("LSP request timed out", { method: reqType.method, param, error }); 75 log.warn("LSP request timed out", { method: reqType.method, param, error });
51 throw error; 76 throw error;
52 } 77 }
53 78
@@ -56,7 +81,7 @@ export async function sendRequestWithRetry<TParam, TRet>(
56 } 81 }
57 82
58 if (error.code !== lc.ErrorCodes.ContentModified) { 83 if (error.code !== lc.ErrorCodes.ContentModified) {
59 log.error("LSP request failed", { method: reqType.method, param, error }); 84 log.warn("LSP request failed", { method: reqType.method, param, error });
60 throw error; 85 throw error;
61 } 86 }
62 87
@@ -90,7 +115,8 @@ export function isValidExecutable(path: string): boolean {
90 115
91 const res = spawnSync(path, ["--version"], { encoding: 'utf8' }); 116 const res = spawnSync(path, ["--version"], { encoding: 'utf8' });
92 117
93 log.debug(res, "--version output:", res.output); 118 const printOutput = res.error && (res.error as any).code !== 'ENOENT' ? log.warn : log.debug;
119 printOutput(path, "--version:", res);
94 120
95 return res.status === 0; 121 return res.status === 0;
96} 122}
@@ -99,3 +125,21 @@ export function isValidExecutable(path: string): boolean {
99export function setContextValue(key: string, value: any): Thenable<void> { 125export function setContextValue(key: string, value: any): Thenable<void> {
100 return vscode.commands.executeCommand('setContext', key, value); 126 return vscode.commands.executeCommand('setContext', key, value);
101} 127}
128
129/**
130 * Returns a higher-order function that caches the results of invoking the
131 * underlying function.
132 */
133export function memoize<Ret, TThis, Param extends string>(func: (this: TThis, arg: Param) => Ret) {
134 const cache = new Map<string, Ret>();
135
136 return function(this: TThis, arg: Param) {
137 const cached = cache.get(arg);
138 if (cached) return cached;
139
140 const result = func.call(this, arg);
141 cache.set(arg, result);
142
143 return result;
144 };
145}