pi-lsp-adapter 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +506 -0
- package/package.json +79 -0
- package/src/commands/registerCommands.ts +228 -0
- package/src/commands/status.ts +79 -0
- package/src/config/loadConfig.ts +377 -0
- package/src/config/paths.ts +58 -0
- package/src/config/trust.ts +85 -0
- package/src/detect/filetypes.ts +86 -0
- package/src/detect/root.ts +32 -0
- package/src/index.ts +132 -0
- package/src/install/installers.ts +513 -0
- package/src/install/lockfile.ts +159 -0
- package/src/install/manager.ts +177 -0
- package/src/install/version.ts +40 -0
- package/src/lsp/client.ts +465 -0
- package/src/lsp/processRegistry.ts +339 -0
- package/src/lsp/runtimeManager.ts +552 -0
- package/src/registry/builtin.ts +171 -0
- package/src/registry/schema.ts +185 -0
- package/src/resolve/languages.ts +96 -0
- package/src/resolve/resolveServer.ts +315 -0
- package/src/state.ts +20 -0
- package/src/statusLine.ts +21 -0
- package/src/tools/lspFormat.ts +594 -0
- package/src/tools/registerLspTools.ts +241 -0
- package/src/tools/registerLspWarmup.ts +25 -0
- package/src/tools/resultCache.ts +162 -0
- package/src/ui/lspPanel.ts +123 -0
- package/src/util/deepMerge.ts +38 -0
- package/src/util/errors.ts +22 -0
- package/src/util/hash.ts +10 -0
- package/src/util/helpers.ts +41 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import type { BuiltinCatalog, FiletypeRules } from "./schema.js";
|
|
2
|
+
|
|
3
|
+
export const BUILTIN_FILETYPE_RULES: Required<FiletypeRules> = {
|
|
4
|
+
exactFilenames: {},
|
|
5
|
+
extensions: {
|
|
6
|
+
".js": "javascript",
|
|
7
|
+
".jsx": "javascriptreact",
|
|
8
|
+
".ts": "typescript",
|
|
9
|
+
".tsx": "typescriptreact",
|
|
10
|
+
".py": "python",
|
|
11
|
+
".go": "go",
|
|
12
|
+
".rs": "rust",
|
|
13
|
+
".yaml": "yaml",
|
|
14
|
+
".yml": "yaml",
|
|
15
|
+
".json": "json",
|
|
16
|
+
".jsonc": "jsonc",
|
|
17
|
+
".java": "java",
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const BUILTIN_CATALOG: BuiltinCatalog = {
|
|
22
|
+
servers: {
|
|
23
|
+
vtsls: {
|
|
24
|
+
id: "vtsls",
|
|
25
|
+
displayName: "JavaScript/TypeScript Language Server (VTSLS)",
|
|
26
|
+
filetypes: ["javascript", "javascriptreact", "typescript", "typescriptreact"],
|
|
27
|
+
rootMarkers: [
|
|
28
|
+
"package.json",
|
|
29
|
+
"tsconfig.json",
|
|
30
|
+
"jsconfig.json",
|
|
31
|
+
"pnpm-workspace.yaml",
|
|
32
|
+
"bun.lock",
|
|
33
|
+
"bun.lockb",
|
|
34
|
+
"yarn.lock",
|
|
35
|
+
".git",
|
|
36
|
+
],
|
|
37
|
+
install: {
|
|
38
|
+
type: "npm",
|
|
39
|
+
packages: {
|
|
40
|
+
"@vtsls/language-server": "0.3.0",
|
|
41
|
+
typescript: "6.0.3",
|
|
42
|
+
},
|
|
43
|
+
bin: "vtsls",
|
|
44
|
+
},
|
|
45
|
+
command: ["{installBin}/vtsls", "--stdio"],
|
|
46
|
+
env: {},
|
|
47
|
+
settings: {},
|
|
48
|
+
initializationOptions: {},
|
|
49
|
+
lazy: true,
|
|
50
|
+
},
|
|
51
|
+
pyright: {
|
|
52
|
+
id: "pyright",
|
|
53
|
+
displayName: "Pyright",
|
|
54
|
+
filetypes: ["python"],
|
|
55
|
+
rootMarkers: ["pyproject.toml", "setup.py", "setup.cfg", "requirements.txt", "uv.lock", "poetry.lock", ".git"],
|
|
56
|
+
install: {
|
|
57
|
+
type: "npm",
|
|
58
|
+
packages: {
|
|
59
|
+
pyright: "1.1.410",
|
|
60
|
+
},
|
|
61
|
+
bin: "pyright-langserver",
|
|
62
|
+
},
|
|
63
|
+
command: ["{installBin}/pyright-langserver", "--stdio"],
|
|
64
|
+
env: {},
|
|
65
|
+
settings: {},
|
|
66
|
+
initializationOptions: {},
|
|
67
|
+
lazy: true,
|
|
68
|
+
},
|
|
69
|
+
gopls: {
|
|
70
|
+
id: "gopls",
|
|
71
|
+
displayName: "gopls",
|
|
72
|
+
filetypes: ["go"],
|
|
73
|
+
rootMarkers: ["go.work", "go.mod", ".git"],
|
|
74
|
+
install: {
|
|
75
|
+
type: "go",
|
|
76
|
+
module: "golang.org/x/tools/gopls",
|
|
77
|
+
version: "v0.22.0",
|
|
78
|
+
bin: "gopls",
|
|
79
|
+
},
|
|
80
|
+
command: ["{installBin}/gopls"],
|
|
81
|
+
env: {},
|
|
82
|
+
settings: {},
|
|
83
|
+
initializationOptions: {},
|
|
84
|
+
lazy: true,
|
|
85
|
+
},
|
|
86
|
+
"rust-analyzer": {
|
|
87
|
+
id: "rust-analyzer",
|
|
88
|
+
displayName: "rust-analyzer",
|
|
89
|
+
filetypes: ["rust"],
|
|
90
|
+
rootMarkers: ["Cargo.toml", "rust-project.json", ".git"],
|
|
91
|
+
install: {
|
|
92
|
+
type: "github",
|
|
93
|
+
repo: "rust-lang/rust-analyzer",
|
|
94
|
+
version: "2026-05-25",
|
|
95
|
+
asset: "rust-analyzer-{platform}.gz",
|
|
96
|
+
bin: "rust-analyzer",
|
|
97
|
+
},
|
|
98
|
+
command: ["{installBin}/rust-analyzer"],
|
|
99
|
+
env: {},
|
|
100
|
+
settings: {},
|
|
101
|
+
initializationOptions: {},
|
|
102
|
+
lazy: true,
|
|
103
|
+
},
|
|
104
|
+
yamlls: {
|
|
105
|
+
id: "yamlls",
|
|
106
|
+
displayName: "YAML Language Server",
|
|
107
|
+
filetypes: ["yaml"],
|
|
108
|
+
rootMarkers: [".yamlls.yaml", ".git"],
|
|
109
|
+
install: {
|
|
110
|
+
type: "npm",
|
|
111
|
+
packages: {
|
|
112
|
+
"yaml-language-server": "1.23.0",
|
|
113
|
+
},
|
|
114
|
+
bin: "yaml-language-server",
|
|
115
|
+
},
|
|
116
|
+
command: ["{installBin}/yaml-language-server", "--stdio"],
|
|
117
|
+
env: {},
|
|
118
|
+
settings: {},
|
|
119
|
+
initializationOptions: {},
|
|
120
|
+
lazy: true,
|
|
121
|
+
},
|
|
122
|
+
jsonls: {
|
|
123
|
+
id: "jsonls",
|
|
124
|
+
displayName: "JSON Language Server",
|
|
125
|
+
filetypes: ["json", "jsonc"],
|
|
126
|
+
rootMarkers: ["package.json", ".git"],
|
|
127
|
+
install: {
|
|
128
|
+
type: "npm",
|
|
129
|
+
packages: {
|
|
130
|
+
"vscode-langservers-extracted": "4.10.0",
|
|
131
|
+
},
|
|
132
|
+
bin: "vscode-json-language-server",
|
|
133
|
+
},
|
|
134
|
+
command: ["{installBin}/vscode-json-language-server", "--stdio"],
|
|
135
|
+
env: {},
|
|
136
|
+
settings: {},
|
|
137
|
+
initializationOptions: {},
|
|
138
|
+
lazy: true,
|
|
139
|
+
},
|
|
140
|
+
jdtls: {
|
|
141
|
+
id: "jdtls",
|
|
142
|
+
displayName: "Eclipse JDT LS",
|
|
143
|
+
filetypes: ["java"],
|
|
144
|
+
rootMarkers: ["pom.xml", "build.gradle", "build.gradle.kts", "settings.gradle", ".project", ".git"],
|
|
145
|
+
install: {
|
|
146
|
+
type: "github",
|
|
147
|
+
repo: "eclipse-jdtls/eclipse.jdt.ls",
|
|
148
|
+
version: "1.58.0",
|
|
149
|
+
asset: "jdt-language-server-1.58.0-202604151538.tar.gz",
|
|
150
|
+
downloadUrl: "https://download.eclipse.org/jdtls/milestones/{version}/{asset}",
|
|
151
|
+
bin: "jdtls",
|
|
152
|
+
},
|
|
153
|
+
command: [
|
|
154
|
+
"java",
|
|
155
|
+
"-Declipse.application=org.eclipse.jdt.ls.core.id1",
|
|
156
|
+
"-Dosgi.bundles.defaultStartLevel=4",
|
|
157
|
+
"-Declipse.product=org.eclipse.jdt.ls.core.product",
|
|
158
|
+
"-jar",
|
|
159
|
+
"{installDir}/plugins/org.eclipse.equinox.launcher_*.jar",
|
|
160
|
+
"-configuration",
|
|
161
|
+
"{installDir}/config_{platform}",
|
|
162
|
+
"-data",
|
|
163
|
+
"{workspaceDir}",
|
|
164
|
+
],
|
|
165
|
+
env: {},
|
|
166
|
+
settings: {},
|
|
167
|
+
initializationOptions: {},
|
|
168
|
+
lazy: true,
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
};
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { Value } from "typebox/value";
|
|
3
|
+
|
|
4
|
+
export type JsonPrimitive = string | number | boolean | null;
|
|
5
|
+
export type JsonValue = JsonPrimitive | JsonValue[] | { [key: string]: JsonValue };
|
|
6
|
+
export type JsonObject = { [key: string]: JsonValue };
|
|
7
|
+
|
|
8
|
+
export type InstallMode = "prompt" | "auto" | "off";
|
|
9
|
+
|
|
10
|
+
export const SUPPORTED_LANGUAGE_SERVER_IDS = [
|
|
11
|
+
"vtsls",
|
|
12
|
+
"pyright",
|
|
13
|
+
"gopls",
|
|
14
|
+
"rust-analyzer",
|
|
15
|
+
"yamlls",
|
|
16
|
+
"jsonls",
|
|
17
|
+
"jdtls",
|
|
18
|
+
] as const;
|
|
19
|
+
|
|
20
|
+
export type SupportedLanguageServerId = (typeof SUPPORTED_LANGUAGE_SERVER_IDS)[number];
|
|
21
|
+
|
|
22
|
+
export type InstallerType = "npm" | "go" | "github" | "system";
|
|
23
|
+
|
|
24
|
+
export interface BaseInstallSpec {
|
|
25
|
+
type: InstallerType;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface NpmInstallSpec extends BaseInstallSpec {
|
|
29
|
+
type: "npm";
|
|
30
|
+
packages: Record<string, string>;
|
|
31
|
+
bin: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface GoInstallSpec extends BaseInstallSpec {
|
|
35
|
+
type: "go";
|
|
36
|
+
module: string;
|
|
37
|
+
version?: string;
|
|
38
|
+
bin: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface GithubInstallSpec extends BaseInstallSpec {
|
|
42
|
+
type: "github";
|
|
43
|
+
repo: string;
|
|
44
|
+
version?: string;
|
|
45
|
+
asset?: string;
|
|
46
|
+
downloadUrl?: string;
|
|
47
|
+
bin: string;
|
|
48
|
+
stripComponents?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface SystemInstallSpec extends BaseInstallSpec {
|
|
52
|
+
type: "system";
|
|
53
|
+
bin?: string;
|
|
54
|
+
command?: string[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type InstallSpec = NpmInstallSpec | GoInstallSpec | GithubInstallSpec | SystemInstallSpec;
|
|
58
|
+
|
|
59
|
+
export interface ServerDefinition<TServerId extends string = string> {
|
|
60
|
+
id: TServerId;
|
|
61
|
+
displayName: string;
|
|
62
|
+
filetypes: string[];
|
|
63
|
+
rootMarkers: string[];
|
|
64
|
+
install: InstallSpec;
|
|
65
|
+
command: string[];
|
|
66
|
+
cwd?: string;
|
|
67
|
+
env?: Record<string, string>;
|
|
68
|
+
settings: JsonObject;
|
|
69
|
+
initializationOptions: JsonObject;
|
|
70
|
+
lazy: boolean;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface Catalog<TServerId extends string = string> {
|
|
74
|
+
servers: { [ServerId in TServerId]: ServerDefinition<ServerId> };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export type RuntimeCatalog = Catalog<string>;
|
|
78
|
+
export type BuiltinCatalog = Catalog<SupportedLanguageServerId>;
|
|
79
|
+
|
|
80
|
+
export interface FiletypeRules {
|
|
81
|
+
exactFilenames?: Record<string, string>;
|
|
82
|
+
extensions?: Record<string, string>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface LspConfig {
|
|
86
|
+
installMode?: InstallMode;
|
|
87
|
+
warmup?: boolean;
|
|
88
|
+
servers?: Record<string, Partial<ServerDefinition>>;
|
|
89
|
+
trustedProjects?: string[];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface InstalledServerMetadata {
|
|
93
|
+
installer: InstallerType;
|
|
94
|
+
requestedVersion?: string;
|
|
95
|
+
packages?: Record<string, string>;
|
|
96
|
+
resolvedCommand: string[];
|
|
97
|
+
packageDir?: string;
|
|
98
|
+
binDir?: string;
|
|
99
|
+
installedAt: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface ResolvedServerConfig {
|
|
103
|
+
server: ServerDefinition;
|
|
104
|
+
rootDir: string;
|
|
105
|
+
rootMarker?: string;
|
|
106
|
+
command: string[];
|
|
107
|
+
cwd: string;
|
|
108
|
+
env: Record<string, string>;
|
|
109
|
+
settings: JsonObject;
|
|
110
|
+
initializationOptions: JsonObject;
|
|
111
|
+
install?: InstalledServerMetadata;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export type ParseResult<T> = { ok: true; value: T } | { ok: false; errors: string[] };
|
|
115
|
+
|
|
116
|
+
const StringRecordSchema = Type.Record(Type.String(), Type.String());
|
|
117
|
+
const JsonObjectSchema = Type.Record(Type.String(), Type.Any());
|
|
118
|
+
const StringArraySchema = Type.Array(Type.String());
|
|
119
|
+
|
|
120
|
+
export const InstalledServerMetadataSchema = Type.Object({
|
|
121
|
+
installer: Type.String(),
|
|
122
|
+
requestedVersion: Type.Optional(Type.String()),
|
|
123
|
+
packages: Type.Optional(StringRecordSchema),
|
|
124
|
+
resolvedCommand: StringArraySchema,
|
|
125
|
+
packageDir: Type.Optional(Type.String()),
|
|
126
|
+
binDir: Type.Optional(Type.String()),
|
|
127
|
+
installedAt: Type.String(),
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
export const InstallSpecSchema = Type.Union([
|
|
131
|
+
Type.Object({
|
|
132
|
+
type: Type.Literal("npm"),
|
|
133
|
+
packages: StringRecordSchema,
|
|
134
|
+
bin: Type.String(),
|
|
135
|
+
}),
|
|
136
|
+
Type.Object({
|
|
137
|
+
type: Type.Literal("go"),
|
|
138
|
+
module: Type.String(),
|
|
139
|
+
version: Type.Optional(Type.String()),
|
|
140
|
+
bin: Type.String(),
|
|
141
|
+
}),
|
|
142
|
+
Type.Object({
|
|
143
|
+
type: Type.Literal("github"),
|
|
144
|
+
repo: Type.String(),
|
|
145
|
+
version: Type.Optional(Type.String()),
|
|
146
|
+
asset: Type.Optional(Type.String()),
|
|
147
|
+
downloadUrl: Type.Optional(Type.String()),
|
|
148
|
+
bin: Type.String(),
|
|
149
|
+
stripComponents: Type.Optional(Type.Number()),
|
|
150
|
+
}),
|
|
151
|
+
Type.Object({
|
|
152
|
+
type: Type.Literal("system"),
|
|
153
|
+
bin: Type.Optional(Type.String()),
|
|
154
|
+
command: Type.Optional(StringArraySchema),
|
|
155
|
+
}),
|
|
156
|
+
]);
|
|
157
|
+
|
|
158
|
+
export const ServerDefinitionSchema = Type.Object({
|
|
159
|
+
id: Type.String(),
|
|
160
|
+
displayName: Type.String(),
|
|
161
|
+
filetypes: StringArraySchema,
|
|
162
|
+
rootMarkers: StringArraySchema,
|
|
163
|
+
install: InstallSpecSchema,
|
|
164
|
+
command: StringArraySchema,
|
|
165
|
+
cwd: Type.Optional(Type.String()),
|
|
166
|
+
env: Type.Optional(StringRecordSchema),
|
|
167
|
+
settings: JsonObjectSchema,
|
|
168
|
+
initializationOptions: JsonObjectSchema,
|
|
169
|
+
lazy: Type.Boolean(),
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
export function parseServerDefinition(value: unknown): ParseResult<ServerDefinition> {
|
|
173
|
+
if (Value.Check(ServerDefinitionSchema, value)) {
|
|
174
|
+
return { ok: true, value: value as ServerDefinition };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return { ok: false, errors: formatSchemaErrors(ServerDefinitionSchema, value) };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function formatSchemaErrors(schema: unknown, value: unknown): string[] {
|
|
181
|
+
return [...Value.Errors(schema as never, value)].map((error) => {
|
|
182
|
+
const path = error.instancePath === "" ? "server" : `server${error.instancePath}`;
|
|
183
|
+
return `${path} ${error.message}`;
|
|
184
|
+
});
|
|
185
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { delimiter, join, resolve } from "node:path";
|
|
2
|
+
import { getWorkspacesDir } from "../config/paths.js";
|
|
3
|
+
import type { JsonObject, ServerDefinition } from "../registry/schema.js";
|
|
4
|
+
import { deepClone } from "../util/deepMerge.js";
|
|
5
|
+
import { hashPath } from "../util/hash.js";
|
|
6
|
+
import { isPythonServerId, pathExists } from "../util/helpers.js";
|
|
7
|
+
|
|
8
|
+
export interface LanguageDefaultsInput {
|
|
9
|
+
server: ServerDefinition;
|
|
10
|
+
rootDir: string;
|
|
11
|
+
env: Record<string, string>;
|
|
12
|
+
settings: JsonObject;
|
|
13
|
+
initializationOptions: JsonObject;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface LanguageDefaultsResult {
|
|
17
|
+
env: Record<string, string>;
|
|
18
|
+
settings: JsonObject;
|
|
19
|
+
initializationOptions: JsonObject;
|
|
20
|
+
workspaceDir?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function applyLanguageDefaults(input: LanguageDefaultsInput): Promise<LanguageDefaultsResult> {
|
|
24
|
+
const env = { ...input.env };
|
|
25
|
+
const settings = deepClone(input.settings);
|
|
26
|
+
const initializationOptions = deepClone(input.initializationOptions);
|
|
27
|
+
let workspaceDir: string | undefined;
|
|
28
|
+
|
|
29
|
+
if (isPythonServer(input.server)) {
|
|
30
|
+
await applyPythonDefaults(input.rootDir, env, settings);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (input.server.id === "jdtls") {
|
|
34
|
+
workspaceDir = join(getWorkspacesDir(), "jdtls", hashPath(input.rootDir));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return { env, settings, initializationOptions, workspaceDir };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function applyPythonDefaults(rootDir: string, env: Record<string, string>, settings: JsonObject): Promise<void> {
|
|
41
|
+
const venvDir = await selectPythonVirtualEnv(rootDir, env);
|
|
42
|
+
if (!venvDir) return;
|
|
43
|
+
|
|
44
|
+
const binDir = getVirtualEnvBinDir(venvDir);
|
|
45
|
+
env.PATH = prependPath(binDir, env.PATH ?? "");
|
|
46
|
+
|
|
47
|
+
if (!hasPythonInterpreterSetting(settings)) {
|
|
48
|
+
settings["python.defaultInterpreterPath"] = join(binDir, getPythonExecutableName());
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function selectPythonVirtualEnv(rootDir: string, env: Record<string, string>): Promise<string | undefined> {
|
|
53
|
+
if (env.VIRTUAL_ENV) {
|
|
54
|
+
return resolve(rootDir, env.VIRTUAL_ENV);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
for (const dirname of [".venv", "venv"]) {
|
|
58
|
+
const candidate = join(rootDir, dirname);
|
|
59
|
+
if (await pathExists(candidate)) {
|
|
60
|
+
return candidate;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function isPythonServer(server: ServerDefinition): boolean {
|
|
68
|
+
return isPythonServerId(server.id) || server.filetypes.includes("python");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function getVirtualEnvBinDir(venvDir: string): string {
|
|
72
|
+
return join(venvDir, process.platform === "win32" ? "Scripts" : "bin");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getPythonExecutableName(): string {
|
|
76
|
+
return process.platform === "win32" ? "python.exe" : "python";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function prependPath(path: string, currentPath: string): string {
|
|
80
|
+
if (!currentPath) return path;
|
|
81
|
+
return `${path}${delimiter}${currentPath}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function hasPythonInterpreterSetting(settings: JsonObject): boolean {
|
|
85
|
+
if (typeof settings["python.defaultInterpreterPath"] === "string") {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const python = settings.python;
|
|
90
|
+
return (
|
|
91
|
+
typeof python === "object" &&
|
|
92
|
+
python !== null &&
|
|
93
|
+
!Array.isArray(python) &&
|
|
94
|
+
typeof (python as Record<string, unknown>).defaultInterpreterPath === "string"
|
|
95
|
+
);
|
|
96
|
+
}
|