From 05000ccb75cda5f2b587e568a7c9b2891699c9a8 Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Wed, 18 Mar 2020 16:02:30 -0600 Subject: [PATCH 1/9] Add typing annotation for eslint config --- editors/code/.eslintrc.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/editors/code/.eslintrc.js b/editors/code/.eslintrc.js index c6bf410f4b56..503fcf1bb7ad 100644 --- a/editors/code/.eslintrc.js +++ b/editors/code/.eslintrc.js @@ -1,3 +1,6 @@ +// @ts-check + +/** @type { import('eslint').Linter.Config } */ module.exports = { "env": { "es6": true, From 6472051bb02c8cbff8773ec6d66cfc1cfd417e81 Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Wed, 18 Mar 2020 16:03:33 -0600 Subject: [PATCH 2/9] Use recommended eslint and typescript-eslint rules --- editors/code/.eslintrc.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/editors/code/.eslintrc.js b/editors/code/.eslintrc.js index 503fcf1bb7ad..a241cda61f04 100644 --- a/editors/code/.eslintrc.js +++ b/editors/code/.eslintrc.js @@ -14,6 +14,12 @@ module.exports = { "plugins": [ "@typescript-eslint" ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "plugin:@typescript-eslint/recommended" + ], "rules": { "camelcase": ["error"], "eqeqeq": ["error", "always", { "null": "ignore" }], @@ -32,10 +38,13 @@ module.exports = { } } ], - "@typescript-eslint/semi": [ - "error", - "always" - ], - "@typescript-eslint/no-unnecessary-type-assertion": "error" + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/no-namespace": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/no-unnecessary-type-assertion": "error", + "@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }], + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/unbound-method": "off", + "@typescript-eslint/semi": ["error", "always"] } }; From 512d3601f5811dcf5686e737cb63b363107a0ffc Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Wed, 18 Mar 2020 16:04:16 -0600 Subject: [PATCH 3/9] Fix lints --- editors/code/src/client.ts | 8 +++-- editors/code/src/color_theme.ts | 10 +++--- editors/code/src/commands/analyzer_status.ts | 4 +-- editors/code/src/commands/expand_macro.ts | 4 +-- editors/code/src/commands/index.ts | 16 ++++----- editors/code/src/commands/join_lines.ts | 4 +-- editors/code/src/commands/matching_brace.ts | 4 +-- editors/code/src/commands/on_enter.ts | 6 ++-- editors/code/src/commands/parent_module.ts | 4 +-- editors/code/src/commands/runnables.ts | 12 +++---- editors/code/src/commands/server_version.ts | 4 +-- editors/code/src/commands/ssr.ts | 4 +-- editors/code/src/commands/syntax_tree.ts | 6 ++-- editors/code/src/config.ts | 36 ++++++++++---------- editors/code/src/ctx.ts | 9 ++--- editors/code/src/highlighting.ts | 14 ++++---- editors/code/src/inlay_hints.ts | 18 +++++----- editors/code/src/installation/downloads.ts | 2 +- editors/code/src/installation/extension.ts | 4 +-- editors/code/src/main.ts | 6 ++-- editors/code/src/persistent_state.ts | 4 +-- editors/code/src/rust-analyzer-api.ts | 4 +-- editors/code/src/source_change.ts | 2 +- editors/code/src/status_display.ts | 14 ++++---- editors/code/src/util.ts | 21 ++++++------ 25 files changed, 112 insertions(+), 108 deletions(-) diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 08d821dd0a86..c6fb88f81029 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -5,7 +5,7 @@ import { Config } from './config'; import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed'; import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed'; -export async function createClient(config: Config, serverPath: string): Promise { +export function createClient(config: Config, serverPath: string): lc.LanguageClient { // '.' Is the fallback if no folder is open // TODO?: Workspace folders support Uri's (eg: file://test.txt). // It might be a good idea to test if the uri points to a file. @@ -55,7 +55,7 @@ export async function createClient(config: Config, serverPath: string): Promise< if (res === undefined) throw new Error('busy'); return res; } - } as any + } as lc.Middleware }; const res = new lc.LanguageClient( @@ -65,6 +65,7 @@ export async function createClient(config: Config, serverPath: string): Promise< clientOptions, ); + /* eslint-disable @typescript-eslint/ban-ts-ignore */ // HACK: This is an awful way of filtering out the decorations notifications // However, pending proper support, this is the most effecitve approach // Proper support for this would entail a change to vscode-languageclient to allow not notifying on certain messages @@ -72,7 +73,7 @@ export async function createClient(config: Config, serverPath: string): Promise< // This also requires considering our settings strategy, which is work which needs doing // @ts-ignore The tracer is private to vscode-languageclient, but we need access to it to not log publishDecorations requests res._tracer = { - log: (messageOrDataObject: string | unknown, data?: string) => { + log: (messageOrDataObject: string | unknown, data?: string): void => { if (typeof messageOrDataObject === 'string') { if ( messageOrDataObject.includes( @@ -93,6 +94,7 @@ export async function createClient(config: Config, serverPath: string): Promise< } }, }; + /* eslint-enable @typescript-eslint/ban-ts-ignore */ // To turn on all proposed features use: res.registerProposedFeatures(); // Here we want to just enable CallHierarchyFeature since it is available on stable. diff --git a/editors/code/src/color_theme.ts b/editors/code/src/color_theme.ts index 5b9327b28a4a..561f6909d7a1 100644 --- a/editors/code/src/color_theme.ts +++ b/editors/code/src/color_theme.ts @@ -53,7 +53,7 @@ export class ColorTheme { return res; } - mergeFrom(other: ColorTheme) { + mergeFrom(other: ColorTheme): void { other.rules.forEach((value, key) => { const merged = mergeRuleSettings(this.rules.get(key), value); this.rules.set(key, merged); @@ -74,8 +74,8 @@ function loadThemeNamed(themeName: string): ColorTheme { .filter(isTheme) .flatMap( ext => ext.packageJSON.contributes.themes - .filter((it: any) => (it.id || it.label) === themeName) - .map((it: any) => path.join(ext.extensionPath, it.path)) + .filter((it: { id: string; label: string }) => (it.id || it.label) === themeName) + .map((it: { path: string }) => path.join(ext.extensionPath, it.path)) ); const res = new ColorTheme(); @@ -83,10 +83,10 @@ function loadThemeNamed(themeName: string): ColorTheme { res.mergeFrom(loadThemeFile(themePath)); } - const globalCustomizations: any = vscode.workspace.getConfiguration('editor').get('tokenColorCustomizations'); + const globalCustomizations: undefined | { textMateRules: undefined | TextMateRule[] } = vscode.workspace.getConfiguration('editor').get('tokenColorCustomizations'); res.mergeFrom(ColorTheme.fromRules(globalCustomizations?.textMateRules ?? [])); - const themeCustomizations: any = vscode.workspace.getConfiguration('editor.tokenColorCustomizations').get(`[${themeName}]`); + const themeCustomizations: undefined | { textMateRules: undefined | TextMateRule[] } = vscode.workspace.getConfiguration('editor.tokenColorCustomizations').get(`[${themeName}]`); res.mergeFrom(ColorTheme.fromRules(themeCustomizations?.textMateRules ?? [])); diff --git a/editors/code/src/commands/analyzer_status.ts b/editors/code/src/commands/analyzer_status.ts index 1c6ea399b1c7..73b061534bec 100644 --- a/editors/code/src/commands/analyzer_status.ts +++ b/editors/code/src/commands/analyzer_status.ts @@ -4,7 +4,7 @@ import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; // Shows status of rust-analyzer (for debugging) -export function analyzerStatus(ctx: Ctx): Cmd { +export function analyzerStatus(ctx: Ctx): Cmd<[]> { let poller: NodeJS.Timer | null = null; const tdcp = new TextDocumentContentProvider(ctx); @@ -23,7 +23,7 @@ export function analyzerStatus(ctx: Ctx): Cmd { }, }); - return async function handle() { + return async function handle(): Promise { if (poller == null) { poller = setInterval(() => tdcp.eventEmitter.fire(tdcp.uri), 1000); } diff --git a/editors/code/src/commands/expand_macro.ts b/editors/code/src/commands/expand_macro.ts index 23f2ef1d5e36..feaffa039140 100644 --- a/editors/code/src/commands/expand_macro.ts +++ b/editors/code/src/commands/expand_macro.ts @@ -6,7 +6,7 @@ import { Ctx, Cmd } from '../ctx'; // Opens the virtual file that will show the syntax tree // // The contents of the file come from the `TextDocumentContentProvider` -export function expandMacro(ctx: Ctx): Cmd { +export function expandMacro(ctx: Ctx): Cmd<[]> { const tdcp = new TextDocumentContentProvider(ctx); ctx.pushCleanup( vscode.workspace.registerTextDocumentContentProvider( @@ -15,7 +15,7 @@ export function expandMacro(ctx: Ctx): Cmd { ), ); - return async () => { + return async (): Promise => { const document = await vscode.workspace.openTextDocument(tdcp.uri); tdcp.eventEmitter.fire(tdcp.uri); return vscode.window.showTextDocument( diff --git a/editors/code/src/commands/index.ts b/editors/code/src/commands/index.ts index bdb7fc3b03b8..bce1bff45414 100644 --- a/editors/code/src/commands/index.ts +++ b/editors/code/src/commands/index.ts @@ -16,12 +16,12 @@ export * from './runnables'; export * from './ssr'; export * from './server_version'; -export function collectGarbage(ctx: Ctx): Cmd { - return async () => ctx.client.sendRequest(ra.collectGarbage, null); +export function collectGarbage(ctx: Ctx): Cmd<[]> { + return async (): Promise => ctx.client.sendRequest(ra.collectGarbage, null); } -export function showReferences(ctx: Ctx): Cmd { - return (uri: string, position: lc.Position, locations: lc.Location[]) => { +export function showReferences(ctx: Ctx): Cmd<[string, lc.Position, lc.Location[]]> { + return (uri: string, position: lc.Position, locations: lc.Location[]): void => { const client = ctx.client; if (client) { vscode.commands.executeCommand( @@ -34,14 +34,14 @@ export function showReferences(ctx: Ctx): Cmd { }; } -export function applySourceChange(ctx: Ctx): Cmd { - return async (change: ra.SourceChange) => { +export function applySourceChange(ctx: Ctx): Cmd<[ra.SourceChange]> { + return async (change: ra.SourceChange): Promise => { await sourceChange.applySourceChange(ctx, change); }; } -export function selectAndApplySourceChange(ctx: Ctx): Cmd { - return async (changes: ra.SourceChange[]) => { +export function selectAndApplySourceChange(ctx: Ctx): Cmd<[ra.SourceChange[]]> { + return async (changes: ra.SourceChange[]): Promise => { if (changes.length === 1) { await sourceChange.applySourceChange(ctx, changes[0]); } else if (changes.length > 0) { diff --git a/editors/code/src/commands/join_lines.ts b/editors/code/src/commands/join_lines.ts index de0614653d6b..dca8f2153abf 100644 --- a/editors/code/src/commands/join_lines.ts +++ b/editors/code/src/commands/join_lines.ts @@ -3,8 +3,8 @@ import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; import { applySourceChange } from '../source_change'; -export function joinLines(ctx: Ctx): Cmd { - return async () => { +export function joinLines(ctx: Ctx): Cmd<[]> { + return async (): Promise => { const editor = ctx.activeRustEditor; const client = ctx.client; if (!editor || !client) return; diff --git a/editors/code/src/commands/matching_brace.ts b/editors/code/src/commands/matching_brace.ts index a60776e2d4d1..1b8a4be5f121 100644 --- a/editors/code/src/commands/matching_brace.ts +++ b/editors/code/src/commands/matching_brace.ts @@ -3,8 +3,8 @@ import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; -export function matchingBrace(ctx: Ctx): Cmd { - return async () => { +export function matchingBrace(ctx: Ctx): Cmd<[]> { + return async (): Promise => { const editor = ctx.activeRustEditor; const client = ctx.client; if (!editor || !client) return; diff --git a/editors/code/src/commands/on_enter.ts b/editors/code/src/commands/on_enter.ts index 285849db7074..a857b932ab76 100644 --- a/editors/code/src/commands/on_enter.ts +++ b/editors/code/src/commands/on_enter.ts @@ -4,7 +4,7 @@ import * as ra from '../rust-analyzer-api'; import { applySourceChange } from '../source_change'; import { Cmd, Ctx } from '../ctx'; -async function handleKeypress(ctx: Ctx) { +async function handleKeypress(ctx: Ctx): Promise { const editor = ctx.activeRustEditor; const client = ctx.client; @@ -25,8 +25,8 @@ async function handleKeypress(ctx: Ctx) { return true; } -export function onEnter(ctx: Ctx): Cmd { - return async () => { +export function onEnter(ctx: Ctx): Cmd<[]> { + return async (): Promise => { if (await handleKeypress(ctx)) return; await vscode.commands.executeCommand('default:type', { text: '\n' }); diff --git a/editors/code/src/commands/parent_module.ts b/editors/code/src/commands/parent_module.ts index 8f78ddd71c63..df57ecb8f568 100644 --- a/editors/code/src/commands/parent_module.ts +++ b/editors/code/src/commands/parent_module.ts @@ -3,8 +3,8 @@ import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; -export function parentModule(ctx: Ctx): Cmd { - return async () => { +export function parentModule(ctx: Ctx): Cmd<[]> { + return async (): Promise => { const editor = ctx.activeRustEditor; const client = ctx.client; if (!editor || !client) return; diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts index 357155163d76..ae92f7a15311 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/commands/runnables.ts @@ -4,10 +4,10 @@ import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; -export function run(ctx: Ctx): Cmd { +export function run(ctx: Ctx): Cmd<[]> { let prevRunnable: RunnableQuickPick | undefined; - return async () => { + return async (): Promise => { const editor = ctx.activeRustEditor; const client = ctx.client; if (!editor || !client) return; @@ -45,8 +45,8 @@ export function run(ctx: Ctx): Cmd { }; } -export function runSingle(ctx: Ctx): Cmd { - return async (runnable: ra.Runnable) => { +export function runSingle(ctx: Ctx): Cmd<[ra.Runnable]> { + return async (runnable: ra.Runnable): Promise => { const editor = ctx.activeRustEditor; if (!editor) return; @@ -62,8 +62,8 @@ export function runSingle(ctx: Ctx): Cmd { }; } -export function debugSingle(ctx: Ctx): Cmd { - return async (config: ra.Runnable) => { +export function debugSingle(ctx: Ctx): Cmd<[ra.Runnable]> { + return async (config: ra.Runnable): Promise => { const editor = ctx.activeRustEditor; if (!editor) return; diff --git a/editors/code/src/commands/server_version.ts b/editors/code/src/commands/server_version.ts index 83b1acf67709..9a1b9be8d56d 100644 --- a/editors/code/src/commands/server_version.ts +++ b/editors/code/src/commands/server_version.ts @@ -3,8 +3,8 @@ import { ensureServerBinary } from '../installation/server'; import { Ctx, Cmd } from '../ctx'; import { spawnSync } from 'child_process'; -export function serverVersion(ctx: Ctx): Cmd { - return async () => { +export function serverVersion(ctx: Ctx): Cmd<[]> { + return async (): Promise => { const binaryPath = await ensureServerBinary(ctx.config, ctx.state); if (binaryPath == null) { diff --git a/editors/code/src/commands/ssr.ts b/editors/code/src/commands/ssr.ts index 6fee051fdf66..61e1ed3a6c82 100644 --- a/editors/code/src/commands/ssr.ts +++ b/editors/code/src/commands/ssr.ts @@ -4,8 +4,8 @@ import * as ra from "../rust-analyzer-api"; import { Ctx, Cmd } from '../ctx'; import { applySourceChange } from '../source_change'; -export function ssr(ctx: Ctx): Cmd { - return async () => { +export function ssr(ctx: Ctx): Cmd<[]> { + return async (): Promise => { const client = ctx.client; if (!client) return; diff --git a/editors/code/src/commands/syntax_tree.ts b/editors/code/src/commands/syntax_tree.ts index 2e08e8f115b6..2ec1c468b9fa 100644 --- a/editors/code/src/commands/syntax_tree.ts +++ b/editors/code/src/commands/syntax_tree.ts @@ -7,7 +7,7 @@ import { isRustDocument } from '../util'; // Opens the virtual file that will show the syntax tree // // The contents of the file come from the `TextDocumentContentProvider` -export function syntaxTree(ctx: Ctx): Cmd { +export function syntaxTree(ctx: Ctx): Cmd<[]> { const tdcp = new TextDocumentContentProvider(ctx); ctx.pushCleanup( @@ -36,7 +36,7 @@ export function syntaxTree(ctx: Ctx): Cmd { ctx.subscriptions, ); - return async () => { + return async (): Promise => { const editor = vscode.window.activeTextEditor; const rangeEnabled = !!(editor && !editor.selection.isEmpty); @@ -58,7 +58,7 @@ export function syntaxTree(ctx: Ctx): Cmd { // We need to order this after LS updates, but there's no API for that. // Hence, good old setTimeout. -function afterLs(f: () => void) { +function afterLs(f: () => void): void { setTimeout(f, 10); } diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index b45b14bef38d..9aff632a3cf8 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -53,11 +53,11 @@ export class Config { /** * Either `nightly` or `YYYY-MM-DD` (i.e. `stable` release) */ - readonly extensionReleaseTag: string = (() => { + readonly extensionReleaseTag: string = ((): string => { if (this.packageJsonVersion.endsWith(NIGHTLY_TAG)) return NIGHTLY_TAG; const realVersionRegexp = /^\d+\.\d+\.(\d{4})(\d{2})(\d{2})/; - const [, yyyy, mm, dd] = this.packageJsonVersion.match(realVersionRegexp)!; + const [, yyyy, mm, dd] = realVersionRegexp.exec(this.packageJsonVersion)!; return `${yyyy}-${mm}-${dd}`; })(); @@ -69,7 +69,7 @@ export class Config { this.refreshConfig(); } - private refreshConfig() { + private refreshConfig(): void { this.cfg = vscode.workspace.getConfiguration(this.rootSection); const enableLogging = this.cfg.get("trace.extension") as boolean; log.setEnabled(enableLogging); @@ -79,7 +79,7 @@ export class Config { ); } - private async onConfigChange(event: vscode.ConfigurationChangeEvent) { + private async onConfigChange(event: vscode.ConfigurationChangeEvent): Promise { this.refreshConfig(); const requiresReloadOpt = this.requiresReloadOpts.find( @@ -98,7 +98,7 @@ export class Config { } } - private static replaceTildeWithHomeDir(path: string) { + private static replaceTildeWithHomeDir(path: string): string { if (path.startsWith("~/")) { return os.homedir() + path.slice("~".length); } @@ -186,13 +186,13 @@ export class Config { // We don't do runtime config validation here for simplicity. More on stackoverflow: // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension - private get serverPath() { return this.cfg.get("serverPath") as null | string; } - get updatesChannel() { return this.cfg.get("updates.channel") as UpdatesChannel; } - get askBeforeDownload() { return this.cfg.get("updates.askBeforeDownload") as boolean; } - get highlightingSemanticTokens() { return this.cfg.get("highlighting.semanticTokens") as boolean; } - get highlightingOn() { return this.cfg.get("highlightingOn") as boolean; } - get rainbowHighlightingOn() { return this.cfg.get("rainbowHighlightingOn") as boolean; } - get lruCapacity() { return this.cfg.get("lruCapacity") as null | number; } + private get serverPath(): null | string { return this.cfg.get("serverPath") as null | string; } + get updatesChannel(): UpdatesChannel { return this.cfg.get("updates.channel") as UpdatesChannel; } + get askBeforeDownload(): boolean { return this.cfg.get("updates.askBeforeDownload") as boolean; } + get highlightingSemanticTokens(): boolean { return this.cfg.get("highlighting.semanticTokens") as boolean; } + get highlightingOn(): boolean { return this.cfg.get("highlightingOn") as boolean; } + get rainbowHighlightingOn(): boolean { return this.cfg.get("rainbowHighlightingOn") as boolean; } + get lruCapacity(): null | number { return this.cfg.get("lruCapacity") as null | number; } get inlayHints(): InlayHintOptions { return { typeHints: this.cfg.get("inlayHints.typeHints") as boolean, @@ -200,11 +200,11 @@ export class Config { maxLength: this.cfg.get("inlayHints.maxLength") as null | number, }; } - get excludeGlobs() { return this.cfg.get("excludeGlobs") as string[]; } - get useClientWatching() { return this.cfg.get("useClientWatching") as boolean; } - get featureFlags() { return this.cfg.get("featureFlags") as Record; } - get rustfmtArgs() { return this.cfg.get("rustfmtArgs") as string[]; } - get loadOutDirsFromCheck() { return this.cfg.get("loadOutDirsFromCheck") as boolean; } + get excludeGlobs(): string[] { return this.cfg.get("excludeGlobs") as string[]; } + get useClientWatching(): boolean { return this.cfg.get("useClientWatching") as boolean; } + get featureFlags(): Record { return this.cfg.get("featureFlags") as Record; } + get rustfmtArgs(): string[] { return this.cfg.get("rustfmtArgs") as string[]; } + get loadOutDirsFromCheck(): boolean { return this.cfg.get("loadOutDirsFromCheck") as boolean; } get cargoWatchOptions(): CargoWatchOptions { return { @@ -225,5 +225,5 @@ export class Config { } // for internal use - get withSysroot() { return this.cfg.get("withSysroot", true) as boolean; } + get withSysroot(): boolean { return this.cfg.get("withSysroot", true) as boolean; } } diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index c929ab0632d8..5b3a3f8c6b44 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -17,7 +17,7 @@ export class Ctx { } static async create(config: Config, state: PersistentState, extCtx: vscode.ExtensionContext, serverPath: string): Promise { - const client = await createClient(config, serverPath); + const client = createClient(config, serverPath); const res = new Ctx(config, state, extCtx, client); res.pushCleanup(client.start()); await client.onReady(); @@ -35,7 +35,7 @@ export class Ctx { return vscode.window.visibleTextEditors.filter(isRustEditor); } - registerCommand(name: string, factory: (ctx: Ctx) => Cmd) { + registerCommand(name: string, factory: (ctx: Ctx) => Cmd): void { const fullName = `rust-analyzer.${name}`; const cmd = factory(this); const d = vscode.commands.registerCommand(fullName, cmd); @@ -50,7 +50,7 @@ export class Ctx { return this.extCtx.subscriptions; } - pushCleanup(d: Disposable) { + pushCleanup(d: Disposable): void { this.extCtx.subscriptions.push(d); } } @@ -58,4 +58,5 @@ export class Ctx { export interface Disposable { dispose(): void; } -export type Cmd = (...args: any[]) => unknown; + +export type Cmd = (...args: T) => unknown; diff --git a/editors/code/src/highlighting.ts b/editors/code/src/highlighting.ts index ea2dfc0e39f6..0c984c8747a1 100644 --- a/editors/code/src/highlighting.ts +++ b/editors/code/src/highlighting.ts @@ -6,7 +6,7 @@ import { ColorTheme, TextMateRuleSettings } from './color_theme'; import { Ctx } from './ctx'; import { sendRequestWithRetry, isRustDocument } from './util'; -export function activateHighlighting(ctx: Ctx) { +export function activateHighlighting(ctx: Ctx): void { const highlighter = new Highlighter(ctx); ctx.client.onNotification(ra.publishDecorations, params => { @@ -54,9 +54,9 @@ export function activateHighlighting(ctx: Ctx) { } // Based on this HSL-based color generator: https://gist.github.com/bendc/76c48ce53299e6078a76 -function fancify(seed: string, shade: 'light' | 'dark') { +function fancify(seed: string, shade: 'light' | 'dark'): string { const random = randomU32Numbers(hashString(seed)); - const randomInt = (min: number, max: number) => { + const randomInt = (min: number, max: number): number => { return Math.abs(random()) % (max - min + 1) + min; }; @@ -77,7 +77,7 @@ class Highlighter { this.ctx = ctx; } - public removeHighlights() { + public removeHighlights(): void { if (this.decorations == null) { return; } @@ -90,7 +90,7 @@ class Highlighter { this.decorations = null; } - public setHighlights(editor: vscode.TextEditor, highlights: ra.Decoration[]) { + public setHighlights(editor: vscode.TextEditor, highlights: ra.Decoration[]): void { const client = this.ctx.client; if (!client) return; // Initialize decorations if necessary @@ -234,9 +234,9 @@ const TAG_TO_SCOPES = new Map([ ["keyword.control", ["keyword.control"]], ]); -function randomU32Numbers(seed: number) { +function randomU32Numbers(seed: number): () => number { let random = seed | 0; - return () => { + return (): number => { random ^= random << 13; random ^= random >> 17; random ^= random << 5; diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts index b19b09ad5619..ac792b533b6f 100644 --- a/editors/code/src/inlay_hints.ts +++ b/editors/code/src/inlay_hints.ts @@ -6,16 +6,16 @@ import { Ctx, Disposable } from './ctx'; import { sendRequestWithRetry, isRustDocument, RustDocument, RustEditor } from './util'; -export function activateInlayHints(ctx: Ctx) { +export function activateInlayHints(ctx: Ctx): void { const maybeUpdater = { updater: null as null | HintsUpdater, - onConfigChange() { + onConfigChange(): void { if (!ctx.config.inlayHints.typeHints && !ctx.config.inlayHints.parameterHints) { return this.dispose(); } if (!this.updater) this.updater = new HintsUpdater(ctx); }, - dispose() { + dispose(): void { this.updater?.dispose(); this.updater = null; } @@ -93,19 +93,20 @@ class HintsUpdater implements Disposable { this.syncCacheAndRenderHints(); } - dispose() { + dispose(): void { this.sourceFiles.forEach(file => file.inlaysRequest?.cancel()); this.ctx.visibleRustEditors.forEach(editor => this.renderDecorations(editor, { param: [], type: [] })); this.disposables.forEach(d => d.dispose()); } - onDidChangeTextDocument({ contentChanges, document }: vscode.TextDocumentChangeEvent) { + onDidChangeTextDocument({ contentChanges, document }: vscode.TextDocumentChangeEvent): void { if (contentChanges.length === 0 || !isRustDocument(document)) return; this.syncCacheAndRenderHints(); } - private syncCacheAndRenderHints() { + private syncCacheAndRenderHints(): void { // FIXME: make inlayHints request pass an array of files? + // eslint-disable-next-line @typescript-eslint/no-misused-promises this.sourceFiles.forEach((file, uri) => this.fetchHints(file).then(hints => { if (!hints) return; @@ -119,10 +120,11 @@ class HintsUpdater implements Disposable { })); } - onDidChangeVisibleTextEditors() { + onDidChangeVisibleTextEditors(): void { const newSourceFiles = new Map(); // Rerendering all, even up-to-date editors for simplicity + // eslint-disable-next-line @typescript-eslint/no-misused-promises this.ctx.visibleRustEditors.forEach(async editor => { const uri = editor.document.uri.toString(); const file = this.sourceFiles.get(uri) ?? { @@ -153,7 +155,7 @@ class HintsUpdater implements Disposable { this.sourceFiles = newSourceFiles; } - private renderDecorations(editor: RustEditor, decorations: InlaysDecorations) { + private renderDecorations(editor: RustEditor, decorations: InlaysDecorations): void { editor.setDecorations(typeHints.decorationType, decorations.type); editor.setDecorations(paramHints.decorationType, decorations.param); } diff --git a/editors/code/src/installation/downloads.ts b/editors/code/src/installation/downloads.ts index 7ce2e2960f23..54325ebbefc0 100644 --- a/editors/code/src/installation/downloads.ts +++ b/editors/code/src/installation/downloads.ts @@ -65,7 +65,7 @@ export async function downloadArtifactWithProgressUi( artifactFileName: string, installationDir: string, displayName: string, -) { +): Promise { await fs.promises.mkdir(installationDir).catch(err => assert( err?.code === "EEXIST", `Couldn't create directory "${installationDir}" to download ` + diff --git a/editors/code/src/installation/extension.ts b/editors/code/src/installation/extension.ts index a1db96f052bf..331c626f23a9 100644 --- a/editors/code/src/installation/extension.ts +++ b/editors/code/src/installation/extension.ts @@ -85,7 +85,7 @@ export async function ensureProperExtensionVersion(config: Config, state: Persis }); } -async function askToDownloadProperExtensionVersion(config: Config, reason = "") { +async function askToDownloadProperExtensionVersion(config: Config, reason = ""): Promise { if (!config.askBeforeDownload) return true; const stableOrNightly = config.updatesChannel === UpdatesChannel.Stable ? "stable" : "latest nightly"; @@ -113,7 +113,7 @@ async function askToDownloadProperExtensionVersion(config: Config, reason = "") const tryDownloadNightlyExtension = notReentrant(async ( config: Config, state: PersistentState, - shouldDownload: (releaseInfo: ArtifactReleaseInfo) => boolean = () => true + shouldDownload: (releaseInfo: ArtifactReleaseInfo) => boolean = (): boolean => true ): Promise => { const vsixSource = config.nightlyVsixSource; try { diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 94ecd4dab64f..b1fe311f06db 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -13,7 +13,7 @@ import { PersistentState } from './persistent_state'; let ctx: Ctx | undefined; -export async function activate(context: vscode.ExtensionContext) { +export async function activate(context: vscode.ExtensionContext): Promise { // Register a "dumb" onEnter command for the case where server fails to // start. // @@ -59,7 +59,7 @@ export async function activate(context: vscode.ExtensionContext) { // Commands which invokes manually via command palette, shortcut, etc. ctx.registerCommand('reload', (ctx) => { - return async () => { + return async (): Promise => { vscode.window.showInformationMessage('Reloading rust-analyzer...'); // @DanTup maneuver // https://github.com/microsoft/vscode/issues/45774#issuecomment-373423895 @@ -105,7 +105,7 @@ export async function activate(context: vscode.ExtensionContext) { activateInlayHints(ctx); } -export async function deactivate() { +export async function deactivate(): Promise { await ctx?.client?.stop(); ctx = undefined; } diff --git a/editors/code/src/persistent_state.ts b/editors/code/src/persistent_state.ts index 13095b806584..010c0a03b96a 100644 --- a/editors/code/src/persistent_state.ts +++ b/editors/code/src/persistent_state.ts @@ -26,7 +26,7 @@ export class Storage { log.debug(this.key, "==", val); return val; } - async set(val: T) { + async set(val: T): Promise { log.debug(this.key, "=", val); await this.storage.update(this.key, val); } @@ -43,7 +43,7 @@ export class DateStorage { return dateStr ? new Date(dateStr) : null; } - async set(date: null | Date) { + async set(date: null | Date): Promise { await this.inner.set(date ? date.toString() : null); } } diff --git a/editors/code/src/rust-analyzer-api.ts b/editors/code/src/rust-analyzer-api.ts index 9846f7343176..46c523562b03 100644 --- a/editors/code/src/rust-analyzer-api.ts +++ b/editors/code/src/rust-analyzer-api.ts @@ -8,10 +8,10 @@ type Option = null | T; type Vec = T[]; type FxHashMap = Record; -function request(method: string) { +function request(method: string): lc.RequestType { return new lc.RequestType(`rust-analyzer/${method}`); } -function notification(method: string) { +function notification(method: string): lc.NotificationType { return new lc.NotificationType(method); } diff --git a/editors/code/src/source_change.ts b/editors/code/src/source_change.ts index 399a150c6544..21928aaa2025 100644 --- a/editors/code/src/source_change.ts +++ b/editors/code/src/source_change.ts @@ -4,7 +4,7 @@ import * as ra from './rust-analyzer-api'; import { Ctx } from './ctx'; -export async function applySourceChange(ctx: Ctx, change: ra.SourceChange) { +export async function applySourceChange(ctx: Ctx, change: ra.SourceChange): Promise { const client = ctx.client; if (!client) return; diff --git a/editors/code/src/status_display.ts b/editors/code/src/status_display.ts index 0f5f6ef99e64..1c25fda1b224 100644 --- a/editors/code/src/status_display.ts +++ b/editors/code/src/status_display.ts @@ -6,7 +6,7 @@ import { Ctx } from './ctx'; const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; -export function activateStatusDisplay(ctx: Ctx) { +export function activateStatusDisplay(ctx: Ctx): void { const statusDisplay = new StatusDisplay(ctx.config.cargoWatchOptions.command); ctx.pushCleanup(statusDisplay); const client = ctx.client; @@ -36,7 +36,7 @@ class StatusDisplay implements Disposable { this.statusBarItem.hide(); } - show() { + show(): void { this.packageName = undefined; this.timer = @@ -49,7 +49,7 @@ class StatusDisplay implements Disposable { this.statusBarItem.show(); } - hide() { + hide(): void { if (this.timer) { clearInterval(this.timer); this.timer = undefined; @@ -58,7 +58,7 @@ class StatusDisplay implements Disposable { this.statusBarItem.hide(); } - dispose() { + dispose(): void { if (this.timer) { clearInterval(this.timer); this.timer = undefined; @@ -67,7 +67,7 @@ class StatusDisplay implements Disposable { this.statusBarItem.dispose(); } - refreshLabel() { + refreshLabel(): void { if (this.packageName) { this.statusBarItem.text = `${spinnerFrames[this.i]} cargo ${this.command} [${this.packageName}]`; } else { @@ -75,7 +75,7 @@ class StatusDisplay implements Disposable { } } - handleProgressNotification(params: WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd) { + handleProgressNotification(params: WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd): void { switch (params.kind) { case 'begin': this.show(); @@ -94,7 +94,7 @@ class StatusDisplay implements Disposable { } } - private tick() { + private tick(): void { this.i = (this.i + 1) % spinnerFrames.length; } } diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts index 2bfc145e6fe5..7fb8a6771dbb 100644 --- a/editors/code/src/util.ts +++ b/editors/code/src/util.ts @@ -19,20 +19,19 @@ export const log = new class { log.enabled = yes; } - debug(message?: any, ...optionalParams: any[]): void { + debug(message?: unknown, ...optionalParams: unknown[]): void { if (!log.enabled) return; // eslint-disable-next-line no-console console.log(message, ...optionalParams); } - error(message?: any, ...optionalParams: any[]): void { + error(message?: unknown, ...optionalParams: unknown[]): void { if (!log.enabled) return; - debugger; - // eslint-disable-next-line no-console - console.error(message, ...optionalParams); + debugger; // eslint-disable-line no-debugger + console.error(message, ...optionalParams); // eslint-disable-line no-console } - downloadError(err: Error, artifactName: string, repoName: string) { + downloadError(err: Error, artifactName: string, repoName: string): void { vscode.window.showErrorMessage( `Failed to download the rust-analyzer ${artifactName} from ${repoName} ` + `GitHub repository: ${err.message}` @@ -82,15 +81,15 @@ export async function sendRequestWithRetry( throw 'unreachable'; } -function sleep(ms: number) { +function sleep(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } -export function notReentrant( +export function notReentrant( fn: (this: TThis, ...params: TParams) => Promise ): typeof fn { let entered = false; - return function(...params) { + return function(...params): Promise { assert(!entered, `Reentrancy invariant for ${fn.name} is violated`); entered = true; return fn.apply(this, params).finally(() => entered = false); @@ -114,7 +113,7 @@ export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor { /** * @param extensionId The canonical extension identifier in the form of: `publisher.name` */ -export async function vscodeReinstallExtension(extensionId: string) { +export async function vscodeReinstallExtension(extensionId: string): Promise { // Unfortunately there is no straightforward way as of now, these commands // were found in vscode source code. @@ -130,7 +129,7 @@ export async function vscodeReloadWindow(): Promise { assert(false, "unreachable"); } -export async function vscodeInstallExtensionFromVsix(vsixPath: string) { +export async function vscodeInstallExtensionFromVsix(vsixPath: string): Promise { await vscode.commands.executeCommand( "workbench.extensions.installExtension", vscode.Uri.file(vsixPath) From 681b0367aaf7e71c128c825ecc26d4797968a55d Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Wed, 18 Mar 2020 16:05:20 -0600 Subject: [PATCH 4/9] Switch to prettier instead of tsfmt --- editors/code/.prettierignore | 1 + editors/code/.prettierrc.js | 21 ++++++ editors/code/package-lock.json | 119 +++++++++++++++------------------ editors/code/package.json | 10 ++- 4 files changed, 84 insertions(+), 67 deletions(-) create mode 100644 editors/code/.prettierignore create mode 100644 editors/code/.prettierrc.js diff --git a/editors/code/.prettierignore b/editors/code/.prettierignore new file mode 100644 index 000000000000..1fcb1529f8e5 --- /dev/null +++ b/editors/code/.prettierignore @@ -0,0 +1 @@ +out diff --git a/editors/code/.prettierrc.js b/editors/code/.prettierrc.js new file mode 100644 index 000000000000..7376c28784f8 --- /dev/null +++ b/editors/code/.prettierrc.js @@ -0,0 +1,21 @@ +// @ts-check + +/** @type { import('prettier').Options } */ +module.exports = { + bracketSpacing: true, + jsxBracketSameLine: true, + printWidth: 100, + semi: true, + singleQuote: true, + tabWidth: 4, + trailingComma: "all", + useTabs: false, + overrides: [ + { + files: "*.ts", + options: { + parser: "typescript", + }, + }, + ], +}; diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index 787f1b17a095..c9367bf4795a 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json @@ -50,6 +50,16 @@ "resolve": "^1.14.2" } }, + "@rollup/plugin-typescript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-4.0.0.tgz", + "integrity": "sha512-qA3r4WlR8JnTm+VdBzvQSIkfXt802keGxXuE4SAjUjRMKK3nMXTUCvOGSzFkav2qf0QiGv6yijfbjuf+bhwmZQ==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.1", + "resolve": "^1.14.1" + } + }, "@rollup/pluginutils": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.0.8.tgz", @@ -370,12 +380,6 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, - "commandpost": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz", - "integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -498,26 +502,6 @@ "domelementtype": "1" } }, - "editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dev": true, - "requires": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -589,6 +573,24 @@ } } }, + "eslint-config-prettier": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.10.0.tgz", + "integrity": "sha512-AtndijGte1rPILInUdHjvKEGbIV06NuvPrqlIEaEaWtbtvJh464mDeyGMdZEQMsGvC0ZVkiex1fSNcC4HAbRGg==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + } + }, + "eslint-plugin-prettier": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz", + "integrity": "sha512-GlolCC9y3XZfv3RQfwGew7NnuFDKsfI4lbvRK+PIIo23SFH+LemGs4cKwzAaRa+Mdb+lQO/STaIayno8T5sJJA==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, "eslint-scope": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", @@ -684,6 +686,12 @@ "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", "dev": true }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -770,6 +778,12 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -1057,16 +1071,6 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, "magic-string": { "version": "0.25.7", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", @@ -1309,18 +1313,27 @@ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, + "prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -1446,12 +1459,6 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -1662,16 +1669,6 @@ "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", "dev": true }, - "typescript-formatter": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/typescript-formatter/-/typescript-formatter-7.2.2.tgz", - "integrity": "sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ==", - "dev": true, - "requires": { - "commandpost": "^1.0.0", - "editorconfig": "^0.15.0" - } - }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -1814,12 +1811,6 @@ "mkdirp": "^0.5.1" } }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, "yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", diff --git a/editors/code/package.json b/editors/code/package.json index 84642d11cd6f..d24392569922 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -28,8 +28,9 @@ "vscode:prepublish": "tsc && rollup -c", "package": "vsce package -o rust-analyzer.vsix", "watch": "tsc --watch", - "lint": "tsfmt --verify && eslint -c .eslintrc.js --ext ts ./src", - "fix": " tsfmt -r && eslint -c .eslintrc.js --ext ts ./src --fix" + "lint": "eslint 'src/**/*.{js,ts}'", + "fix": " eslint --fix 'src/**/*.{js,ts,tsx}'", + "format": "prettier --write '**/*.{js,json,ts,tsx,yml,yaml}'" }, "dependencies": { "jsonc-parser": "^2.2.1", @@ -39,16 +40,19 @@ "devDependencies": { "@rollup/plugin-commonjs": "^11.0.2", "@rollup/plugin-node-resolve": "^7.1.1", + "@rollup/plugin-typescript": "^4.0.0", "@types/node": "^12.12.30", "@types/node-fetch": "^2.5.5", "@types/vscode": "^1.43.0", "@typescript-eslint/eslint-plugin": "^2.24.0", "@typescript-eslint/parser": "^2.24.0", "eslint": "^6.8.0", + "eslint-config-prettier": "^6.10.0", + "eslint-plugin-prettier": "^3.1.2", + "prettier": "^1.19.1", "rollup": "^2.1.0", "tslib": "^1.11.1", "typescript": "^3.8.3", - "typescript-formatter": "^7.2.2", "vsce": "^1.74.0" }, "activationEvents": [ From dbc069f6d2cd090229d460637cd446190dd2c9fc Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Wed, 18 Mar 2020 16:06:03 -0600 Subject: [PATCH 5/9] Configure eslint to use prettier --- editors/code/.eslintrc.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/editors/code/.eslintrc.js b/editors/code/.eslintrc.js index a241cda61f04..670f949dcaef 100644 --- a/editors/code/.eslintrc.js +++ b/editors/code/.eslintrc.js @@ -18,7 +18,10 @@ module.exports = { "eslint:recommended", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended-requiring-type-checking", - "plugin:@typescript-eslint/recommended" + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + "prettier", + "prettier/@typescript-eslint" ], "rules": { "camelcase": ["error"], From 8b6ad20bce6f037e86c29310ac9e2e581255843a Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Wed, 18 Mar 2020 16:06:32 -0600 Subject: [PATCH 6/9] Run prettier --- editors/code/.eslintrc.js | 82 ++++---- editors/code/.prettierrc.js | 6 +- editors/code/rollup.config.js | 20 +- editors/code/src/client.ts | 25 +-- editors/code/src/color_theme.ts | 30 +-- editors/code/src/commands/analyzer_status.ts | 21 +-- editors/code/src/commands/expand_macro.ts | 19 +- editors/code/src/commands/matching_brace.ts | 8 +- editors/code/src/commands/on_enter.ts | 18 +- editors/code/src/commands/parent_module.ts | 4 +- editors/code/src/commands/runnables.ts | 30 +-- editors/code/src/commands/server_version.ts | 6 +- editors/code/src/commands/ssr.ts | 6 +- editors/code/src/commands/syntax_tree.ts | 28 +-- editors/code/src/config.ts | 176 ++++++++++-------- editors/code/src/ctx.ts | 19 +- editors/code/src/highlighting.ts | 103 ++++------ editors/code/src/inlay_hints.ts | 83 +++++---- editors/code/src/installation/downloads.ts | 67 ++++--- editors/code/src/installation/extension.ts | 128 ++++++++----- .../fetch_artifact_release_info.ts | 29 ++- editors/code/src/installation/interfaces.ts | 6 +- editors/code/src/installation/server.ts | 136 ++++++++------ editors/code/src/main.ts | 15 +- editors/code/src/persistent_state.ts | 26 +-- editors/code/src/rust-analyzer-api.ts | 54 +++--- editors/code/src/source_change.ts | 12 +- editors/code/src/status_display.ts | 31 +-- editors/code/src/util.ts | 64 ++++--- editors/code/tsconfig.json | 8 +- 30 files changed, 646 insertions(+), 614 deletions(-) diff --git a/editors/code/.eslintrc.js b/editors/code/.eslintrc.js index 670f949dcaef..7ee18d150263 100644 --- a/editors/code/.eslintrc.js +++ b/editors/code/.eslintrc.js @@ -2,52 +2,50 @@ /** @type { import('eslint').Linter.Config } */ module.exports = { - "env": { - "es6": true, - "node": true + env: { + es6: true, + node: true, }, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": "tsconfig.json", - "sourceType": "module" + parser: '@typescript-eslint/parser', + parserOptions: { + project: 'tsconfig.json', + sourceType: 'module', }, - "plugins": [ - "@typescript-eslint" + plugins: ['@typescript-eslint'], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking', + 'plugin:@typescript-eslint/recommended', + 'plugin:prettier/recommended', + 'prettier', + 'prettier/@typescript-eslint', ], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended-requiring-type-checking", - "plugin:@typescript-eslint/recommended", - "plugin:prettier/recommended", - "prettier", - "prettier/@typescript-eslint" - ], - "rules": { - "camelcase": ["error"], - "eqeqeq": ["error", "always", { "null": "ignore" }], - "no-console": ["error"], - "prefer-const": "error", - "@typescript-eslint/member-delimiter-style": [ - "error", + rules: { + camelcase: ['error'], + eqeqeq: ['error', 'always', { null: 'ignore' }], + 'no-console': ['error'], + 'prefer-const': 'error', + '@typescript-eslint/member-delimiter-style': [ + 'error', { - "multiline": { - "delimiter": "semi", - "requireLast": true + multiline: { + delimiter: 'semi', + requireLast: true, + }, + singleline: { + delimiter: 'semi', + requireLast: false, }, - "singleline": { - "delimiter": "semi", - "requireLast": false - } - } + }, ], - "@typescript-eslint/no-inferrable-types": "off", - "@typescript-eslint/no-namespace": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-unnecessary-type-assertion": "error", - "@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }], - "@typescript-eslint/no-use-before-define": "off", - "@typescript-eslint/unbound-method": "off", - "@typescript-eslint/semi": ["error", "always"] - } + '@typescript-eslint/no-inferrable-types': 'off', + '@typescript-eslint/no-namespace': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-unnecessary-type-assertion': 'error', + '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], + '@typescript-eslint/no-use-before-define': 'off', + '@typescript-eslint/unbound-method': 'off', + '@typescript-eslint/semi': ['error', 'always'], + }, }; diff --git a/editors/code/.prettierrc.js b/editors/code/.prettierrc.js index 7376c28784f8..292f4825947d 100644 --- a/editors/code/.prettierrc.js +++ b/editors/code/.prettierrc.js @@ -8,13 +8,13 @@ module.exports = { semi: true, singleQuote: true, tabWidth: 4, - trailingComma: "all", + trailingComma: 'all', useTabs: false, overrides: [ { - files: "*.ts", + files: '*.ts', options: { - parser: "typescript", + parser: 'typescript', }, }, ], diff --git a/editors/code/rollup.config.js b/editors/code/rollup.config.js index 337385a2458e..276b4ac24dfa 100644 --- a/editors/code/rollup.config.js +++ b/editors/code/rollup.config.js @@ -6,19 +6,27 @@ export default { input: 'out/main.js', plugins: [ resolve({ - preferBuiltins: true + preferBuiltins: true, }), commonjs({ namedExports: { // squelch missing import warnings - 'vscode-languageclient': ['CreateFile', 'RenameFile', 'ErrorCodes', 'WorkDoneProgress', 'WorkDoneProgressBegin', 'WorkDoneProgressReport', 'WorkDoneProgressEnd'] - } - }) + 'vscode-languageclient': [ + 'CreateFile', + 'RenameFile', + 'ErrorCodes', + 'WorkDoneProgress', + 'WorkDoneProgressBegin', + 'WorkDoneProgressReport', + 'WorkDoneProgressEnd', + ], + }, + }), ], external: [...nodeBuiltins, 'vscode'], output: { file: './out/main.js', format: 'cjs', - exports: 'named' - } + exports: 'named', + }, }; diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index c6fb88f81029..04ca4e057e44 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -3,7 +3,10 @@ import * as vscode from 'vscode'; import { Config } from './config'; import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed'; -import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed'; +import { + SemanticTokensFeature, + DocumentSemanticsTokensSignature, +} from 'vscode-languageclient/lib/semanticTokens.proposed'; export function createClient(config: Config, serverPath: string): lc.LanguageClient { // '.' Is the fallback if no folder is open @@ -45,17 +48,21 @@ export function createClient(config: Config, serverPath: string): lc.LanguageCli withSysroot: config.withSysroot, cargoFeatures: config.cargoFeatures, rustfmtArgs: config.rustfmtArgs, - vscodeLldb: vscode.extensions.getExtension("vadimcn.vscode-lldb") != null, + vscodeLldb: vscode.extensions.getExtension('vadimcn.vscode-lldb') != null, }, traceOutputChannel, middleware: { // Workaround for https://github.com/microsoft/vscode-languageserver-node/issues/576 - async provideDocumentSemanticTokens(document: vscode.TextDocument, token: vscode.CancellationToken, next: DocumentSemanticsTokensSignature) { + async provideDocumentSemanticTokens( + document: vscode.TextDocument, + token: vscode.CancellationToken, + next: DocumentSemanticsTokensSignature, + ) { const res = await next(document, token); if (res === undefined) throw new Error('busy'); return res; - } - } as lc.Middleware + }, + } as lc.Middleware, }; const res = new lc.LanguageClient( @@ -76,12 +83,8 @@ export function createClient(config: Config, serverPath: string): lc.LanguageCli log: (messageOrDataObject: string | unknown, data?: string): void => { if (typeof messageOrDataObject === 'string') { if ( - messageOrDataObject.includes( - 'rust-analyzer/publishDecorations', - ) || - messageOrDataObject.includes( - 'rust-analyzer/decorationsRequest', - ) + messageOrDataObject.includes('rust-analyzer/publishDecorations') || + messageOrDataObject.includes('rust-analyzer/decorationsRequest') ) { // Don't log publish decorations requests } else { diff --git a/editors/code/src/color_theme.ts b/editors/code/src/color_theme.ts index 561f6909d7a1..19b801a9581e 100644 --- a/editors/code/src/color_theme.ts +++ b/editors/code/src/color_theme.ts @@ -14,9 +14,7 @@ export class ColorTheme { static load(): ColorTheme { // Find out current color theme - const themeName = vscode.workspace - .getConfiguration('workbench') - .get('colorTheme'); + const themeName = vscode.workspace.getConfiguration('workbench').get('colorTheme'); if (typeof themeName !== 'string') { // console.warn('workbench.colorTheme is', themeName) @@ -28,9 +26,10 @@ export class ColorTheme { static fromRules(rules: TextMateRule[]): ColorTheme { const res = new ColorTheme(); for (const rule of rules) { - const scopes = typeof rule.scope === 'undefined' - ? [] - : typeof rule.scope === 'string' + const scopes = + typeof rule.scope === 'undefined' + ? [] + : typeof rule.scope === 'string' ? [rule.scope] : rule.scope; @@ -72,10 +71,10 @@ function loadThemeNamed(themeName: string): ColorTheme { const themePaths: string[] = vscode.extensions.all .filter(isTheme) - .flatMap( - ext => ext.packageJSON.contributes.themes + .flatMap(ext => + ext.packageJSON.contributes.themes .filter((it: { id: string; label: string }) => (it.id || it.label) === themeName) - .map((it: { path: string }) => path.join(ext.extensionPath, it.path)) + .map((it: { path: string }) => path.join(ext.extensionPath, it.path)), ); const res = new ColorTheme(); @@ -83,13 +82,20 @@ function loadThemeNamed(themeName: string): ColorTheme { res.mergeFrom(loadThemeFile(themePath)); } - const globalCustomizations: undefined | { textMateRules: undefined | TextMateRule[] } = vscode.workspace.getConfiguration('editor').get('tokenColorCustomizations'); + const globalCustomizations: + | undefined + | { textMateRules: undefined | TextMateRule[] } = vscode.workspace + .getConfiguration('editor') + .get('tokenColorCustomizations'); res.mergeFrom(ColorTheme.fromRules(globalCustomizations?.textMateRules ?? [])); - const themeCustomizations: undefined | { textMateRules: undefined | TextMateRule[] } = vscode.workspace.getConfiguration('editor.tokenColorCustomizations').get(`[${themeName}]`); + const themeCustomizations: + | undefined + | { textMateRules: undefined | TextMateRule[] } = vscode.workspace + .getConfiguration('editor.tokenColorCustomizations') + .get(`[${themeName}]`); res.mergeFrom(ColorTheme.fromRules(themeCustomizations?.textMateRules ?? [])); - return res; } diff --git a/editors/code/src/commands/analyzer_status.ts b/editors/code/src/commands/analyzer_status.ts index 73b061534bec..8cfe1159dca8 100644 --- a/editors/code/src/commands/analyzer_status.ts +++ b/editors/code/src/commands/analyzer_status.ts @@ -9,10 +9,7 @@ export function analyzerStatus(ctx: Ctx): Cmd<[]> { const tdcp = new TextDocumentContentProvider(ctx); ctx.pushCleanup( - vscode.workspace.registerTextDocumentContentProvider( - 'rust-analyzer-status', - tdcp, - ), + vscode.workspace.registerTextDocumentContentProvider('rust-analyzer-status', tdcp), ); ctx.pushCleanup({ @@ -28,25 +25,17 @@ export function analyzerStatus(ctx: Ctx): Cmd<[]> { poller = setInterval(() => tdcp.eventEmitter.fire(tdcp.uri), 1000); } const document = await vscode.workspace.openTextDocument(tdcp.uri); - return vscode.window.showTextDocument( - document, - vscode.ViewColumn.Two, - true, - ); + return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true); }; } -class TextDocumentContentProvider - implements vscode.TextDocumentContentProvider { +class TextDocumentContentProvider implements vscode.TextDocumentContentProvider { uri = vscode.Uri.parse('rust-analyzer-status://status'); eventEmitter = new vscode.EventEmitter(); - constructor(private readonly ctx: Ctx) { - } + constructor(private readonly ctx: Ctx) {} - provideTextDocumentContent( - _uri: vscode.Uri, - ): vscode.ProviderResult { + provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult { const editor = vscode.window.activeTextEditor; const client = this.ctx.client; if (!editor || !client) return ''; diff --git a/editors/code/src/commands/expand_macro.ts b/editors/code/src/commands/expand_macro.ts index feaffa039140..88b857720e23 100644 --- a/editors/code/src/commands/expand_macro.ts +++ b/editors/code/src/commands/expand_macro.ts @@ -8,21 +8,12 @@ import { Ctx, Cmd } from '../ctx'; // The contents of the file come from the `TextDocumentContentProvider` export function expandMacro(ctx: Ctx): Cmd<[]> { const tdcp = new TextDocumentContentProvider(ctx); - ctx.pushCleanup( - vscode.workspace.registerTextDocumentContentProvider( - 'rust-analyzer', - tdcp, - ), - ); + ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp)); return async (): Promise => { const document = await vscode.workspace.openTextDocument(tdcp.uri); tdcp.eventEmitter.fire(tdcp.uri); - return vscode.window.showTextDocument( - document, - vscode.ViewColumn.Two, - true, - ); + return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true); }; } @@ -35,13 +26,11 @@ function codeFormat(expanded: ra.ExpandedMacro): string { return result; } -class TextDocumentContentProvider - implements vscode.TextDocumentContentProvider { +class TextDocumentContentProvider implements vscode.TextDocumentContentProvider { uri = vscode.Uri.parse('rust-analyzer://expandMacro/[EXPANSION].rs'); eventEmitter = new vscode.EventEmitter(); - constructor(private readonly ctx: Ctx) { - } + constructor(private readonly ctx: Ctx) {} async provideTextDocumentContent(_uri: vscode.Uri): Promise { const editor = vscode.window.activeTextEditor; diff --git a/editors/code/src/commands/matching_brace.ts b/editors/code/src/commands/matching_brace.ts index 1b8a4be5f121..ca48a2177ce7 100644 --- a/editors/code/src/commands/matching_brace.ts +++ b/editors/code/src/commands/matching_brace.ts @@ -11,14 +11,10 @@ export function matchingBrace(ctx: Ctx): Cmd<[]> { const response = await client.sendRequest(ra.findMatchingBrace, { textDocument: { uri: editor.document.uri.toString() }, - offsets: editor.selections.map(s => - client.code2ProtocolConverter.asPosition(s.active), - ), + offsets: editor.selections.map(s => client.code2ProtocolConverter.asPosition(s.active)), }); editor.selections = editor.selections.map((sel, idx) => { - const active = client.protocol2CodeConverter.asPosition( - response[idx], - ); + const active = client.protocol2CodeConverter.asPosition(response[idx]); const anchor = sel.isEmpty ? active : sel.anchor; return new vscode.Selection(anchor, active); }); diff --git a/editors/code/src/commands/on_enter.ts b/editors/code/src/commands/on_enter.ts index a857b932ab76..cdd488097729 100644 --- a/editors/code/src/commands/on_enter.ts +++ b/editors/code/src/commands/on_enter.ts @@ -10,15 +10,15 @@ async function handleKeypress(ctx: Ctx): Promise { if (!editor || !client) return false; - const change = await client.sendRequest(ra.onEnter, { - textDocument: { uri: editor.document.uri.toString() }, - position: client.code2ProtocolConverter.asPosition( - editor.selection.active, - ), - }).catch(_error => { - // client.logFailedRequest(OnEnterRequest.type, error); - return null; - }); + const change = await client + .sendRequest(ra.onEnter, { + textDocument: { uri: editor.document.uri.toString() }, + position: client.code2ProtocolConverter.asPosition(editor.selection.active), + }) + .catch(_error => { + // client.logFailedRequest(OnEnterRequest.type, error); + return null; + }); if (!change) return false; await applySourceChange(ctx, change); diff --git a/editors/code/src/commands/parent_module.ts b/editors/code/src/commands/parent_module.ts index df57ecb8f568..2bee80ee673f 100644 --- a/editors/code/src/commands/parent_module.ts +++ b/editors/code/src/commands/parent_module.ts @@ -11,9 +11,7 @@ export function parentModule(ctx: Ctx): Cmd<[]> { const response = await client.sendRequest(ra.parentModule, { textDocument: { uri: editor.document.uri.toString() }, - position: client.code2ProtocolConverter.asPosition( - editor.selection.active, - ), + position: client.code2ProtocolConverter.asPosition(editor.selection.active), }); const loc = response[0]; if (loc == null) return; diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts index ae92f7a15311..e9a7a754b0cc 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/commands/runnables.ts @@ -18,19 +18,14 @@ export function run(ctx: Ctx): Cmd<[]> { const runnables = await client.sendRequest(ra.runnables, { textDocument, - position: client.code2ProtocolConverter.asPosition( - editor.selection.active, - ), + position: client.code2ProtocolConverter.asPosition(editor.selection.active), }); const items: RunnableQuickPick[] = []; if (prevRunnable) { items.push(prevRunnable); } for (const r of runnables) { - if ( - prevRunnable && - JSON.stringify(prevRunnable.runnable) === JSON.stringify(r) - ) { + if (prevRunnable && JSON.stringify(prevRunnable.runnable) === JSON.stringify(r)) { continue; } items.push(new RunnableQuickPick(r)); @@ -68,14 +63,14 @@ export function debugSingle(ctx: Ctx): Cmd<[ra.Runnable]> { if (!editor) return; const debugConfig = { - type: "lldb", - request: "launch", + type: 'lldb', + request: 'launch', name: config.label, cargo: { args: config.args, }, args: config.extraArgs, - cwd: config.cwd + cwd: config.cwd, }; return vscode.debug.startDebugging(undefined, debugConfig); @@ -115,21 +110,10 @@ function createTask(spec: ra.Runnable): vscode.Task { cwd: spec.cwd || '.', env: definition.env, }; - const exec = new vscode.ShellExecution( - definition.command, - definition.args, - execOption, - ); + const exec = new vscode.ShellExecution(definition.command, definition.args, execOption); const f = vscode.workspace.workspaceFolders![0]; - const t = new vscode.Task( - definition, - f, - definition.label, - TASK_SOURCE, - exec, - ['$rustc'], - ); + const t = new vscode.Task(definition, f, definition.label, TASK_SOURCE, exec, ['$rustc']); t.presentationOptions.clear = true; return t; } diff --git a/editors/code/src/commands/server_version.ts b/editors/code/src/commands/server_version.ts index 9a1b9be8d56d..95aebe9c498e 100644 --- a/editors/code/src/commands/server_version.ts +++ b/editors/code/src/commands/server_version.ts @@ -9,12 +9,12 @@ export function serverVersion(ctx: Ctx): Cmd<[]> { if (binaryPath == null) { throw new Error( - "Rust Analyzer Language Server is not available. " + - "Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation)." + 'Rust Analyzer Language Server is not available. ' + + 'Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation).', ); } - const version = spawnSync(binaryPath, ["--version"], { encoding: "utf8" }).stdout; + const version = spawnSync(binaryPath, ['--version'], { encoding: 'utf8' }).stdout; vscode.window.showInformationMessage('rust-analyzer version : ' + version); }; } diff --git a/editors/code/src/commands/ssr.ts b/editors/code/src/commands/ssr.ts index 61e1ed3a6c82..81418b6daea0 100644 --- a/editors/code/src/commands/ssr.ts +++ b/editors/code/src/commands/ssr.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import * as ra from "../rust-analyzer-api"; +import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; import { applySourceChange } from '../source_change'; @@ -10,7 +10,7 @@ export function ssr(ctx: Ctx): Cmd<[]> { if (!client) return; const options: vscode.InputBoxOptions = { - value: "() ==>> ()", + value: '() ==>> ()', prompt: "EnteR request, for example 'Foo($a:expr) ==> Foo::new($a)' ", validateInput: async (x: string) => { try { @@ -19,7 +19,7 @@ export function ssr(ctx: Ctx): Cmd<[]> { return e.toString(); } return null; - } + }, }; const request = await vscode.window.showInputBox(options); diff --git a/editors/code/src/commands/syntax_tree.ts b/editors/code/src/commands/syntax_tree.ts index 2ec1c468b9fa..d412ec3aec84 100644 --- a/editors/code/src/commands/syntax_tree.ts +++ b/editors/code/src/commands/syntax_tree.ts @@ -10,12 +10,7 @@ import { isRustDocument } from '../util'; export function syntaxTree(ctx: Ctx): Cmd<[]> { const tdcp = new TextDocumentContentProvider(ctx); - ctx.pushCleanup( - vscode.workspace.registerTextDocumentContentProvider( - 'rust-analyzer', - tdcp, - ), - ); + ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp)); vscode.workspace.onDidChangeTextDocument( (event: vscode.TextDocumentChangeEvent) => { @@ -40,19 +35,13 @@ export function syntaxTree(ctx: Ctx): Cmd<[]> { const editor = vscode.window.activeTextEditor; const rangeEnabled = !!(editor && !editor.selection.isEmpty); - const uri = rangeEnabled - ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) - : tdcp.uri; + const uri = rangeEnabled ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) : tdcp.uri; const document = await vscode.workspace.openTextDocument(uri); tdcp.eventEmitter.fire(uri); - return vscode.window.showTextDocument( - document, - vscode.ViewColumn.Two, - true, - ); + return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true); }; } @@ -62,13 +51,11 @@ function afterLs(f: () => void): void { setTimeout(f, 10); } - class TextDocumentContentProvider implements vscode.TextDocumentContentProvider { uri = vscode.Uri.parse('rust-analyzer://syntaxtree'); eventEmitter = new vscode.EventEmitter(); - constructor(private readonly ctx: Ctx) { - } + constructor(private readonly ctx: Ctx) {} provideTextDocumentContent(uri: vscode.Uri): vscode.ProviderResult { const editor = vscode.window.activeTextEditor; @@ -76,9 +63,10 @@ class TextDocumentContentProvider implements vscode.TextDocumentContentProvider if (!editor || !client) return ''; // When the range based query is enabled we take the range of the selection - const range = uri.query === 'range=true' && !editor.selection.isEmpty - ? client.code2ProtocolConverter.asRange(editor.selection) - : null; + const range = + uri.query === 'range=true' && !editor.selection.isEmpty + ? client.code2ProtocolConverter.asRange(editor.selection) + : null; return client.sendRequest(ra.syntaxTree, { textDocument: { uri: editor.document.uri.toString() }, diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 9aff632a3cf8..16b6974200fa 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -1,7 +1,7 @@ -import * as os from "os"; +import * as os from 'os'; import * as vscode from 'vscode'; -import { ArtifactSource } from "./installation/interfaces"; -import { log, vscodeReloadWindow } from "./util"; +import { ArtifactSource } from './installation/interfaces'; +import { log, vscodeReloadWindow } from './util'; const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG; @@ -26,28 +26,24 @@ export interface CargoFeatures { } export const enum UpdatesChannel { - Stable = "stable", - Nightly = "nightly" + Stable = 'stable', + Nightly = 'nightly', } -export const NIGHTLY_TAG = "nightly"; +export const NIGHTLY_TAG = 'nightly'; export class Config { - readonly extensionId = "matklad.rust-analyzer"; + readonly extensionId = 'matklad.rust-analyzer'; - private readonly rootSection = "rust-analyzer"; + private readonly rootSection = 'rust-analyzer'; private readonly requiresReloadOpts = [ - "serverPath", - "cargoFeatures", - "cargo-watch", - "highlighting.semanticTokens", - "inlayHints", - ] - .map(opt => `${this.rootSection}.${opt}`); - - readonly packageJsonVersion = vscode - .extensions - .getExtension(this.extensionId)! - .packageJSON + 'serverPath', + 'cargoFeatures', + 'cargo-watch', + 'highlighting.semanticTokens', + 'inlayHints', + ].map(opt => `${this.rootSection}.${opt}`); + + readonly packageJsonVersion = vscode.extensions.getExtension(this.extensionId)!.packageJSON .version as string; // n.n.YYYYMMDD[-nightly] /** @@ -71,36 +67,33 @@ export class Config { private refreshConfig(): void { this.cfg = vscode.workspace.getConfiguration(this.rootSection); - const enableLogging = this.cfg.get("trace.extension") as boolean; + const enableLogging = this.cfg.get('trace.extension') as boolean; log.setEnabled(enableLogging); - log.debug( - "Extension version:", this.packageJsonVersion, - "using configuration:", this.cfg - ); + log.debug('Extension version:', this.packageJsonVersion, 'using configuration:', this.cfg); } private async onConfigChange(event: vscode.ConfigurationChangeEvent): Promise { this.refreshConfig(); - const requiresReloadOpt = this.requiresReloadOpts.find( - opt => event.affectsConfiguration(opt) + const requiresReloadOpt = this.requiresReloadOpts.find(opt => + event.affectsConfiguration(opt), ); if (!requiresReloadOpt) return; const userResponse = await vscode.window.showInformationMessage( `Changing "${requiresReloadOpt}" requires a reload`, - "Reload now" + 'Reload now', ); - if (userResponse === "Reload now") { + if (userResponse === 'Reload now') { await vscodeReloadWindow(); } } private static replaceTildeWithHomeDir(path: string): string { - if (path.startsWith("~/")) { - return os.homedir() + path.slice("~".length); + if (path.startsWith('~/')) { + return os.homedir() + path.slice('~'.length); } return path; } @@ -115,27 +108,31 @@ export class Config { // https://nodejs.org/api/process.html#process_process_arch switch (process.platform) { - - case "linux": { + case 'linux': { switch (process.arch) { - case "arm": - case "arm64": return null; + case 'arm': + case 'arm64': + return null; - default: return "rust-analyzer-linux"; + default: + return 'rust-analyzer-linux'; } } - case "darwin": return "rust-analyzer-mac"; - case "win32": return "rust-analyzer-windows.exe"; + case 'darwin': + return 'rust-analyzer-mac'; + case 'win32': + return 'rust-analyzer-windows.exe'; // Users on these platforms yet need to manually build from sources - case "aix": - case "android": - case "freebsd": - case "openbsd": - case "sunos": - case "cygwin": - case "netbsd": return null; + case 'aix': + case 'android': + case 'freebsd': + case 'openbsd': + case 'sunos': + case 'cygwin': + case 'netbsd': + return null; // The list of platforms is exhaustive (see `NodeJS.Platform` type definition) } } @@ -152,7 +149,7 @@ export class Config { if (serverPath) { return { type: ArtifactSource.Type.ExplicitPath, - path: Config.replaceTildeWithHomeDir(serverPath) + path: Config.replaceTildeWithHomeDir(serverPath), }; } @@ -160,10 +157,7 @@ export class Config { if (!prebuiltBinaryName) return null; - return this.createGithubReleaseSource( - prebuiltBinaryName, - this.extensionReleaseTag - ); + return this.createGithubReleaseSource(prebuiltBinaryName, this.extensionReleaseTag); } private createGithubReleaseSource(file: string, tag: string): ArtifactSource.GithubRelease { @@ -173,57 +167,83 @@ export class Config { tag, dir: this.ctx.globalStoragePath, repo: { - name: "rust-analyzer", - owner: "rust-analyzer", - } + name: 'rust-analyzer', + owner: 'rust-analyzer', + }, }; } get nightlyVsixSource(): ArtifactSource.GithubRelease { - return this.createGithubReleaseSource("rust-analyzer.vsix", NIGHTLY_TAG); + return this.createGithubReleaseSource('rust-analyzer.vsix', NIGHTLY_TAG); } // We don't do runtime config validation here for simplicity. More on stackoverflow: // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension - private get serverPath(): null | string { return this.cfg.get("serverPath") as null | string; } - get updatesChannel(): UpdatesChannel { return this.cfg.get("updates.channel") as UpdatesChannel; } - get askBeforeDownload(): boolean { return this.cfg.get("updates.askBeforeDownload") as boolean; } - get highlightingSemanticTokens(): boolean { return this.cfg.get("highlighting.semanticTokens") as boolean; } - get highlightingOn(): boolean { return this.cfg.get("highlightingOn") as boolean; } - get rainbowHighlightingOn(): boolean { return this.cfg.get("rainbowHighlightingOn") as boolean; } - get lruCapacity(): null | number { return this.cfg.get("lruCapacity") as null | number; } + private get serverPath(): null | string { + return this.cfg.get('serverPath') as null | string; + } + get updatesChannel(): UpdatesChannel { + return this.cfg.get('updates.channel') as UpdatesChannel; + } + get askBeforeDownload(): boolean { + return this.cfg.get('updates.askBeforeDownload') as boolean; + } + get highlightingSemanticTokens(): boolean { + return this.cfg.get('highlighting.semanticTokens') as boolean; + } + get highlightingOn(): boolean { + return this.cfg.get('highlightingOn') as boolean; + } + get rainbowHighlightingOn(): boolean { + return this.cfg.get('rainbowHighlightingOn') as boolean; + } + get lruCapacity(): null | number { + return this.cfg.get('lruCapacity') as null | number; + } get inlayHints(): InlayHintOptions { return { - typeHints: this.cfg.get("inlayHints.typeHints") as boolean, - parameterHints: this.cfg.get("inlayHints.parameterHints") as boolean, - maxLength: this.cfg.get("inlayHints.maxLength") as null | number, + typeHints: this.cfg.get('inlayHints.typeHints') as boolean, + parameterHints: this.cfg.get('inlayHints.parameterHints') as boolean, + maxLength: this.cfg.get('inlayHints.maxLength') as null | number, }; } - get excludeGlobs(): string[] { return this.cfg.get("excludeGlobs") as string[]; } - get useClientWatching(): boolean { return this.cfg.get("useClientWatching") as boolean; } - get featureFlags(): Record { return this.cfg.get("featureFlags") as Record; } - get rustfmtArgs(): string[] { return this.cfg.get("rustfmtArgs") as string[]; } - get loadOutDirsFromCheck(): boolean { return this.cfg.get("loadOutDirsFromCheck") as boolean; } + get excludeGlobs(): string[] { + return this.cfg.get('excludeGlobs') as string[]; + } + get useClientWatching(): boolean { + return this.cfg.get('useClientWatching') as boolean; + } + get featureFlags(): Record { + return this.cfg.get('featureFlags') as Record; + } + get rustfmtArgs(): string[] { + return this.cfg.get('rustfmtArgs') as string[]; + } + get loadOutDirsFromCheck(): boolean { + return this.cfg.get('loadOutDirsFromCheck') as boolean; + } get cargoWatchOptions(): CargoWatchOptions { return { - enable: this.cfg.get("cargo-watch.enable") as boolean, - arguments: this.cfg.get("cargo-watch.arguments") as string[], - allTargets: this.cfg.get("cargo-watch.allTargets") as boolean, - command: this.cfg.get("cargo-watch.command") as string, + enable: this.cfg.get('cargo-watch.enable') as boolean, + arguments: this.cfg.get('cargo-watch.arguments') as string[], + allTargets: this.cfg.get('cargo-watch.allTargets') as boolean, + command: this.cfg.get('cargo-watch.command') as string, }; } get cargoFeatures(): CargoFeatures { return { - noDefaultFeatures: this.cfg.get("cargoFeatures.noDefaultFeatures") as boolean, - allFeatures: this.cfg.get("cargoFeatures.allFeatures") as boolean, - features: this.cfg.get("cargoFeatures.features") as string[], - loadOutDirsFromCheck: this.cfg.get("cargoFeatures.loadOutDirsFromCheck") as boolean, + noDefaultFeatures: this.cfg.get('cargoFeatures.noDefaultFeatures') as boolean, + allFeatures: this.cfg.get('cargoFeatures.allFeatures') as boolean, + features: this.cfg.get('cargoFeatures.features') as string[], + loadOutDirsFromCheck: this.cfg.get('cargoFeatures.loadOutDirsFromCheck') as boolean, }; } // for internal use - get withSysroot(): boolean { return this.cfg.get("withSysroot", true) as boolean; } + get withSysroot(): boolean { + return this.cfg.get('withSysroot', true) as boolean; + } } diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index 5b3a3f8c6b44..a4b3ce3d3b88 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -11,12 +11,15 @@ export class Ctx { readonly config: Config, readonly state: PersistentState, private readonly extCtx: vscode.ExtensionContext, - readonly client: lc.LanguageClient - ) { - - } - - static async create(config: Config, state: PersistentState, extCtx: vscode.ExtensionContext, serverPath: string): Promise { + readonly client: lc.LanguageClient, + ) {} + + static async create( + config: Config, + state: PersistentState, + extCtx: vscode.ExtensionContext, + serverPath: string, + ): Promise { const client = createClient(config, serverPath); const res = new Ctx(config, state, extCtx, client); res.pushCleanup(client.start()); @@ -26,9 +29,7 @@ export class Ctx { get activeRustEditor(): RustEditor | undefined { const editor = vscode.window.activeTextEditor; - return editor && isRustEditor(editor) - ? editor - : undefined; + return editor && isRustEditor(editor) ? editor : undefined; } get visibleRustEditors(): RustEditor[] { diff --git a/editors/code/src/highlighting.ts b/editors/code/src/highlighting.ts index 0c984c8747a1..2fd208954799 100644 --- a/editors/code/src/highlighting.ts +++ b/editors/code/src/highlighting.ts @@ -12,22 +12,17 @@ export function activateHighlighting(ctx: Ctx): void { ctx.client.onNotification(ra.publishDecorations, params => { if (!ctx.config.highlightingOn) return; - const targetEditor = vscode.window.visibleTextEditors.find( - editor => { - const unescapedUri = unescape( - editor.document.uri.toString(), - ); - // Unescaped URI looks like: - // file:///c:/Workspace/ra-test/src/main.rs - return unescapedUri === params.uri; - }, - ); + const targetEditor = vscode.window.visibleTextEditors.find(editor => { + const unescapedUri = unescape(editor.document.uri.toString()); + // Unescaped URI looks like: + // file:///c:/Workspace/ra-test/src/main.rs + return unescapedUri === params.uri; + }); if (!targetEditor) return; highlighter.setHighlights(targetEditor, params.decorations); }); - vscode.workspace.onDidChangeConfiguration( _ => highlighter.removeHighlights(), null, @@ -41,11 +36,9 @@ export function activateHighlighting(ctx: Ctx): void { const client = ctx.client; if (!client) return; - const decorations = await sendRequestWithRetry( - client, - ra.decorationsRequest, - { uri: editor.document.uri.toString() }, - ); + const decorations = await sendRequestWithRetry(client, ra.decorationsRequest, { + uri: editor.document.uri.toString(), + }); highlighter.setHighlights(editor, decorations); }, null, @@ -57,7 +50,7 @@ export function activateHighlighting(ctx: Ctx): void { function fancify(seed: string, shade: 'light' | 'dark'): string { const random = randomU32Numbers(hashString(seed)); const randomInt = (min: number, max: number): number => { - return Math.abs(random()) % (max - min + 1) + min; + return (Math.abs(random()) % (max - min + 1)) + min; }; const h = randomInt(0, 360); @@ -68,10 +61,7 @@ function fancify(seed: string, shade: 'light' | 'dark'): string { class Highlighter { private ctx: Ctx; - private decorations: Map< - string, - vscode.TextEditorDecorationType - > | null = null; + private decorations: Map | null = null; constructor(ctx: Ctx) { this.ctx = ctx; @@ -102,10 +92,7 @@ class Highlighter { } const byTag: Map = new Map(); - const colorfulIdents: Map< - string, - [vscode.Range[], boolean] - > = new Map(); + const colorfulIdents: Map = new Map(); const rainbowTime = this.ctx.config.rainbowHighlightingOn; for (const tag of this.decorations.keys()) { @@ -124,22 +111,14 @@ class Highlighter { } colorfulIdents .get(d.bindingHash)![0] - .push( - client.protocol2CodeConverter.asRange(d.range), - ); + .push(client.protocol2CodeConverter.asRange(d.range)); } else { - byTag - .get(d.tag)! - .push( - client.protocol2CodeConverter.asRange(d.range), - ); + byTag.get(d.tag)!.push(client.protocol2CodeConverter.asRange(d.range)); } } for (const tag of byTag.keys()) { - const dec = this.decorations.get( - tag, - ) as vscode.TextEditorDecorationType; + const dec = this.decorations.get(tag) as vscode.TextEditorDecorationType; const ranges = byTag.get(tag)!; editor.setDecorations(dec, ranges); } @@ -206,32 +185,32 @@ function createDecorationFromTextmate( // sync with tags from `syntax_highlighting.rs`. const TAG_TO_SCOPES = new Map([ - ["field", ["entity.name.field"]], - ["function", ["entity.name.function"]], - ["module", ["entity.name.module"]], - ["constant", ["entity.name.constant"]], - ["macro", ["entity.name.macro"]], - - ["variable", ["variable"]], - ["variable.mutable", ["variable", "meta.mutable"]], - - ["type", ["entity.name.type"]], - ["type.builtin", ["entity.name.type", "support.type.primitive"]], - ["type.self", ["entity.name.type.parameter.self"]], - ["type.param", ["entity.name.type.parameter", "entity.name.type.param.rust"]], - ["type.lifetime", ["entity.name.type.lifetime", "entity.name.lifetime.rust"]], - - ["literal.byte", ["constant.character.byte"]], - ["literal.char", ["constant.character.rust"]], - ["numeric_literal", ["constant.numeric"]], - - ["comment", ["comment"]], - ["string_literal", ["string.quoted"]], - ["attribute", ["meta.attribute.rust"]], - - ["keyword", ["keyword"]], - ["keyword.unsafe", ["keyword.other.unsafe"]], - ["keyword.control", ["keyword.control"]], + ['field', ['entity.name.field']], + ['function', ['entity.name.function']], + ['module', ['entity.name.module']], + ['constant', ['entity.name.constant']], + ['macro', ['entity.name.macro']], + + ['variable', ['variable']], + ['variable.mutable', ['variable', 'meta.mutable']], + + ['type', ['entity.name.type']], + ['type.builtin', ['entity.name.type', 'support.type.primitive']], + ['type.self', ['entity.name.type.parameter.self']], + ['type.param', ['entity.name.type.parameter', 'entity.name.type.param.rust']], + ['type.lifetime', ['entity.name.type.lifetime', 'entity.name.lifetime.rust']], + + ['literal.byte', ['constant.character.byte']], + ['literal.char', ['constant.character.rust']], + ['numeric_literal', ['constant.numeric']], + + ['comment', ['comment']], + ['string_literal', ['string.quoted']], + ['attribute', ['meta.attribute.rust']], + + ['keyword', ['keyword']], + ['keyword.unsafe', ['keyword.other.unsafe']], + ['keyword.control', ['keyword.control']], ]); function randomU32Numbers(seed: number): () => number { diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts index ac792b533b6f..d14595b2774a 100644 --- a/editors/code/src/inlay_hints.ts +++ b/editors/code/src/inlay_hints.ts @@ -1,11 +1,10 @@ -import * as lc from "vscode-languageclient"; +import * as lc from 'vscode-languageclient'; import * as vscode from 'vscode'; import * as ra from './rust-analyzer-api'; import { Ctx, Disposable } from './ctx'; import { sendRequestWithRetry, isRustDocument, RustDocument, RustEditor } from './util'; - export function activateInlayHints(ctx: Ctx): void { const maybeUpdater = { updater: null as null | HintsUpdater, @@ -18,49 +17,56 @@ export function activateInlayHints(ctx: Ctx): void { dispose(): void { this.updater?.dispose(); this.updater = null; - } + }, }; ctx.pushCleanup(maybeUpdater); vscode.workspace.onDidChangeConfiguration( - maybeUpdater.onConfigChange, maybeUpdater, ctx.subscriptions + maybeUpdater.onConfigChange, + maybeUpdater, + ctx.subscriptions, ); maybeUpdater.onConfigChange(); } - const typeHints = { decorationType: vscode.window.createTextEditorDecorationType({ after: { color: new vscode.ThemeColor('rust_analyzer.inlayHint'), - fontStyle: "normal", - } + fontStyle: 'normal', + }, }), - toDecoration(hint: ra.InlayHint.TypeHint, conv: lc.Protocol2CodeConverter): vscode.DecorationOptions { + toDecoration( + hint: ra.InlayHint.TypeHint, + conv: lc.Protocol2CodeConverter, + ): vscode.DecorationOptions { return { range: conv.asRange(hint.range), - renderOptions: { after: { contentText: `: ${hint.label}` } } + renderOptions: { after: { contentText: `: ${hint.label}` } }, }; - } + }, }; const paramHints = { decorationType: vscode.window.createTextEditorDecorationType({ before: { color: new vscode.ThemeColor('rust_analyzer.inlayHint'), - fontStyle: "normal", - } + fontStyle: 'normal', + }, }), - toDecoration(hint: ra.InlayHint.ParamHint, conv: lc.Protocol2CodeConverter): vscode.DecorationOptions { + toDecoration( + hint: ra.InlayHint.ParamHint, + conv: lc.Protocol2CodeConverter, + ): vscode.DecorationOptions { return { range: conv.asRange(hint.range), - renderOptions: { before: { contentText: `${hint.label}: ` } } + renderOptions: { before: { contentText: `${hint.label}: ` } }, }; - } + }, }; class HintsUpdater implements Disposable { @@ -71,31 +77,32 @@ class HintsUpdater implements Disposable { vscode.window.onDidChangeVisibleTextEditors( this.onDidChangeVisibleTextEditors, this, - this.disposables + this.disposables, ); vscode.workspace.onDidChangeTextDocument( this.onDidChangeTextDocument, this, - this.disposables + this.disposables, ); // Set up initial cache shape - ctx.visibleRustEditors.forEach(editor => this.sourceFiles.set( - editor.document.uri.toString(), - { + ctx.visibleRustEditors.forEach(editor => + this.sourceFiles.set(editor.document.uri.toString(), { document: editor.document, inlaysRequest: null, - cachedDecorations: null - } - )); + cachedDecorations: null, + }), + ); this.syncCacheAndRenderHints(); } dispose(): void { this.sourceFiles.forEach(file => file.inlaysRequest?.cancel()); - this.ctx.visibleRustEditors.forEach(editor => this.renderDecorations(editor, { param: [], type: [] })); + this.ctx.visibleRustEditors.forEach(editor => + this.renderDecorations(editor, { param: [], type: [] }), + ); this.disposables.forEach(d => d.dispose()); } @@ -107,17 +114,19 @@ class HintsUpdater implements Disposable { private syncCacheAndRenderHints(): void { // FIXME: make inlayHints request pass an array of files? // eslint-disable-next-line @typescript-eslint/no-misused-promises - this.sourceFiles.forEach((file, uri) => this.fetchHints(file).then(hints => { - if (!hints) return; + this.sourceFiles.forEach((file, uri) => + this.fetchHints(file).then(hints => { + if (!hints) return; - file.cachedDecorations = this.hintsToDecorations(hints); + file.cachedDecorations = this.hintsToDecorations(hints); - for (const editor of this.ctx.visibleRustEditors) { - if (editor.document.uri.toString() === uri) { - this.renderDecorations(editor, file.cachedDecorations); + for (const editor of this.ctx.visibleRustEditors) { + if (editor.document.uri.toString() === uri) { + this.renderDecorations(editor, file.cachedDecorations); + } } - } - })); + }), + ); } onDidChangeVisibleTextEditors(): void { @@ -130,7 +139,7 @@ class HintsUpdater implements Disposable { const file = this.sourceFiles.get(uri) ?? { document: editor.document, inlaysRequest: null, - cachedDecorations: null + cachedDecorations: null, }; newSourceFiles.set(uri, file); @@ -204,12 +213,12 @@ interface InlaysDecorations { interface RustSourceFile { /* - * Source of the token to cancel in-flight inlay hints request if any. - */ + * Source of the token to cancel in-flight inlay hints request if any. + */ inlaysRequest: null | vscode.CancellationTokenSource; /** - * Last applied decorations. - */ + * Last applied decorations. + */ cachedDecorations: null | InlaysDecorations; document: RustDocument; diff --git a/editors/code/src/installation/downloads.ts b/editors/code/src/installation/downloads.ts index 54325ebbefc0..c419df094e7b 100644 --- a/editors/code/src/installation/downloads.ts +++ b/editors/code/src/installation/downloads.ts @@ -1,11 +1,11 @@ -import fetch from "node-fetch"; -import * as vscode from "vscode"; -import * as path from "path"; -import * as fs from "fs"; -import * as stream from "stream"; -import * as util from "util"; -import { log, assert } from "../util"; -import { ArtifactReleaseInfo } from "./interfaces"; +import fetch from 'node-fetch'; +import * as vscode from 'vscode'; +import * as path from 'path'; +import * as fs from 'fs'; +import * as stream from 'stream'; +import * as util from 'util'; +import { log, assert } from '../util'; +import { ArtifactReleaseInfo } from './interfaces'; const pipeline = util.promisify(stream.pipeline); @@ -19,24 +19,24 @@ export async function downloadFile( url: string, destFilePath: fs.PathLike, destFilePermissions: number, - onProgress: (readBytes: number, totalBytes: number) => void + onProgress: (readBytes: number, totalBytes: number) => void, ): Promise { const res = await fetch(url); if (!res.ok) { - log.error("Error", res.status, "while downloading file from", url); + log.error('Error', res.status, 'while downloading file from', url); log.error({ body: await res.text(), headers: res.headers }); throw new Error(`Got response ${res.status} when trying to download a file.`); } const totalBytes = Number(res.headers.get('content-length')); - assert(!Number.isNaN(totalBytes), "Sanity check of content-length protocol"); + assert(!Number.isNaN(totalBytes), 'Sanity check of content-length protocol'); - log.debug("Downloading file of", totalBytes, "bytes size from", url, "to", destFilePath); + log.debug('Downloading file of', totalBytes, 'bytes size from', url, 'to', destFilePath); let readBytes = 0; - res.body.on("data", (chunk: Buffer) => { + res.body.on('data', (chunk: Buffer) => { readBytes += chunk.length; onProgress(readBytes, totalBytes); }); @@ -45,7 +45,7 @@ export async function downloadFile( await pipeline(res.body, destFileStream); return new Promise(resolve => { - destFileStream.on("close", resolve); + destFileStream.on('close', resolve); destFileStream.destroy(); // Details on workaround: https://github.com/rust-analyzer/rust-analyzer/pull/3092#discussion_r378191131 @@ -66,11 +66,15 @@ export async function downloadArtifactWithProgressUi( installationDir: string, displayName: string, ): Promise { - await fs.promises.mkdir(installationDir).catch(err => assert( - err?.code === "EEXIST", - `Couldn't create directory "${installationDir}" to download ` + - `${artifactFileName} artifact: ${err?.message}` - )); + await fs.promises + .mkdir(installationDir) + .catch(err => + assert( + err?.code === 'EEXIST', + `Couldn't create directory "${installationDir}" to download ` + + `${artifactFileName} artifact: ${err?.message}`, + ), + ); const installationPath = path.join(installationDir, artifactFileName); @@ -78,20 +82,25 @@ export async function downloadArtifactWithProgressUi( { location: vscode.ProgressLocation.Notification, cancellable: false, // FIXME: add support for canceling download? - title: `Downloading rust-analyzer ${displayName} (${releaseName})` + title: `Downloading rust-analyzer ${displayName} (${releaseName})`, }, async (progress, _cancellationToken) => { let lastPrecentage = 0; const filePermissions = 0o755; // (rwx, r_x, r_x) - await downloadFile(downloadUrl, installationPath, filePermissions, (readBytes, totalBytes) => { - const newPercentage = (readBytes / totalBytes) * 100; - progress.report({ - message: newPercentage.toFixed(0) + "%", - increment: newPercentage - lastPrecentage - }); + await downloadFile( + downloadUrl, + installationPath, + filePermissions, + (readBytes, totalBytes) => { + const newPercentage = (readBytes / totalBytes) * 100; + progress.report({ + message: newPercentage.toFixed(0) + '%', + increment: newPercentage - lastPrecentage, + }); - lastPrecentage = newPercentage; - }); - } + lastPrecentage = newPercentage; + }, + ); + }, ); } diff --git a/editors/code/src/installation/extension.ts b/editors/code/src/installation/extension.ts index 331c626f23a9..40499266417d 100644 --- a/editors/code/src/installation/extension.ts +++ b/editors/code/src/installation/extension.ts @@ -1,13 +1,20 @@ -import * as vscode from "vscode"; -import * as path from "path"; +import * as vscode from 'vscode'; +import * as path from 'path'; import { promises as fs } from 'fs'; -import { vscodeReinstallExtension, vscodeReloadWindow, log, vscodeInstallExtensionFromVsix, assert, notReentrant } from "../util"; -import { Config, UpdatesChannel } from "../config"; -import { ArtifactReleaseInfo, ArtifactSource } from "./interfaces"; -import { downloadArtifactWithProgressUi } from "./downloads"; -import { fetchArtifactReleaseInfo } from "./fetch_artifact_release_info"; -import { PersistentState } from "../persistent_state"; +import { + vscodeReinstallExtension, + vscodeReloadWindow, + log, + vscodeInstallExtensionFromVsix, + assert, + notReentrant, +} from '../util'; +import { Config, UpdatesChannel } from '../config'; +import { ArtifactReleaseInfo, ArtifactSource } from './interfaces'; +import { downloadArtifactWithProgressUi } from './downloads'; +import { fetchArtifactReleaseInfo } from './fetch_artifact_release_info'; +import { PersistentState } from '../persistent_state'; const HEURISTIC_NIGHTLY_RELEASE_PERIOD_IN_HOURS = 25; @@ -15,7 +22,10 @@ const HEURISTIC_NIGHTLY_RELEASE_PERIOD_IN_HOURS = 25; * Installs `stable` or latest `nightly` version or does nothing if the current * extension version is what's needed according to `desiredUpdateChannel`. */ -export async function ensureProperExtensionVersion(config: Config, state: PersistentState): Promise { +export async function ensureProperExtensionVersion( + config: Config, + state: PersistentState, +): Promise { // User has built lsp server from sources, she should manage updates manually if (config.serverSource?.type === ArtifactSource.Type.ExplicitPath) return; @@ -31,14 +41,14 @@ export async function ensureProperExtensionVersion(config: Config, state: Persis // VSCode should handle updates for stable channel if (currentUpdChannel === UpdatesChannel.Stable) return; - if (!await askToDownloadProperExtensionVersion(config)) return; + if (!(await askToDownloadProperExtensionVersion(config))) return; await vscodeReinstallExtension(config.extensionId); await vscodeReloadWindow(); // never returns } if (currentUpdChannel === UpdatesChannel.Stable) { - if (!await askToDownloadProperExtensionVersion(config)) return; + if (!(await askToDownloadProperExtensionVersion(config))) return; return await tryDownloadNightlyExtension(config, state); } @@ -48,36 +58,46 @@ export async function ensureProperExtensionVersion(config: Config, state: Persis if (currentExtReleaseDate === null) { void vscode.window.showErrorMessage( "Nightly release date must've been set during the installation. " + - "Did you download and install the nightly .vsix package manually?" + 'Did you download and install the nightly .vsix package manually?', ); - throw new Error("Nightly release date was not set in globalStorage"); + throw new Error('Nightly release date was not set in globalStorage'); } - const dateNow = new Date; + const dateNow = new Date(); const hoursSinceLastUpdate = diffInHours(currentExtReleaseDate, dateNow); log.debug( - "Current rust-analyzer nightly was downloaded", hoursSinceLastUpdate, - "hours ago, namely:", currentExtReleaseDate, "and now is", dateNow + 'Current rust-analyzer nightly was downloaded', + hoursSinceLastUpdate, + 'hours ago, namely:', + currentExtReleaseDate, + 'and now is', + dateNow, ); if (hoursSinceLastUpdate < HEURISTIC_NIGHTLY_RELEASE_PERIOD_IN_HOURS) { return; } - if (!await askToDownloadProperExtensionVersion(config, "The installed nightly version is most likely outdated. ")) { + if ( + !(await askToDownloadProperExtensionVersion( + config, + 'The installed nightly version is most likely outdated. ', + )) + ) { return; } await tryDownloadNightlyExtension(config, state, releaseInfo => { assert( - currentExtReleaseDate.getTime() === state.installedNightlyExtensionReleaseDate.get()?.getTime(), - "Other active VSCode instance has reinstalled the extension" + currentExtReleaseDate.getTime() === + state.installedNightlyExtensionReleaseDate.get()?.getTime(), + 'Other active VSCode instance has reinstalled the extension', ); if (releaseInfo.releaseDate.getTime() === currentExtReleaseDate.getTime()) { vscode.window.showInformationMessage( - "Whoops, it appears that your nightly version is up-to-date. " + - "There might be some problems with the upcomming nightly release " + - "or you traveled too far into the future. Sorry for that 😅! " + 'Whoops, it appears that your nightly version is up-to-date. ' + + 'There might be some problems with the upcomming nightly release ' + + 'or you traveled too far into the future. Sorry for that 😅! ', ); return false; } @@ -85,10 +105,11 @@ export async function ensureProperExtensionVersion(config: Config, state: Persis }); } -async function askToDownloadProperExtensionVersion(config: Config, reason = ""): Promise { +async function askToDownloadProperExtensionVersion(config: Config, reason = ''): Promise { if (!config.askBeforeDownload) return true; - const stableOrNightly = config.updatesChannel === UpdatesChannel.Stable ? "stable" : "latest nightly"; + const stableOrNightly = + config.updatesChannel === UpdatesChannel.Stable ? 'stable' : 'latest nightly'; // In case of reentering this function and showing the same info message // (e.g. after we had shown this message, the user changed the config) @@ -96,11 +117,13 @@ async function askToDownloadProperExtensionVersion(config: Config, reason = ""): // This behaviour is what we want, but likely it is not documented const userResponse = await vscode.window.showInformationMessage( - reason + `Do you want to download the ${stableOrNightly} rust-analyzer extension ` + - `version and reload the window now?`, - "Download now", "Cancel" + reason + + `Do you want to download the ${stableOrNightly} rust-analyzer extension ` + + `version and reload the window now?`, + 'Download now', + 'Cancel', ); - return userResponse === "Download now"; + return userResponse === 'Download now'; } /** @@ -110,30 +133,41 @@ async function askToDownloadProperExtensionVersion(config: Config, reason = ""): * each of them would result in a ton of code (especially accounting for cross-process * shared mutable `globalState` access). Enforcing no reentrancy for this is best-effort. */ -const tryDownloadNightlyExtension = notReentrant(async ( - config: Config, - state: PersistentState, - shouldDownload: (releaseInfo: ArtifactReleaseInfo) => boolean = (): boolean => true -): Promise => { - const vsixSource = config.nightlyVsixSource; - try { - const releaseInfo = await fetchArtifactReleaseInfo(vsixSource.repo, vsixSource.file, vsixSource.tag); +const tryDownloadNightlyExtension = notReentrant( + async ( + config: Config, + state: PersistentState, + shouldDownload: (releaseInfo: ArtifactReleaseInfo) => boolean = (): boolean => true, + ): Promise => { + const vsixSource = config.nightlyVsixSource; + try { + const releaseInfo = await fetchArtifactReleaseInfo( + vsixSource.repo, + vsixSource.file, + vsixSource.tag, + ); - if (!shouldDownload(releaseInfo)) return; + if (!shouldDownload(releaseInfo)) return; - await downloadArtifactWithProgressUi(releaseInfo, vsixSource.file, vsixSource.dir, "nightly extension"); + await downloadArtifactWithProgressUi( + releaseInfo, + vsixSource.file, + vsixSource.dir, + 'nightly extension', + ); - const vsixPath = path.join(vsixSource.dir, vsixSource.file); + const vsixPath = path.join(vsixSource.dir, vsixSource.file); - await vscodeInstallExtensionFromVsix(vsixPath); - await state.installedNightlyExtensionReleaseDate.set(releaseInfo.releaseDate); - await fs.unlink(vsixPath); + await vscodeInstallExtensionFromVsix(vsixPath); + await state.installedNightlyExtensionReleaseDate.set(releaseInfo.releaseDate); + await fs.unlink(vsixPath); - await vscodeReloadWindow(); // never returns - } catch (err) { - log.downloadError(err, "nightly extension", vsixSource.repo.name); - } -}); + await vscodeReloadWindow(); // never returns + } catch (err) { + log.downloadError(err, 'nightly extension', vsixSource.repo.name); + } + }, +); function diffInHours(a: Date, b: Date): number { // Discard the time and time-zone information (to abstract from daylight saving time bugs) diff --git a/editors/code/src/installation/fetch_artifact_release_info.ts b/editors/code/src/installation/fetch_artifact_release_info.ts index 1ad3b8338ba9..bfc074c36824 100644 --- a/editors/code/src/installation/fetch_artifact_release_info.ts +++ b/editors/code/src/installation/fetch_artifact_release_info.ts @@ -1,8 +1,8 @@ -import fetch from "node-fetch"; -import { GithubRepo, ArtifactReleaseInfo } from "./interfaces"; -import { log } from "../util"; +import fetch from 'node-fetch'; +import { GithubRepo, ArtifactReleaseInfo } from './interfaces'; +import { log } from '../util'; -const GITHUB_API_ENDPOINT_URL = "https://api.github.com"; +const GITHUB_API_ENDPOINT_URL = 'https://api.github.com'; /** * Fetches the release with `releaseTag` from GitHub `repo` and @@ -14,9 +14,8 @@ const GITHUB_API_ENDPOINT_URL = "https://api.github.com"; export async function fetchArtifactReleaseInfo( repo: GithubRepo, artifactFileName: string, - releaseTag: string + releaseTag: string, ): Promise { - const repoOwner = encodeURIComponent(repo.owner); const repoName = encodeURIComponent(repo.name); @@ -24,12 +23,14 @@ export async function fetchArtifactReleaseInfo( const requestUrl = GITHUB_API_ENDPOINT_URL + apiEndpointPath; - log.debug("Issuing request for released artifacts metadata to", requestUrl); + log.debug('Issuing request for released artifacts metadata to', requestUrl); - const response = await fetch(requestUrl, { headers: { Accept: "application/vnd.github.v3+json" } }); + const response = await fetch(requestUrl, { + headers: { Accept: 'application/vnd.github.v3+json' }, + }); if (!response.ok) { - log.error("Error fetching artifact release info", { + log.error('Error fetching artifact release info', { requestUrl, releaseTag, artifactFileName, @@ -37,12 +38,12 @@ export async function fetchArtifactReleaseInfo( headers: response.headers, status: response.status, body: await response.text(), - } + }, }); throw new Error( `Got response ${response.status} when trying to fetch ` + - `"${artifactFileName}" artifact release info for ${releaseTag} release` + `"${artifactFileName}" artifact release info for ${releaseTag} release`, ); } @@ -52,15 +53,13 @@ export async function fetchArtifactReleaseInfo( const artifact = release.assets.find(artifact => artifact.name === artifactFileName); if (!artifact) { - throw new Error( - `Artifact ${artifactFileName} was not found in ${release.name} release!` - ); + throw new Error(`Artifact ${artifactFileName} was not found in ${release.name} release!`); } return { releaseName: release.name, releaseDate: new Date(release.published_at), - downloadUrl: artifact.browser_download_url + downloadUrl: artifact.browser_download_url, }; // We omit declaration of tremendous amount of fields that we are not using here diff --git a/editors/code/src/installation/interfaces.ts b/editors/code/src/installation/interfaces.ts index 1a8ea0884cb6..1b853bd92d90 100644 --- a/editors/code/src/installation/interfaces.ts +++ b/editors/code/src/installation/interfaces.ts @@ -22,7 +22,10 @@ export namespace ArtifactSource { /** * Type tag for `ArtifactSource` discriminated union. */ - export const enum Type { ExplicitPath, GithubRelease } + export const enum Type { + ExplicitPath, + GithubRelease, + } export interface ExplicitPath { type: Type.ExplicitPath; @@ -41,7 +44,6 @@ export namespace ArtifactSource { */ repo: GithubRepo; - // FIXME: add installationPath: string; /** diff --git a/editors/code/src/installation/server.ts b/editors/code/src/installation/server.ts index 05d32613158b..ee9a4b50bb39 100644 --- a/editors/code/src/installation/server.ts +++ b/editors/code/src/installation/server.ts @@ -1,25 +1,28 @@ -import * as vscode from "vscode"; -import * as path from "path"; -import { spawnSync } from "child_process"; - -import { ArtifactSource } from "./interfaces"; -import { fetchArtifactReleaseInfo } from "./fetch_artifact_release_info"; -import { downloadArtifactWithProgressUi } from "./downloads"; -import { log, assert, notReentrant } from "../util"; -import { Config, NIGHTLY_TAG } from "../config"; -import { PersistentState } from "../persistent_state"; - -export async function ensureServerBinary(config: Config, state: PersistentState): Promise { +import * as vscode from 'vscode'; +import * as path from 'path'; +import { spawnSync } from 'child_process'; + +import { ArtifactSource } from './interfaces'; +import { fetchArtifactReleaseInfo } from './fetch_artifact_release_info'; +import { downloadArtifactWithProgressUi } from './downloads'; +import { log, assert, notReentrant } from '../util'; +import { Config, NIGHTLY_TAG } from '../config'; +import { PersistentState } from '../persistent_state'; + +export async function ensureServerBinary( + config: Config, + state: PersistentState, +): Promise { const source = config.serverSource; if (!source) { vscode.window.showErrorMessage( "Unfortunately we don't ship binaries for your platform yet. " + - "You need to manually clone rust-analyzer repository and " + - "run `cargo xtask install --server` to build the language server from sources. " + - "If you feel that your platform should be supported, please create an issue " + - "about that [here](https://github.com/rust-analyzer/rust-analyzer/issues) and we " + - "will consider it." + 'You need to manually clone rust-analyzer repository and ' + + 'run `cargo xtask install --server` to build the language server from sources. ' + + 'If you feel that your platform should be supported, please create an issue ' + + 'about that [here](https://github.com/rust-analyzer/rust-analyzer/issues) and we ' + + 'will consider it.', ); return null; } @@ -32,8 +35,8 @@ export async function ensureServerBinary(config: Config, state: PersistentState) vscode.window.showErrorMessage( `Unable to run ${source.path} binary. ` + - `To use the pre-built language server, set "rust-analyzer.serverPath" ` + - "value to `null` or remove it from the settings to use it by default." + `To use the pre-built language server, set "rust-analyzer.serverPath" ` + + 'value to `null` or remove it from the settings to use it by default.', ); return null; } @@ -45,10 +48,11 @@ export async function ensureServerBinary(config: Config, state: PersistentState) if (config.askBeforeDownload) { const userResponse = await vscode.window.showInformationMessage( `Language server version ${source.tag} for rust-analyzer is not installed. ` + - "Do you want to download it now?", - "Download now", "Cancel" + 'Do you want to download it now?', + 'Download now', + 'Cancel', ); - if (userResponse !== "Download now") return null; + if (userResponse !== 'Download now') return null; } return await downloadServer(state, source); @@ -64,21 +68,27 @@ function shouldDownloadServer( const installed = { tag: state.serverReleaseTag.get(), - date: state.serverReleaseDate.get() + date: state.serverReleaseDate.get(), }; const required = { tag: source.tag, - date: state.installedNightlyExtensionReleaseDate.get() + date: state.installedNightlyExtensionReleaseDate.get(), }; - log.debug("Installed server:", installed, "required:", required); + log.debug('Installed server:', installed, 'required:', required); if (required.tag !== NIGHTLY_TAG || installed.tag !== NIGHTLY_TAG) { return required.tag !== installed.tag; } - assert(required.date !== null, "Extension release date should have been saved during its installation"); - assert(installed.date !== null, "Server release date should have been saved during its installation"); + assert( + required.date !== null, + 'Extension release date should have been saved during its installation', + ); + assert( + installed.date !== null, + 'Server release date should have been saved during its installation', + ); return installed.date.getTime() !== required.date.getTime(); } @@ -86,46 +96,58 @@ function shouldDownloadServer( /** * Enforcing no reentrancy for this is best-effort. */ -const downloadServer = notReentrant(async ( - state: PersistentState, - source: ArtifactSource.GithubRelease, -): Promise => { - try { - const releaseInfo = await fetchArtifactReleaseInfo(source.repo, source.file, source.tag); - - await downloadArtifactWithProgressUi(releaseInfo, source.file, source.dir, "language server"); - await Promise.all([ - state.serverReleaseTag.set(releaseInfo.releaseName), - state.serverReleaseDate.set(releaseInfo.releaseDate) - ]); - } catch (err) { - log.downloadError(err, "language server", source.repo.name); - return null; - } +const downloadServer = notReentrant( + async ( + state: PersistentState, + source: ArtifactSource.GithubRelease, + ): Promise => { + try { + const releaseInfo = await fetchArtifactReleaseInfo( + source.repo, + source.file, + source.tag, + ); - const binaryPath = path.join(source.dir, source.file); + await downloadArtifactWithProgressUi( + releaseInfo, + source.file, + source.dir, + 'language server', + ); + await Promise.all([ + state.serverReleaseTag.set(releaseInfo.releaseName), + state.serverReleaseDate.set(releaseInfo.releaseDate), + ]); + } catch (err) { + log.downloadError(err, 'language server', source.repo.name); + return null; + } - assert(isBinaryAvailable(binaryPath), - `Downloaded language server binary is not functional.` + - `Downloaded from GitHub repo ${source.repo.owner}/${source.repo.name} ` + - `to ${binaryPath}` - ); + const binaryPath = path.join(source.dir, source.file); - vscode.window.showInformationMessage( - "Rust analyzer language server was successfully installed 🦀" - ); + assert( + isBinaryAvailable(binaryPath), + `Downloaded language server binary is not functional.` + + `Downloaded from GitHub repo ${source.repo.owner}/${source.repo.name} ` + + `to ${binaryPath}`, + ); + + vscode.window.showInformationMessage( + 'Rust analyzer language server was successfully installed 🦀', + ); - return binaryPath; -}); + return binaryPath; + }, +); function isBinaryAvailable(binaryPath: string): boolean { - const res = spawnSync(binaryPath, ["--version"]); + const res = spawnSync(binaryPath, ['--version']); // ACHTUNG! `res` type declaration is inherently wrong, see // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/42221 - log.debug("Checked binary availablity via --version", res); - log.debug(binaryPath, "--version output:", res.output?.map(String)); + log.debug('Checked binary availablity via --version', res); + log.debug(binaryPath, '--version output:', res.output?.map(String)); return res.status === 0; } diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index b1fe311f06db..e036ffcc3d02 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -28,16 +28,17 @@ export async function activate(context: vscode.ExtensionContext): Promise // "rust-analyzer is not available" // ), // ) - const defaultOnEnter = vscode.commands.registerCommand( - 'rust-analyzer.onEnter', - () => vscode.commands.executeCommand('default:type', { text: '\n' }), + const defaultOnEnter = vscode.commands.registerCommand('rust-analyzer.onEnter', () => + vscode.commands.executeCommand('default:type', { text: '\n' }), ); context.subscriptions.push(defaultOnEnter); const config = new Config(context); const state = new PersistentState(context); - vscode.workspace.onDidChangeConfiguration(() => ensureProperExtensionVersion(config, state).catch(log.error)); + vscode.workspace.onDidChangeConfiguration(() => + ensureProperExtensionVersion(config, state).catch(log.error), + ); // Don't await the user response here, otherwise we will block the lsp server bootstrap void ensureProperExtensionVersion(config, state).catch(log.error); @@ -46,8 +47,8 @@ export async function activate(context: vscode.ExtensionContext): Promise if (serverPath == null) { throw new Error( - "Rust Analyzer Language Server is not available. " + - "Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation)." + 'Rust Analyzer Language Server is not available. ' + + 'Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation).', ); } @@ -58,7 +59,7 @@ export async function activate(context: vscode.ExtensionContext): Promise ctx = await Ctx.create(config, state, context, serverPath); // Commands which invokes manually via command palette, shortcut, etc. - ctx.registerCommand('reload', (ctx) => { + ctx.registerCommand('reload', ctx => { return async (): Promise => { vscode.window.showInformationMessage('Reloading rust-analyzer...'); // @DanTup maneuver diff --git a/editors/code/src/persistent_state.ts b/editors/code/src/persistent_state.ts index 010c0a03b96a..09802720fc79 100644 --- a/editors/code/src/persistent_state.ts +++ b/editors/code/src/persistent_state.ts @@ -1,33 +1,35 @@ import * as vscode from 'vscode'; -import { log } from "./util"; +import { log } from './util'; export class PersistentState { - constructor(private readonly ctx: vscode.ExtensionContext) { - } + constructor(private readonly ctx: vscode.ExtensionContext) {} readonly installedNightlyExtensionReleaseDate = new DateStorage( - "installed-nightly-extension-release-date", - this.ctx.globalState + 'installed-nightly-extension-release-date', + this.ctx.globalState, + ); + readonly serverReleaseDate = new DateStorage('server-release-date', this.ctx.globalState); + readonly serverReleaseTag = new Storage( + 'server-release-tag', + this.ctx.globalState, + null, ); - readonly serverReleaseDate = new DateStorage("server-release-date", this.ctx.globalState); - readonly serverReleaseTag = new Storage("server-release-tag", this.ctx.globalState, null); } - export class Storage { constructor( private readonly key: string, private readonly storage: vscode.Memento, - private readonly defaultVal: T - ) { } + private readonly defaultVal: T, + ) {} get(): T { const val = this.storage.get(this.key, this.defaultVal); - log.debug(this.key, "==", val); + log.debug(this.key, '==', val); return val; } async set(val: T): Promise { - log.debug(this.key, "=", val); + log.debug(this.key, '=', val); await this.storage.update(this.key, val); } } diff --git a/editors/code/src/rust-analyzer-api.ts b/editors/code/src/rust-analyzer-api.ts index 46c523562b03..d027cf7ba1fd 100644 --- a/editors/code/src/rust-analyzer-api.ts +++ b/editors/code/src/rust-analyzer-api.ts @@ -2,32 +2,30 @@ * This file mirrors `crates/rust-analyzer/src/req.rs` declarations. */ -import * as lc from "vscode-languageclient"; +import * as lc from 'vscode-languageclient'; type Option = null | T; type Vec = T[]; type FxHashMap = Record; -function request(method: string): lc.RequestType { +function request( + method: string, +): lc.RequestType { return new lc.RequestType(`rust-analyzer/${method}`); } function notification(method: string): lc.NotificationType { return new lc.NotificationType(method); } +export const analyzerStatus = request('analyzerStatus'); -export const analyzerStatus = request("analyzerStatus"); - - -export const collectGarbage = request("collectGarbage"); - +export const collectGarbage = request('collectGarbage'); export interface SyntaxTreeParams { textDocument: lc.TextDocumentIdentifier; range: Option; } -export const syntaxTree = request("syntaxTree"); - +export const syntaxTree = request('syntaxTree'); export interface ExpandMacroParams { textDocument: lc.TextDocumentIdentifier; @@ -37,15 +35,15 @@ export interface ExpandedMacro { name: string; expansion: string; } -export const expandMacro = request>("expandMacro"); - +export const expandMacro = request>('expandMacro'); export interface FindMatchingBraceParams { textDocument: lc.TextDocumentIdentifier; offsets: Vec; } -export const findMatchingBrace = request>("findMatchingBrace"); - +export const findMatchingBrace = request>( + 'findMatchingBrace', +); export interface PublishDecorationsParams { uri: string; @@ -56,20 +54,21 @@ export interface Decoration { tag: string; bindingHash: Option; } -export const decorationsRequest = request>("decorationsRequest"); - - -export const parentModule = request>("parentModule"); +export const decorationsRequest = request>( + 'decorationsRequest', +); +export const parentModule = request>( + 'parentModule', +); export interface JoinLinesParams { textDocument: lc.TextDocumentIdentifier; range: lc.Range; } -export const joinLines = request("joinLines"); - +export const joinLines = request('joinLines'); -export const onEnter = request>("onEnter"); +export const onEnter = request>('onEnter'); export interface RunnablesParams { textDocument: lc.TextDocumentIdentifier; @@ -84,14 +83,14 @@ export interface Runnable { env: FxHashMap; cwd: Option; } -export const runnables = request>("runnables"); +export const runnables = request>('runnables'); export type InlayHint = InlayHint.TypeHint | InlayHint.ParamHint; export namespace InlayHint { export const enum Kind { - TypeHint = "TypeHint", - ParamHint = "ParameterHint", + TypeHint = 'TypeHint', + ParamHint = 'ParameterHint', } interface Common { range: lc.Range; @@ -103,18 +102,15 @@ export namespace InlayHint { export interface InlayHintsParams { textDocument: lc.TextDocumentIdentifier; } -export const inlayHints = request>("inlayHints"); - +export const inlayHints = request>('inlayHints'); export interface SsrParams { query: string; parseOnly: boolean; } -export const ssr = request("ssr"); - - -export const publishDecorations = notification("publishDecorations"); +export const ssr = request('ssr'); +export const publishDecorations = notification('publishDecorations'); export interface SourceChange { label: string; diff --git a/editors/code/src/source_change.ts b/editors/code/src/source_change.ts index 21928aaa2025..b75a72ab8166 100644 --- a/editors/code/src/source_change.ts +++ b/editors/code/src/source_change.ts @@ -8,9 +8,7 @@ export async function applySourceChange(ctx: Ctx, change: ra.SourceChange): Prom const client = ctx.client; if (!client) return; - const wsEdit = client.protocol2CodeConverter.asWorkspaceEdit( - change.workspaceEdit, - ); + const wsEdit = client.protocol2CodeConverter.asWorkspaceEdit(change.workspaceEdit); let created; let moved; if (change.workspaceEdit.documentChanges) { @@ -30,12 +28,8 @@ export async function applySourceChange(ctx: Ctx, change: ra.SourceChange): Prom const doc = await vscode.workspace.openTextDocument(toOpenUri); await vscode.window.showTextDocument(doc); } else if (toReveal) { - const uri = client.protocol2CodeConverter.asUri( - toReveal.textDocument.uri, - ); - const position = client.protocol2CodeConverter.asPosition( - toReveal.position, - ); + const uri = client.protocol2CodeConverter.asUri(toReveal.textDocument.uri); + const position = client.protocol2CodeConverter.asPosition(toReveal.position); const editor = vscode.window.activeTextEditor; if (!editor || editor.document.uri.toString() !== uri.toString()) { return; diff --git a/editors/code/src/status_display.ts b/editors/code/src/status_display.ts index 1c25fda1b224..1b610b93f58e 100644 --- a/editors/code/src/status_display.ts +++ b/editors/code/src/status_display.ts @@ -1,6 +1,12 @@ import * as vscode from 'vscode'; -import { WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressReport, WorkDoneProgressEnd, Disposable } from 'vscode-languageclient'; +import { + WorkDoneProgress, + WorkDoneProgressBegin, + WorkDoneProgressReport, + WorkDoneProgressEnd, + Disposable, +} from 'vscode-languageclient'; import { Ctx } from './ctx'; @@ -11,11 +17,11 @@ export function activateStatusDisplay(ctx: Ctx): void { ctx.pushCleanup(statusDisplay); const client = ctx.client; if (client != null) { - ctx.pushCleanup(client.onProgress( - WorkDoneProgress.type, - 'rustAnalyzer/cargoWatcher', - params => statusDisplay.handleProgressNotification(params) - )); + ctx.pushCleanup( + client.onProgress(WorkDoneProgress.type, 'rustAnalyzer/cargoWatcher', params => + statusDisplay.handleProgressNotification(params), + ), + ); } } @@ -28,10 +34,7 @@ class StatusDisplay implements Disposable { private timer?: NodeJS.Timeout; constructor(command: string) { - this.statusBarItem = vscode.window.createStatusBarItem( - vscode.StatusBarAlignment.Left, - 10, - ); + this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 10); this.command = command; this.statusBarItem.hide(); } @@ -69,13 +72,17 @@ class StatusDisplay implements Disposable { refreshLabel(): void { if (this.packageName) { - this.statusBarItem.text = `${spinnerFrames[this.i]} cargo ${this.command} [${this.packageName}]`; + this.statusBarItem.text = `${spinnerFrames[this.i]} cargo ${this.command} [${ + this.packageName + }]`; } else { this.statusBarItem.text = `${spinnerFrames[this.i]} cargo ${this.command}`; } } - handleProgressNotification(params: WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd): void { + handleProgressNotification( + params: WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd, + ): void { switch (params.kind) { case 'begin': this.show(); diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts index 7fb8a6771dbb..a7145344250d 100644 --- a/editors/code/src/util.ts +++ b/editors/code/src/util.ts @@ -1,7 +1,7 @@ -import * as lc from "vscode-languageclient"; -import * as vscode from "vscode"; -import { promises as dns } from "dns"; -import { strict as nativeAssert } from "assert"; +import * as lc from 'vscode-languageclient'; +import * as vscode from 'vscode'; +import { promises as dns } from 'dns'; +import { strict as nativeAssert } from 'assert'; export function assert(condition: boolean, explanation: string): asserts condition { try { @@ -12,7 +12,7 @@ export function assert(condition: boolean, explanation: string): asserts conditi } } -export const log = new class { +export const log = new (class { private enabled = true; setEnabled(yes: boolean): void { @@ -34,19 +34,20 @@ export const log = new class { downloadError(err: Error, artifactName: string, repoName: string): void { vscode.window.showErrorMessage( `Failed to download the rust-analyzer ${artifactName} from ${repoName} ` + - `GitHub repository: ${err.message}` + `GitHub repository: ${err.message}`, ); log.error(err); dns.resolve('example.com').then( - addrs => log.debug("DNS resolution for example.com was successful", addrs), - err => log.error( - "DNS resolution for example.com failed, " + - "there might be an issue with Internet availability", - err - ) + addrs => log.debug('DNS resolution for example.com was successful', addrs), + err => + log.error( + 'DNS resolution for example.com failed, ' + + 'there might be an issue with Internet availability', + err, + ), ); } -}; +})(); export async function sendRequestWithRetry( client: lc.LanguageClient, @@ -58,11 +59,10 @@ export async function sendRequestWithRetry( try { return await (token ? client.sendRequest(reqType, param, token) - : client.sendRequest(reqType, param) - ); + : client.sendRequest(reqType, param)); } catch (error) { if (delay === null) { - log.error("LSP request timed out", { method: reqType.method, param, error }); + log.error('LSP request timed out', { method: reqType.method, param, error }); throw error; } @@ -71,7 +71,7 @@ export async function sendRequestWithRetry( } if (error.code !== lc.ErrorCodes.ContentModified) { - log.error("LSP request failed", { method: reqType.method, param, error }); + log.error('LSP request failed', { method: reqType.method, param, error }); throw error; } @@ -86,24 +86,26 @@ function sleep(ms: number): Promise { } export function notReentrant( - fn: (this: TThis, ...params: TParams) => Promise + fn: (this: TThis, ...params: TParams) => Promise, ): typeof fn { let entered = false; return function(...params): Promise { assert(!entered, `Reentrancy invariant for ${fn.name} is violated`); entered = true; - return fn.apply(this, params).finally(() => entered = false); + return fn.apply(this, params).finally(() => (entered = false)); }; } -export type RustDocument = vscode.TextDocument & { languageId: "rust" }; +export type RustDocument = vscode.TextDocument & { languageId: 'rust' }; export type RustEditor = vscode.TextEditor & { document: RustDocument; id: string }; export function isRustDocument(document: vscode.TextDocument): document is RustDocument { - return document.languageId === 'rust' + return ( + document.languageId === 'rust' && // SCM diff views have the same URI as the on-disk document but not the same content - && document.uri.scheme !== 'git' - && document.uri.scheme !== 'svn'; + document.uri.scheme !== 'git' && + document.uri.scheme !== 'svn' + ); } export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor { @@ -117,21 +119,21 @@ export async function vscodeReinstallExtension(extensionId: string): Promise { - await vscode.commands.executeCommand("workbench.action.reloadWindow"); + await vscode.commands.executeCommand('workbench.action.reloadWindow'); - assert(false, "unreachable"); + assert(false, 'unreachable'); } export async function vscodeInstallExtensionFromVsix(vsixPath: string): Promise { await vscode.commands.executeCommand( - "workbench.extensions.installExtension", - vscode.Uri.file(vsixPath) + 'workbench.extensions.installExtension', + vscode.Uri.file(vsixPath), ); } diff --git a/editors/code/tsconfig.json b/editors/code/tsconfig.json index 0c7702974a9c..e01b3762b338 100644 --- a/editors/code/tsconfig.json +++ b/editors/code/tsconfig.json @@ -3,9 +3,7 @@ "module": "commonjs", "target": "es2018", "outDir": "out", - "lib": [ - "es2019" - ], + "lib": ["es2019"], "esModuleInterop": true, "allowSyntheticDefaultImports": true, "sourceMap": true, @@ -17,7 +15,5 @@ "noFallthroughCasesInSwitch": true, "newLine": "LF" }, - "exclude": [ - "node_modules" - ] + "exclude": ["node_modules"] } From 8be009de8e37b671d1eafc10978f1b1d88167a34 Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Wed, 18 Mar 2020 20:06:37 -0600 Subject: [PATCH 7/9] Adjust eslint rules --- editors/code/.eslintrc.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/editors/code/.eslintrc.js b/editors/code/.eslintrc.js index 7ee18d150263..82acd1580520 100644 --- a/editors/code/.eslintrc.js +++ b/editors/code/.eslintrc.js @@ -22,10 +22,11 @@ module.exports = { 'prettier/@typescript-eslint', ], rules: { - camelcase: ['error'], + camelcase: 'error', eqeqeq: ['error', 'always', { null: 'ignore' }], - 'no-console': ['error'], + 'no-console': 'error', 'prefer-const': 'error', + '@typescript-eslint/explicit-function-return-type': ['warn', { allowExpressions: true }], '@typescript-eslint/member-delimiter-style': [ 'error', { From 2cec955033f9ed89acba3fa91dc56ac8d5a71f57 Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Wed, 18 Mar 2020 20:06:58 -0600 Subject: [PATCH 8/9] Work on formatting --- editors/code/src/client.ts | 2 +- editors/code/src/commands/analyzer_status.ts | 4 +-- editors/code/src/commands/expand_macro.ts | 4 +-- editors/code/src/commands/index.ts | 16 +++++------ editors/code/src/commands/join_lines.ts | 4 +-- editors/code/src/commands/matching_brace.ts | 4 +-- editors/code/src/commands/on_enter.ts | 4 +-- editors/code/src/commands/parent_module.ts | 4 +-- editors/code/src/commands/runnables.ts | 12 ++++---- editors/code/src/commands/server_version.ts | 8 ++++-- editors/code/src/commands/ssr.ts | 4 +-- editors/code/src/commands/syntax_tree.ts | 4 +-- editors/code/src/config.ts | 30 +++++++++++--------- editors/code/src/ctx.ts | 4 +-- editors/code/src/highlighting.ts | 2 +- editors/code/src/installation/downloads.ts | 4 ++- editors/code/src/installation/extension.ts | 18 ++++++++---- editors/code/src/installation/server.ts | 28 +++++++++++------- editors/code/src/rust-analyzer-api.ts | 4 +-- editors/code/src/util.ts | 8 ++++-- 20 files changed, 96 insertions(+), 72 deletions(-) diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 04ca4e057e44..c25cb656c98f 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -80,7 +80,7 @@ export function createClient(config: Config, serverPath: string): lc.LanguageCli // This also requires considering our settings strategy, which is work which needs doing // @ts-ignore The tracer is private to vscode-languageclient, but we need access to it to not log publishDecorations requests res._tracer = { - log: (messageOrDataObject: string | unknown, data?: string): void => { + log: (messageOrDataObject: string | unknown, data?: string) => { if (typeof messageOrDataObject === 'string') { if ( messageOrDataObject.includes('rust-analyzer/publishDecorations') || diff --git a/editors/code/src/commands/analyzer_status.ts b/editors/code/src/commands/analyzer_status.ts index 8cfe1159dca8..2d98c3de3df3 100644 --- a/editors/code/src/commands/analyzer_status.ts +++ b/editors/code/src/commands/analyzer_status.ts @@ -4,7 +4,7 @@ import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; // Shows status of rust-analyzer (for debugging) -export function analyzerStatus(ctx: Ctx): Cmd<[]> { +export function analyzerStatus(ctx: Ctx): Cmd<[], Promise> { let poller: NodeJS.Timer | null = null; const tdcp = new TextDocumentContentProvider(ctx); @@ -20,7 +20,7 @@ export function analyzerStatus(ctx: Ctx): Cmd<[]> { }, }); - return async function handle(): Promise { + return async function handle() { if (poller == null) { poller = setInterval(() => tdcp.eventEmitter.fire(tdcp.uri), 1000); } diff --git a/editors/code/src/commands/expand_macro.ts b/editors/code/src/commands/expand_macro.ts index 88b857720e23..a35a076d8fc1 100644 --- a/editors/code/src/commands/expand_macro.ts +++ b/editors/code/src/commands/expand_macro.ts @@ -6,11 +6,11 @@ import { Ctx, Cmd } from '../ctx'; // Opens the virtual file that will show the syntax tree // // The contents of the file come from the `TextDocumentContentProvider` -export function expandMacro(ctx: Ctx): Cmd<[]> { +export function expandMacro(ctx: Ctx): Cmd<[], Promise> { const tdcp = new TextDocumentContentProvider(ctx); ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp)); - return async (): Promise => { + return async () => { const document = await vscode.workspace.openTextDocument(tdcp.uri); tdcp.eventEmitter.fire(tdcp.uri); return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true); diff --git a/editors/code/src/commands/index.ts b/editors/code/src/commands/index.ts index bce1bff45414..d405c3a7b6aa 100644 --- a/editors/code/src/commands/index.ts +++ b/editors/code/src/commands/index.ts @@ -16,12 +16,12 @@ export * from './runnables'; export * from './ssr'; export * from './server_version'; -export function collectGarbage(ctx: Ctx): Cmd<[]> { - return async (): Promise => ctx.client.sendRequest(ra.collectGarbage, null); +export function collectGarbage(ctx: Ctx): Cmd<[], Promise> { + return async () => ctx.client.sendRequest(ra.collectGarbage, null); } -export function showReferences(ctx: Ctx): Cmd<[string, lc.Position, lc.Location[]]> { - return (uri: string, position: lc.Position, locations: lc.Location[]): void => { +export function showReferences(ctx: Ctx): Cmd<[string, lc.Position, lc.Location[]], void> { + return (uri, position, locations) => { const client = ctx.client; if (client) { vscode.commands.executeCommand( @@ -34,14 +34,14 @@ export function showReferences(ctx: Ctx): Cmd<[string, lc.Position, lc.Location[ }; } -export function applySourceChange(ctx: Ctx): Cmd<[ra.SourceChange]> { - return async (change: ra.SourceChange): Promise => { +export function applySourceChange(ctx: Ctx): Cmd<[ra.SourceChange], Promise> { + return async change => { await sourceChange.applySourceChange(ctx, change); }; } -export function selectAndApplySourceChange(ctx: Ctx): Cmd<[ra.SourceChange[]]> { - return async (changes: ra.SourceChange[]): Promise => { +export function selectAndApplySourceChange(ctx: Ctx): Cmd<[ra.SourceChange[]], Promise> { + return async changes => { if (changes.length === 1) { await sourceChange.applySourceChange(ctx, changes[0]); } else if (changes.length > 0) { diff --git a/editors/code/src/commands/join_lines.ts b/editors/code/src/commands/join_lines.ts index dca8f2153abf..25a6dc14dc0e 100644 --- a/editors/code/src/commands/join_lines.ts +++ b/editors/code/src/commands/join_lines.ts @@ -3,8 +3,8 @@ import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; import { applySourceChange } from '../source_change'; -export function joinLines(ctx: Ctx): Cmd<[]> { - return async (): Promise => { +export function joinLines(ctx: Ctx): Cmd<[], Promise> { + return async () => { const editor = ctx.activeRustEditor; const client = ctx.client; if (!editor || !client) return; diff --git a/editors/code/src/commands/matching_brace.ts b/editors/code/src/commands/matching_brace.ts index ca48a2177ce7..ee58925a60de 100644 --- a/editors/code/src/commands/matching_brace.ts +++ b/editors/code/src/commands/matching_brace.ts @@ -3,8 +3,8 @@ import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; -export function matchingBrace(ctx: Ctx): Cmd<[]> { - return async (): Promise => { +export function matchingBrace(ctx: Ctx): Cmd<[], Promise> { + return async () => { const editor = ctx.activeRustEditor; const client = ctx.client; if (!editor || !client) return; diff --git a/editors/code/src/commands/on_enter.ts b/editors/code/src/commands/on_enter.ts index cdd488097729..3ebe7b1fd5f8 100644 --- a/editors/code/src/commands/on_enter.ts +++ b/editors/code/src/commands/on_enter.ts @@ -25,8 +25,8 @@ async function handleKeypress(ctx: Ctx): Promise { return true; } -export function onEnter(ctx: Ctx): Cmd<[]> { - return async (): Promise => { +export function onEnter(ctx: Ctx): Cmd<[], Promise> { + return async () => { if (await handleKeypress(ctx)) return; await vscode.commands.executeCommand('default:type', { text: '\n' }); diff --git a/editors/code/src/commands/parent_module.ts b/editors/code/src/commands/parent_module.ts index 2bee80ee673f..9257b61be955 100644 --- a/editors/code/src/commands/parent_module.ts +++ b/editors/code/src/commands/parent_module.ts @@ -3,8 +3,8 @@ import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; -export function parentModule(ctx: Ctx): Cmd<[]> { - return async (): Promise => { +export function parentModule(ctx: Ctx): Cmd<[], Promise> { + return async () => { const editor = ctx.activeRustEditor; const client = ctx.client; if (!editor || !client) return; diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts index e9a7a754b0cc..166b568e00e6 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/commands/runnables.ts @@ -4,10 +4,10 @@ import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; -export function run(ctx: Ctx): Cmd<[]> { +export function run(ctx: Ctx): Cmd<[], Promise> { let prevRunnable: RunnableQuickPick | undefined; - return async (): Promise => { + return async () => { const editor = ctx.activeRustEditor; const client = ctx.client; if (!editor || !client) return; @@ -40,8 +40,8 @@ export function run(ctx: Ctx): Cmd<[]> { }; } -export function runSingle(ctx: Ctx): Cmd<[ra.Runnable]> { - return async (runnable: ra.Runnable): Promise => { +export function runSingle(ctx: Ctx): Cmd<[ra.Runnable], Promise> { + return async runnable => { const editor = ctx.activeRustEditor; if (!editor) return; @@ -57,8 +57,8 @@ export function runSingle(ctx: Ctx): Cmd<[ra.Runnable]> { }; } -export function debugSingle(ctx: Ctx): Cmd<[ra.Runnable]> { - return async (config: ra.Runnable): Promise => { +export function debugSingle(ctx: Ctx): Cmd<[ra.Runnable], Promise> { + return async config => { const editor = ctx.activeRustEditor; if (!editor) return; diff --git a/editors/code/src/commands/server_version.ts b/editors/code/src/commands/server_version.ts index 95aebe9c498e..7fd6b07c6e79 100644 --- a/editors/code/src/commands/server_version.ts +++ b/editors/code/src/commands/server_version.ts @@ -3,14 +3,16 @@ import { ensureServerBinary } from '../installation/server'; import { Ctx, Cmd } from '../ctx'; import { spawnSync } from 'child_process'; -export function serverVersion(ctx: Ctx): Cmd<[]> { - return async (): Promise => { +export function serverVersion(ctx: Ctx): Cmd<[], Promise> { + return async () => { const binaryPath = await ensureServerBinary(ctx.config, ctx.state); if (binaryPath == null) { throw new Error( - 'Rust Analyzer Language Server is not available. ' + + String.prototype.concat( + 'Rust Analyzer Language Server is not available. ', 'Please, ensure its [proper installation](https://rust-analyzer.github.io/manual.html#installation).', + ), ); } diff --git a/editors/code/src/commands/ssr.ts b/editors/code/src/commands/ssr.ts index 81418b6daea0..d33cc5aaeec3 100644 --- a/editors/code/src/commands/ssr.ts +++ b/editors/code/src/commands/ssr.ts @@ -4,8 +4,8 @@ import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; import { applySourceChange } from '../source_change'; -export function ssr(ctx: Ctx): Cmd<[]> { - return async (): Promise => { +export function ssr(ctx: Ctx): Cmd<[], Promise> { + return async () => { const client = ctx.client; if (!client) return; diff --git a/editors/code/src/commands/syntax_tree.ts b/editors/code/src/commands/syntax_tree.ts index d412ec3aec84..b13fbb92e32c 100644 --- a/editors/code/src/commands/syntax_tree.ts +++ b/editors/code/src/commands/syntax_tree.ts @@ -7,7 +7,7 @@ import { isRustDocument } from '../util'; // Opens the virtual file that will show the syntax tree // // The contents of the file come from the `TextDocumentContentProvider` -export function syntaxTree(ctx: Ctx): Cmd<[]> { +export function syntaxTree(ctx: Ctx): Cmd<[], Promise> { const tdcp = new TextDocumentContentProvider(ctx); ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp)); @@ -31,7 +31,7 @@ export function syntaxTree(ctx: Ctx): Cmd<[]> { ctx.subscriptions, ); - return async (): Promise => { + return async () => { const editor = vscode.window.activeTextEditor; const rangeEnabled = !!(editor && !editor.selection.isEmpty); diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 16b6974200fa..3e666b7453ac 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -49,7 +49,7 @@ export class Config { /** * Either `nightly` or `YYYY-MM-DD` (i.e. `stable` release) */ - readonly extensionReleaseTag: string = ((): string => { + readonly extensionReleaseTag: string = (() => { if (this.packageJsonVersion.endsWith(NIGHTLY_TAG)) return NIGHTLY_TAG; const realVersionRegexp = /^\d+\.\d+\.(\d{4})(\d{2})(\d{2})/; @@ -180,25 +180,26 @@ export class Config { // We don't do runtime config validation here for simplicity. More on stackoverflow: // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension - private get serverPath(): null | string { + /* eslint-disable @typescript-eslint/explicit-function-return-type */ + private get serverPath() { return this.cfg.get('serverPath') as null | string; } - get updatesChannel(): UpdatesChannel { + get updatesChannel() { return this.cfg.get('updates.channel') as UpdatesChannel; } - get askBeforeDownload(): boolean { + get askBeforeDownload() { return this.cfg.get('updates.askBeforeDownload') as boolean; } - get highlightingSemanticTokens(): boolean { + get highlightingSemanticTokens() { return this.cfg.get('highlighting.semanticTokens') as boolean; } - get highlightingOn(): boolean { + get highlightingOn() { return this.cfg.get('highlightingOn') as boolean; } - get rainbowHighlightingOn(): boolean { + get rainbowHighlightingOn() { return this.cfg.get('rainbowHighlightingOn') as boolean; } - get lruCapacity(): null | number { + get lruCapacity() { return this.cfg.get('lruCapacity') as null | number; } get inlayHints(): InlayHintOptions { @@ -208,19 +209,19 @@ export class Config { maxLength: this.cfg.get('inlayHints.maxLength') as null | number, }; } - get excludeGlobs(): string[] { + get excludeGlobs() { return this.cfg.get('excludeGlobs') as string[]; } - get useClientWatching(): boolean { + get useClientWatching() { return this.cfg.get('useClientWatching') as boolean; } - get featureFlags(): Record { + get featureFlags() { return this.cfg.get('featureFlags') as Record; } - get rustfmtArgs(): string[] { + get rustfmtArgs() { return this.cfg.get('rustfmtArgs') as string[]; } - get loadOutDirsFromCheck(): boolean { + get loadOutDirsFromCheck() { return this.cfg.get('loadOutDirsFromCheck') as boolean; } @@ -243,7 +244,8 @@ export class Config { } // for internal use - get withSysroot(): boolean { + get withSysroot() { return this.cfg.get('withSysroot', true) as boolean; } + /* eslint-enable @typescript-eslint/explicit-function-return-type */ } diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index a4b3ce3d3b88..5d6bb0169071 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -36,7 +36,7 @@ export class Ctx { return vscode.window.visibleTextEditors.filter(isRustEditor); } - registerCommand(name: string, factory: (ctx: Ctx) => Cmd): void { + registerCommand(name: string, factory: (ctx: Ctx) => Cmd): void { const fullName = `rust-analyzer.${name}`; const cmd = factory(this); const d = vscode.commands.registerCommand(fullName, cmd); @@ -60,4 +60,4 @@ export interface Disposable { dispose(): void; } -export type Cmd = (...args: T) => unknown; +export type Cmd = (...args: I) => O; diff --git a/editors/code/src/highlighting.ts b/editors/code/src/highlighting.ts index 2fd208954799..38fa2d66f1d8 100644 --- a/editors/code/src/highlighting.ts +++ b/editors/code/src/highlighting.ts @@ -215,7 +215,7 @@ const TAG_TO_SCOPES = new Map([ function randomU32Numbers(seed: number): () => number { let random = seed | 0; - return (): number => { + return () => { random ^= random << 13; random ^= random >> 17; random ^= random << 5; diff --git a/editors/code/src/installation/downloads.ts b/editors/code/src/installation/downloads.ts index c419df094e7b..6bebc3f02c9a 100644 --- a/editors/code/src/installation/downloads.ts +++ b/editors/code/src/installation/downloads.ts @@ -71,8 +71,10 @@ export async function downloadArtifactWithProgressUi( .catch(err => assert( err?.code === 'EEXIST', - `Couldn't create directory "${installationDir}" to download ` + + String.prototype.concat( + `Couldn't create directory "${installationDir}" to download `, `${artifactFileName} artifact: ${err?.message}`, + ), ), ); diff --git a/editors/code/src/installation/extension.ts b/editors/code/src/installation/extension.ts index 40499266417d..d2d4e4c2ec96 100644 --- a/editors/code/src/installation/extension.ts +++ b/editors/code/src/installation/extension.ts @@ -57,8 +57,10 @@ export async function ensureProperExtensionVersion( if (currentExtReleaseDate === null) { void vscode.window.showErrorMessage( - "Nightly release date must've been set during the installation. " + + String.prototype.concat( + "Nightly release date must've been set during the installation. ", 'Did you download and install the nightly .vsix package manually?', + ), ); throw new Error('Nightly release date was not set in globalStorage'); } @@ -95,9 +97,11 @@ export async function ensureProperExtensionVersion( if (releaseInfo.releaseDate.getTime() === currentExtReleaseDate.getTime()) { vscode.window.showInformationMessage( - 'Whoops, it appears that your nightly version is up-to-date. ' + - 'There might be some problems with the upcomming nightly release ' + + String.prototype.concat( + 'Whoops, it appears that your nightly version is up-to-date. ', + 'There might be some problems with the upcomming nightly release ', 'or you traveled too far into the future. Sorry for that 😅! ', + ), ); return false; } @@ -117,9 +121,11 @@ async function askToDownloadProperExtensionVersion(config: Config, reason = ''): // This behaviour is what we want, but likely it is not documented const userResponse = await vscode.window.showInformationMessage( - reason + - `Do you want to download the ${stableOrNightly} rust-analyzer extension ` + + String.prototype.concat( + reason, + `Do you want to download the ${stableOrNightly} rust-analyzer extension `, `version and reload the window now?`, + ), 'Download now', 'Cancel', ); @@ -137,7 +143,7 @@ const tryDownloadNightlyExtension = notReentrant( async ( config: Config, state: PersistentState, - shouldDownload: (releaseInfo: ArtifactReleaseInfo) => boolean = (): boolean => true, + shouldDownload: (releaseInfo: ArtifactReleaseInfo) => boolean = () => true, ): Promise => { const vsixSource = config.nightlyVsixSource; try { diff --git a/editors/code/src/installation/server.ts b/editors/code/src/installation/server.ts index ee9a4b50bb39..5520bcebce03 100644 --- a/editors/code/src/installation/server.ts +++ b/editors/code/src/installation/server.ts @@ -17,12 +17,14 @@ export async function ensureServerBinary( if (!source) { vscode.window.showErrorMessage( - "Unfortunately we don't ship binaries for your platform yet. " + - 'You need to manually clone rust-analyzer repository and ' + - 'run `cargo xtask install --server` to build the language server from sources. ' + - 'If you feel that your platform should be supported, please create an issue ' + - 'about that [here](https://github.com/rust-analyzer/rust-analyzer/issues) and we ' + + String.prototype.concat( + "Unfortunately we don't ship binaries for your platform yet.", + 'You need to manually clone rust-analyzer repository and ', + 'run `cargo xtask install --server` to build the language server from sources. ', + 'If you feel that your platform should be supported, please create an issue ', + 'about that [here](https://github.com/rust-analyzer/rust-analyzer/issues) and we ', 'will consider it.', + ), ); return null; } @@ -34,9 +36,11 @@ export async function ensureServerBinary( } vscode.window.showErrorMessage( - `Unable to run ${source.path} binary. ` + - `To use the pre-built language server, set "rust-analyzer.serverPath" ` + + String.prototype.concat( + `Unable to run ${source.path} binary. `, + `To use the pre-built language server, set "rust-analyzer.serverPath" `, 'value to `null` or remove it from the settings to use it by default.', + ), ); return null; } @@ -47,8 +51,10 @@ export async function ensureServerBinary( if (config.askBeforeDownload) { const userResponse = await vscode.window.showInformationMessage( - `Language server version ${source.tag} for rust-analyzer is not installed. ` + + String.prototype.concat( + `Language server version ${source.tag} for rust-analyzer is not installed. `, 'Do you want to download it now?', + ), 'Download now', 'Cancel', ); @@ -127,9 +133,11 @@ const downloadServer = notReentrant( assert( isBinaryAvailable(binaryPath), - `Downloaded language server binary is not functional.` + - `Downloaded from GitHub repo ${source.repo.owner}/${source.repo.name} ` + + String.prototype.concat( + `Downloaded language server binary is not functional.`, + `Downloaded from GitHub repo ${source.repo.owner}/${source.repo.name} `, `to ${binaryPath}`, + ), ); vscode.window.showInformationMessage( diff --git a/editors/code/src/rust-analyzer-api.ts b/editors/code/src/rust-analyzer-api.ts index d027cf7ba1fd..db57610c37f7 100644 --- a/editors/code/src/rust-analyzer-api.ts +++ b/editors/code/src/rust-analyzer-api.ts @@ -11,10 +11,10 @@ type FxHashMap = Record; function request( method: string, ): lc.RequestType { - return new lc.RequestType(`rust-analyzer/${method}`); + return new lc.RequestType(`rust-analyzer/${method}`); } function notification(method: string): lc.NotificationType { - return new lc.NotificationType(method); + return new lc.NotificationType(method); } export const analyzerStatus = request('analyzerStatus'); diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts index a7145344250d..21a2ca31b818 100644 --- a/editors/code/src/util.ts +++ b/editors/code/src/util.ts @@ -33,16 +33,20 @@ export const log = new (class { downloadError(err: Error, artifactName: string, repoName: string): void { vscode.window.showErrorMessage( - `Failed to download the rust-analyzer ${artifactName} from ${repoName} ` + + String.prototype.concat( + `Failed to download the rust-analyzer ${artifactName} from ${repoName} `, `GitHub repository: ${err.message}`, + ), ); log.error(err); dns.resolve('example.com').then( addrs => log.debug('DNS resolution for example.com was successful', addrs), err => log.error( - 'DNS resolution for example.com failed, ' + + String.prototype.concat( + 'DNS resolution for example.com failed, ', 'there might be an issue with Internet availability', + ), err, ), ); From c1a4caa888b9de9d5daa2510a6f0f46432421384 Mon Sep 17 00:00:00 2001 From: Darin Morrison Date: Wed, 18 Mar 2020 20:23:23 -0600 Subject: [PATCH 9/9] Fix instance of @typescript-eslint/no-misused-promises --- editors/code/src/inlay_hints.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts index d14595b2774a..eaef9c327708 100644 --- a/editors/code/src/inlay_hints.ts +++ b/editors/code/src/inlay_hints.ts @@ -113,19 +113,19 @@ class HintsUpdater implements Disposable { private syncCacheAndRenderHints(): void { // FIXME: make inlayHints request pass an array of files? - // eslint-disable-next-line @typescript-eslint/no-misused-promises - this.sourceFiles.forEach((file, uri) => - this.fetchHints(file).then(hints => { - if (!hints) return; + this.sourceFiles.forEach( + (file, uri) => + void this.fetchHints(file).then(hints => { + if (!hints) return; - file.cachedDecorations = this.hintsToDecorations(hints); + file.cachedDecorations = this.hintsToDecorations(hints); - for (const editor of this.ctx.visibleRustEditors) { - if (editor.document.uri.toString() === uri) { - this.renderDecorations(editor, file.cachedDecorations); + for (const editor of this.ctx.visibleRustEditors) { + if (editor.document.uri.toString() === uri) { + this.renderDecorations(editor, file.cachedDecorations); + } } - } - }), + }), ); }