// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. import { ConfigurationChangeEvent, ConfigurationScope, WorkspaceConfiguration, WorkspaceFolder } from "vscode" import { getInterpreterDetails } from "./python" import { getConfiguration, getWorkspaceFolders } from "./vscodeapi" export interface ISettings { cwd: string workspace: string args: string[] path: string[] interpreter: string[] importStrategy: string showNotifications: string formatter: boolean inlayHint: boolean inlayHints: { parameterNames: "all" | "literals" | "none" suppressWhenArgumentMatchesName: boolean } } export function getExtensionSettings( namespace: string, includeInterpreter?: boolean ): Promise { return Promise.all( getWorkspaceFolders().map((w) => getWorkspaceSettings(namespace, w, includeInterpreter)) ) } function resolveVariables(value: string[], workspace?: WorkspaceFolder): string[] { const substitutions = new Map() const home = process.env.HOME || process.env.USERPROFILE if (home) { substitutions.set("${userHome}", home) } if (workspace) { substitutions.set("${workspaceFolder}", workspace.uri.fsPath) } substitutions.set("${cwd}", process.cwd()) getWorkspaceFolders().forEach((w) => { substitutions.set("${workspaceFolder:" + w.name + "}", w.uri.fsPath) }) return value.map((s) => { for (const [key, value] of substitutions) { s = s.replace(key, value) } return s }) } export function getInterpreterFromSetting(namespace: string, scope?: ConfigurationScope) { const config = getConfiguration(namespace, scope) return config.get("interpreter") } export async function getWorkspaceSettings( namespace: string, workspace: WorkspaceFolder, includeInterpreter?: boolean ): Promise { const config = getConfiguration(namespace, workspace.uri) let interpreter: string[] = [] if (includeInterpreter) { interpreter = getInterpreterFromSetting(namespace, workspace) ?? [] if (interpreter.length === 0) { interpreter = (await getInterpreterDetails(workspace.uri)).path ?? [] } } const workspaceSetting = { cwd: workspace.uri.fsPath, workspace: workspace.uri.toString(), args: resolveVariables(config.get(`args`) ?? [], workspace), path: resolveVariables(config.get(`path`) ?? [], workspace), interpreter: resolveVariables(interpreter, workspace), importStrategy: config.get(`importStrategy`) ?? "useBundled", showNotifications: config.get(`showNotifications`) ?? "off", formatter: config.get(`formatter`) ?? true, inlayHint: config.get(`inlayHint`) ?? true, inlayHints: { parameterNames: config.get<"all" | "literals" | "none">(`inlayHints.parameterNames`) ?? "all", suppressWhenArgumentMatchesName: config.get(`inlayHints.suppressWhenArgumentMatchesName`) ?? true } } return workspaceSetting } function getGlobalValue(config: WorkspaceConfiguration, key: string, defaultValue: T): T { const inspect = config.inspect(key) return inspect?.globalValue ?? inspect?.defaultValue ?? defaultValue } export async function getGlobalSettings( namespace: string, includeInterpreter?: boolean ): Promise { const config = getConfiguration(namespace) let interpreter: string[] = [] if (includeInterpreter) { interpreter = getGlobalValue(config, "interpreter", []) if (interpreter === undefined || interpreter.length === 0) { interpreter = (await getInterpreterDetails()).path ?? [] } } const setting = { cwd: process.cwd(), workspace: process.cwd(), args: getGlobalValue(config, "args", []), path: getGlobalValue(config, "path", []), interpreter: interpreter, importStrategy: getGlobalValue(config, "importStrategy", "useBundled"), showNotifications: getGlobalValue(config, "showNotifications", "off"), formatter: config.get(`formatter`) ?? true, inlayHint: config.get(`inlayHint`) ?? true, inlayHints: { parameterNames: config.get<"all" | "literals" | "none">(`inlayHints.parameterNames`) ?? "all", suppressWhenArgumentMatchesName: config.get(`inlayHints.suppressWhenArgumentMatchesName`) ?? true } } return setting } export function checkIfConfigurationChanged( e: ConfigurationChangeEvent, namespace: string ): boolean { const settings = [ `${namespace}.args`, `${namespace}.path`, `${namespace}.interpreter`, `${namespace}.importStrategy`, `${namespace}.showNotifications`, `${namespace}.formatter`, `${namespace}.inlayHint`, `${namespace}.inlayHints.parameterNames`, `${namespace}.inlayHints.suppressWhenArgumentMatchesName` ] const changed = settings.map((s) => e.affectsConfiguration(s)) return changed.includes(true) }