Files
openidea/src/features/tools/missing.ts
T
l0ng-ai e2f8e8d5bc fix(cpp): explain missing clang-tidy checks with Apple's clangd (#770)
Apple's clangd (/usr/bin/clangd, Xcode and CommandLineTools toolchains) is built without clang-tidy, so on a Mac without a managed clangd the checks from .clang-tidy never appear. When a clangd server for C, C++, Objective-C or Objective-C++ resolves to Apple's binary and the project has a .clang-tidy, show one warning per session with Install (managed LLVM clangd, which already takes precedence once installed) and Language Servers… actions. Fixes #692.
2026-11-02 11:14:27 +08:00

87 lines
3.3 KiB
TypeScript

/**
* "rust-analyzer is not installed — Install": when a language server reports
* `missing` and we know how to install it, offer a one-click install that
* restarts the server when done. Uses the same notification key as the
* generic code-insight notice so it replaces it.
*/
import { executeAction } from "@/platform/actions";
import { onIdeEvent } from "@/platform/ipc";
import { notifications } from "@/workbench/contributions";
import { installTool, refreshTools, SETTINGS_PAGE_ID, toolByName, useTools } from "./store";
import { tx } from "@/platform/i18n";
export const missingKey = (name: string) => `lsp-missing-${name}`;
export async function promptInstall(name: string, sticky = true): Promise<boolean> {
if (!useTools.getState().loaded) await refreshTools();
const tool = toolByName(name);
if (!tool || !tool.canInstall || tool.status !== "missing") return false;
// An installed alternative (typescript-language-server for vtsls) already serves these files.
const served = useTools
.getState()
.tools.some(
(t) =>
t.name !== name &&
t.kind === tool.kind &&
t.status !== "missing" &&
t.languages.some((l) => tool.languages.includes(l)),
);
if (tool.kind !== "formatter" && served) return false;
const key = missingKey(name);
const langs = tool.languages.length ? tool.languages.join(", ") : "these files";
notifications().notify({
group: "tools",
level: "warning",
title: tx`${tool.displayName} is not installed`,
body:
tool.kind === "formatter"
? tx`Reformat Code needs ${tool.displayName}. Install it via ${tool.installMethod}?`
: tx`Code insight for ${langs} needs ${tool.command}. Install it via ${tool.installMethod}?`,
key,
sticky,
actions: [
{ label: "Install", run: () => void installTool(name, { notificationKey: key }) },
{ label: "Language Servers…", run: () => void executeAction("file.settings", SETTINGS_PAGE_ID) },
],
});
return true;
}
export function installMissingServerPrompts(): () => void {
const prompted = new Set<string>();
return onIdeEvent("languageServer", (e) => {
if (e.status !== "missing" || prompted.has(e.name)) return;
prompted.add(e.name);
// Async on purpose: lands after the synchronous generic notice and replaces it.
void promptInstall(e.name).catch(() => {});
});
}
/** A system server that lacks a capability can be replaced by the managed tool. */
export function installServerWarningPrompts(): () => void {
const prompted = new Set<string>();
return onIdeEvent("languageServerWarning", (e) => {
const key = `lsp-warning-${e.name}-${e.installTool}`;
if (prompted.has(key)) return;
prompted.add(key);
void (async () => {
if (!useTools.getState().loaded) await refreshTools();
const tool = toolByName(e.installTool);
notifications().notify({
group: "lsp",
level: "warning",
title: e.name,
body: tx(e.message),
key,
sticky: true,
actions: [
...(tool?.canInstall
? [{ label: "Install", run: () => void installTool(e.installTool, { notificationKey: key }) }]
: []),
{ label: "Language Servers…", run: () => void executeAction("file.settings", SETTINGS_PAGE_ID) },
],
});
})();
});
}