dotfiles/vscode/.vscode/extensions/matangover.mypy-0.3.1/out/extension.js
Errol Sancaktar 5f8db31398 alacritty
2024-07-15 17:06:13 -06:00

754 lines
34 KiB
JavaScript

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.deactivate = exports.activate = void 0;
const vscode = require("vscode");
const path = require("path");
const crypto = require("crypto");
const child_process_promise_1 = require("child-process-promise");
const fs = require("fs");
const lookpath_1 = require("lookpath");
const untildify = require("untildify");
const shlex_1 = require("shlex");
const AsyncLock = require("async-lock");
const allSettled = require("promise.allsettled");
const mypy_1 = require("./mypy");
const diagnostics = new Map();
const outputChannel = vscode.window.createOutputChannel('Mypy');
let _context;
let lock = new AsyncLock();
let statusBarItem;
let activeChecks = 0;
let checkIndex = 1;
let activated = false;
let logFile;
function activate(context) {
return __awaiter(this, void 0, void 0, function* () {
activated = true;
_context = context;
context.subscriptions.push(outputChannel);
const extension = vscode.extensions.getExtension('matangover.mypy');
const currentVersion = extension === null || extension === void 0 ? void 0 : extension.packageJSON.version;
context.globalState.update('extensionVersion', currentVersion);
initDebugLog(context);
output(`Mypy extension activated, version ${currentVersion}`);
if ((extension === null || extension === void 0 ? void 0 : extension.extensionKind) === vscode.ExtensionKind.Workspace) {
output('Running remotely');
}
if (logFile) {
output(`Saving debug log to: ${logFile}`);
}
statusBarItem = vscode.window.createStatusBarItem();
context.subscriptions.push(statusBarItem);
statusBarItem.text = "$(gear~spin) mypy";
output('Registering listener for interpreter changed event');
const pythonExtensionAPI = yield getPythonExtensionAPI(undefined);
if (pythonExtensionAPI !== undefined) {
const handler = pythonExtensionAPI.environments.onDidChangeActiveEnvironmentPath(activeInterpreterChanged);
context.subscriptions.push(handler);
output('Listener registered');
}
context.subscriptions.push(vscode.workspace.onDidChangeWorkspaceFolders(workspaceFoldersChanged), vscode.workspace.onDidSaveTextDocument(documentSaved), vscode.workspace.onDidDeleteFiles(filesDeleted), vscode.workspace.onDidRenameFiles(filesRenamed), vscode.workspace.onDidCreateFiles(filesCreated), vscode.workspace.onDidChangeConfiguration(configurationChanged), vscode.commands.registerCommand("mypy.recheckWorkspace", recheckWorkspace), vscode.commands.registerCommand("mypy.restartAndRecheckWorkspace", restartAndRecheckWorkspace));
// This is used to show the custom commands only when the extension is active.
vscode.commands.executeCommand("setContext", "mypy.activated", true);
// Do _not_ await this call on purpose, so that extension activation finishes quickly. This is
// important because if VS Code is closed before the checks are done, deactivate will only be
// called if activate has already finished.
forEachFolder(vscode.workspace.workspaceFolders, folder => checkWorkspace(folder.uri));
output('Activation complete');
});
}
exports.activate = activate;
function initDebugLog(context) {
const mypyConfig = vscode.workspace.getConfiguration('mypy');
const debug = mypyConfig.get('debugLogging', false);
if (debug) {
try {
const storageDir = context.globalStorageUri.fsPath;
fs.mkdirSync(storageDir, { recursive: true });
logFile = path.join(storageDir, "mypy_extension.log");
}
catch (e) {
output(`Failed to create extension storage directory: ${e}`);
}
}
}
function deactivate() {
return __awaiter(this, void 0, void 0, function* () {
activated = false;
output(`Mypy extension deactivating, shutting down daemons...`);
yield forEachFolder(vscode.workspace.workspaceFolders, folder => stopDaemon(folder.uri));
output(`Mypy daemons stopped, extension deactivated`);
vscode.commands.executeCommand("setContext", "mypy.activated", false);
});
}
exports.deactivate = deactivate;
function workspaceFoldersChanged(e) {
return __awaiter(this, void 0, void 0, function* () {
const format = (folders) => folders.map(f => f.name).join(", ") || "none";
output(`Workspace folders changed. Added: ${format(e.added)}. Removed: ${format(e.removed)}.`);
yield forEachFolder(e.removed, (folder) => __awaiter(this, void 0, void 0, function* () {
var _a;
yield stopDaemon(folder.uri);
(_a = diagnostics.get(folder.uri)) === null || _a === void 0 ? void 0 : _a.dispose();
diagnostics.delete(folder.uri);
}));
yield forEachFolder(e.added, folder => checkWorkspace(folder.uri));
});
}
function forEachFolder(folders, func, ignoreErrors = true) {
return __awaiter(this, void 0, void 0, function* () {
if (folders === undefined) {
return;
}
// Run the function for each callback, and catch errors if any.
// Use allSettled instead of Promise.all to always await all Promises, even if one rejects.
const promises = folders.map(func);
const results = yield allSettled(promises);
const rejections = [];
for (const [index, result] of results.entries()) {
if (result.status === "rejected") {
const folder = folders[index];
const folderUri = folder instanceof vscode.Uri ? folder : folder.uri;
rejections.push({
folder: folderUri.fsPath,
error: result.reason
});
}
}
if (rejections.length > 0) {
if (ignoreErrors) {
const errorString = rejections.map(r => `${r.folder}: ${errorToString(r.error)}`).join("\n");
output("forEachFolder ignored errors in the following folders:\n" + errorString);
}
else {
throw rejections;
}
}
});
}
function errorToString(error) {
if (error instanceof Error && error.stack) {
return error.stack;
}
else {
return String(error);
}
}
function stopDaemon(folder, retry = true) {
return __awaiter(this, void 0, void 0, function* () {
output(`Stop daemon: ${folder.fsPath}`);
const result = yield runDmypy(folder, 'stop');
if (result.success) {
output(`Stopped daemon: ${folder.fsPath}`);
}
else {
if (retry) {
// Daemon stopping can fail with 'Status file not found' if the daemon has been started
// very recently and hasn't written the status file yet. In that case, retry, otherwise
// we might leave a zombie daemon running. This happened due to the following events:
// 1. Open folder in VS Code, and then add another workspace folder
// 2. VS Code fires onDidChangeWorkspaceFolders and onDidChangeConfiguration, which
// causes us to queue two checks. (This is probably a bug in VS Code.)
// 3. VS Code immediately restarts the Extension Host process, which causes our
// extension to deactivate.
// 4. We try to stop the daemon but it is not yet running. We then start the daemon
// because of the queued check(s), which results in a zombie daemon.
// This simple retry solves the issue.
output(`Daemon stopping failed, retrying in 1 second: ${folder.fsPath}`);
yield sleep(1000);
yield stopDaemon(folder, false);
}
else {
output(`Daemon stopping failed again, giving up: ${folder.fsPath}`);
}
}
});
}
function runDmypy(folder, dmypyCommand, mypyArgs = [], warnIfFailed = false, successfulExitCodes, addPythonExecutableArgument = false, currentCheck, retryIfDaemonStuck = true) {
return __awaiter(this, void 0, void 0, function* () {
let dmypyGlobalArgs = [];
let dmypyCommandArgs = [];
let statusFilePath = null;
// Store the dmypy status file in the extension's workspace storage folder, instead of the
// default location which is .dmypy.json in the cwd.
if ((_context === null || _context === void 0 ? void 0 : _context.storageUri) !== undefined) {
fs.mkdirSync(_context.storageUri.fsPath, { recursive: true });
const folderHash = crypto.createHash('sha1').update(folder.toString()).digest('hex');
const statusFileName = `dmypy-${folderHash}-${process.pid}.json`;
statusFilePath = path.join(_context.storageUri.fsPath, statusFileName);
dmypyGlobalArgs = ["--status-file", statusFilePath];
const commandsSupportingLog = ["start", "restart", "run"];
if (commandsSupportingLog.includes(dmypyCommand)) {
const logFileName = `dmypy-${folderHash}.log`;
const logFilePath = path.join(_context.storageUri.fsPath, logFileName);
dmypyCommandArgs = ['--log-file', logFilePath];
}
}
const activeInterpreter = yield getActiveInterpreter(folder, currentCheck);
const mypyConfig = vscode.workspace.getConfiguration('mypy', folder);
let executable;
const runUsingActiveInterpreter = mypyConfig.get('runUsingActiveInterpreter');
let executionArgs = [];
if (runUsingActiveInterpreter) {
executable = activeInterpreter;
executionArgs = ["-m", "mypy.dmypy"];
if (executable === undefined) {
warn("Could not run mypy: no active interpreter. Please activate an interpreter in the " +
"Python extension or switch off the mypy.runUsingActiveInterpreter setting.", warnIfFailed, currentCheck);
}
}
else {
executable = yield getDmypyExecutable(folder, warnIfFailed, currentCheck);
}
if (executable === undefined) {
return { success: false, stdout: null };
}
if (addPythonExecutableArgument && activeInterpreter) {
mypyArgs = ['--python-executable', activeInterpreter, ...mypyArgs];
}
const args = [...executionArgs, ...dmypyGlobalArgs, dmypyCommand, ...dmypyCommandArgs];
if (mypyArgs.length > 0) {
args.push("--", ...mypyArgs);
}
const command = [executable, ...args].map(shlex_1.quote).join(" ");
output(`Running dmypy in folder ${folder.fsPath}\n${command}`, currentCheck);
try {
const result = yield child_process_promise_1.spawn(executable, args, {
cwd: folder.fsPath,
capture: ['stdout', 'stderr'],
successfulExitCodes
});
if (result.code == 1 && result.stderr) {
// This might happen when running using `python -m mypy.dmypy` and some error in the
// interpreter occurs, such as import error when mypy is not installed.
let error = '';
if (runUsingActiveInterpreter && result.stderr.includes('ModuleNotFoundError')) {
error = 'Probably mypy is not installed in the active interpreter ' +
`(${activeInterpreter}). Either install mypy in this interpreter or switch ` +
'off the mypy.runUsingActiveInterpreter setting. ';
}
warn(`Error running mypy in ${folder.fsPath}. ${error}See Output panel for details.`, warnIfFailed, currentCheck, true);
if (result.stdout) {
output(`stdout:\n${result.stdout}`, currentCheck);
}
output(`stderr:\n${result.stderr}`, currentCheck);
return { success: false, stdout: result.stdout };
}
return { success: true, stdout: result.stdout };
}
catch (exception) {
let error = exception.toString();
let showDetailsButton = false;
if (exception.name === 'ChildProcessError') {
const ex = exception;
if (ex.code !== undefined) {
let errorString;
if (ex.stderr) {
// Show only first line of error to user because Newlines are stripped in VSCode
// warning messages and it can appear confusing.
let mypyError = ex.stderr.split("\n")[0];
if (mypyError.length > 300) {
mypyError = mypyError.slice(0, 300) + " [...]";
}
errorString = `error: "${mypyError}"`;
}
else {
errorString = `exit code ${ex.code}`;
}
error = `mypy failed with ${errorString}. See Output panel for details.`;
showDetailsButton = true;
}
if (ex.stdout) {
if (ex.code == 2 && !ex.stderr) {
// Mypy considers syntax errors as fatal errors (exit code 2). The daemon's
// exit code is inconsistent in this case (e.g. for syntax errors it can return
// either 1 or 2).
return { success: true, stdout: ex.stdout };
}
output(`stdout:\n${ex.stdout}`, currentCheck);
}
if (ex.stderr) {
output(`stderr:\n${ex.stderr}`, currentCheck);
if (ex.stderr.indexOf('Daemon crashed!') != -1) {
error = 'the mypy daemon crashed. This is probably a bug in mypy itself, ' +
'see Output panel for details. The daemon will be restarted automatically.';
showDetailsButton = true;
}
else if (ex.stderr.indexOf('There are no .py[i] files in directory') != -1) {
// Swallow this error. This may happen if one workspace folder contains
// Python files and another folder doesn't, or if a workspace contains Python
// files that are not reachable from the target directory.
return { success: true, stdout: '' };
}
else if (ex.stderr.indexOf('Connection refused') != -1 ||
ex.stderr.indexOf('[Errno 2] No such file') != -1 ||
ex.stderr.indexOf('Socket operation on non-socket') != -1) {
// This can happen if the daemon is stuck, or if the status file is stale due to
// e.g. a previous daemon that hasn't been stopped properly. See:
// https://github.com/matangover/mypy-vscode/issues/37
// https://github.com/matangover/mypy-vscode/issues/45
// To reproduce the above exceptions:
// 1. 'Connection refused': kill daemon process (so that it stops listening on
// the socket), and change the pid in status file to any running process.
// 2. 'No such file': change connection_name in status file to a non-existent
// file.
// 3. 'Socket operation on non-socket': change connection_name in status file
// to an existing file which is not a socket
if (retryIfDaemonStuck) {
// Kill the daemon.
output("Daemon is stuck or status file is stale. Killing daemon", currentCheck);
yield killDaemon(folder, currentCheck, statusFilePath);
// Run the same command again, but this time don't retry if it fails.
yield sleep(1000);
output("Retrying command", currentCheck);
return yield runDmypy(folder, dmypyCommand, mypyArgs, warnIfFailed, successfulExitCodes, addPythonExecutableArgument, currentCheck, false);
}
else {
error = 'the mypy daemon is stuck. An attempt to kill it and retry failed. ' +
'This is probably a bug in mypy itself, see Output panel for details.';
showDetailsButton = true;
}
}
}
}
warn(`Error running mypy in ${folder.fsPath}: ${error}`, warnIfFailed, currentCheck, showDetailsButton);
return { success: false, stdout: null };
}
});
}
function killDaemon(folder, currentCheck, statusFilePath) {
return __awaiter(this, void 0, void 0, function* () {
const killResult = yield runDmypy(folder, "kill", undefined, undefined, undefined, undefined, currentCheck, false);
output(`Ran dmypy kill, stdout: ${killResult.stdout}`, currentCheck);
if (killResult.success) {
output("Daemon killed successfully", currentCheck);
return;
}
output("Error killing daemon, attempt to delete status file", currentCheck);
if (statusFilePath) {
try {
fs.unlinkSync(statusFilePath);
}
catch (e) {
output(`Error deleting status file: ${errorToString(e)}`, currentCheck);
}
}
else {
output("No status file to delete", currentCheck);
}
});
}
function recheckWorkspace() {
return __awaiter(this, void 0, void 0, function* () {
output("Rechecking workspace");
yield forEachFolder(vscode.workspace.workspaceFolders, folder => checkWorkspace(folder.uri));
output("Recheck complete");
});
}
function restartAndRecheckWorkspace() {
return __awaiter(this, void 0, void 0, function* () {
output("Stopping daemons");
yield forEachFolder(vscode.workspace.workspaceFolders, folder => stopDaemon(folder.uri));
yield recheckWorkspace();
});
}
function getDmypyExecutable(folder, warnIfFailed, currentCheck) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const mypyConfig = vscode.workspace.getConfiguration('mypy', folder);
let dmypyExecutable = (_a = mypyConfig.get('dmypyExecutable')) !== null && _a !== void 0 ? _a : 'dmypy';
let helpURL = "https://github.com/matangover/mypy-vscode#installing-mypy";
const isCommand = path.parse(dmypyExecutable).dir === '';
if (isCommand) {
const executable = yield lookpath_1.lookpath(dmypyExecutable);
if (executable === undefined) {
warn(`The mypy daemon executable ('${dmypyExecutable}') was not found on your PATH. ` +
`Please install mypy or adjust the mypy.dmypyExecutable setting.`, warnIfFailed, currentCheck, undefined, helpURL);
return undefined;
}
dmypyExecutable = executable;
}
else {
dmypyExecutable = untildify(dmypyExecutable).replace('${workspaceFolder}', folder.fsPath);
if (!fs.existsSync(dmypyExecutable)) {
warn(`The mypy daemon executable ('${dmypyExecutable}') was not found. ` +
`Please install mypy or adjust the mypy.dmypyExecutable setting.`, warnIfFailed, currentCheck, undefined, helpURL);
return undefined;
}
}
return dmypyExecutable;
});
}
function documentSaved(document) {
const folder = vscode.workspace.getWorkspaceFolder(document.uri);
if (!folder) {
return;
}
if (document.languageId == "python" || isMaybeConfigFile(folder, document.fileName)) {
output(`Document saved: ${document.uri.fsPath}`);
checkWorkspace(folder.uri);
}
}
function isMaybeConfigFile(folder, file) {
if (isConfigFileName(file)) {
return true;
}
let configFile = vscode.workspace.getConfiguration("mypy", folder).get("configFile");
if (configFile === undefined) {
return false;
}
if (!path.isAbsolute(configFile)) {
configFile = path.join(folder.uri.fsPath, configFile);
}
return path.normalize(configFile) == path.normalize(file);
}
function isConfigFileName(file) {
const name = path.basename(file);
return name == "mypy.ini" || name == ".mypy.ini" || name == "setup.cfg" || name == "config";
}
function configurationChanged(event) {
var _a;
const folders = (_a = vscode.workspace.workspaceFolders) !== null && _a !== void 0 ? _a : [];
const affectedFolders = folders.filter(folder => event.affectsConfiguration("mypy", folder));
if (affectedFolders.length === 0) {
return;
}
const affectedFoldersString = affectedFolders.map(f => f.uri.fsPath).join(", ");
output(`Mypy settings changed: ${affectedFoldersString}`);
forEachFolder(affectedFolders, folder => checkWorkspace(folder.uri));
}
function checkWorkspace(folder) {
return __awaiter(this, void 0, void 0, function* () {
// Don't check the same workspace folder more than once at the same time.
yield lock.acquire(folder.fsPath, () => checkWorkspaceInternal(folder));
});
}
function checkWorkspaceInternal(folder) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
if (!activated) {
// This can happen if a check was queued right before the extension was deactivated.
// We don't want to check in that case since it would cause a zombie daemon.
output(`Extension is not activated, not checking: ${folder.fsPath}`);
return;
}
const mypyConfig = vscode.workspace.getConfiguration("mypy", folder);
if (!mypyConfig.get("enabled", true)) {
output(`Mypy disabled for folder: ${folder.fsPath}`);
const folderDiagnostics = diagnostics.get(folder);
if (folderDiagnostics) {
folderDiagnostics.clear();
}
return;
}
statusBarItem.show();
activeChecks++;
const currentCheck = checkIndex;
checkIndex++;
output(`Check folder: ${folder.fsPath}`, currentCheck);
let targets = mypyConfig.get("targets", []);
const mypyArgs = [...targets, '--show-error-end', '--no-error-summary', '--no-pretty', '--no-color-output'];
const configFile = mypyConfig.get("configFile");
if (configFile) {
output(`Using config file: ${configFile}`, currentCheck);
mypyArgs.push('--config-file', configFile);
}
const extraArguments = mypyConfig.get("extraArguments");
if (extraArguments !== undefined && extraArguments.length > 0) {
output(`Using extra arguments: ${extraArguments}`, currentCheck);
mypyArgs.push(...extraArguments);
}
const result = yield runDmypy(folder, 'run', mypyArgs, true, [0, 1], true, currentCheck);
activeChecks--;
if (activeChecks == 0) {
statusBarItem.hide();
}
if (result.stdout !== null) {
output(`Mypy output:\n${(_a = result.stdout) !== null && _a !== void 0 ? _a : "\n"}`, currentCheck);
}
const folderDiagnostics = getWorkspaceDiagnostics(folder);
folderDiagnostics.clear();
if (result.success && result.stdout) {
const fileDiagnostics = parseMypyOutput(result.stdout, folder);
folderDiagnostics.set(Array.from(fileDiagnostics.entries()));
}
});
}
function parseMypyOutput(stdout, folder) {
const outputLines = [];
stdout.split(/\r?\n/).forEach(line => {
const match = mypy_1.mypyOutputPattern.exec(line);
if (match !== null) {
const line = match.groups;
const previousLine = outputLines[outputLines.length - 1];
if (previousLine && line.type == "note" && previousLine.type == "note" && line.location == previousLine.location) {
// This line continues the note on the previous line, merge them.
previousLine.message += "\n" + line.message;
}
else {
outputLines.push(line);
}
}
});
let fileDiagnostics = new Map();
for (const line of outputLines) {
const diagnostic = createDiagnostic(line);
const fileUri = getFileUri(line.file, folder);
if (!fileDiagnostics.has(fileUri)) {
fileDiagnostics.set(fileUri, []);
}
const thisFileDiagnostics = fileDiagnostics.get(fileUri);
thisFileDiagnostics.push(diagnostic);
}
return fileDiagnostics;
}
function getLinkUrl(line) {
if (line.type == "note") {
const seeLines = line.message.split(/\r?\n/).filter(l => l.startsWith("See https://"));
if (seeLines.length > 0) {
return seeLines[0].slice(4);
}
}
else {
if (line.code) {
return `https://mypy.readthedocs.io/en/stable/_refs.html#code-${line.code}`;
}
}
return undefined;
}
function getFileUri(filePath, folder) {
// By default mypy outputs paths relative to the checked folder. If the user specifies
// `show_absolute_path = True` in the config file, mypy outputs absolute paths.
if (!path.isAbsolute(filePath)) {
filePath = path.join(folder.fsPath, filePath);
}
const fileUri = vscode.Uri.file(filePath);
return fileUri;
}
function createDiagnostic(line) {
var _a;
// Mypy output is 1-based, VS Code is 0-based.
const lineNo = parseInt(line.line) - 1;
let column = 0;
if (line.column !== undefined) {
column = parseInt(line.column) - 1;
}
let endLineNo = lineNo;
let endColumn = column;
if (line.endLine !== undefined && line.endColumn !== undefined) {
endLineNo = parseInt(line.endLine) - 1;
// Mypy's endColumn is inclusive, VS Code's is exclusive.
endColumn = parseInt(line.endColumn);
if (lineNo == endLineNo && column == endColumn - 1) {
// Mypy gave a zero-length range, give a zero-length range for VS Code as well, so that
// the error squiggle marks the entire word at that position.
endColumn = column;
}
}
const range = new vscode.Range(lineNo, column, endLineNo, endColumn);
const diagnostic = new vscode.Diagnostic(range, line.message, line.type === "error"
? vscode.DiagnosticSeverity.Error
: vscode.DiagnosticSeverity.Information);
diagnostic.source = "mypy";
const errorCode = (_a = line.code) !== null && _a !== void 0 ? _a : "note";
const url = getLinkUrl(line);
if (url === undefined) {
diagnostic.code = errorCode;
}
else {
diagnostic.code = {
value: errorCode,
target: vscode.Uri.parse(url),
};
}
return diagnostic;
}
function getWorkspaceDiagnostics(folder) {
let workspaceDiagnostics = diagnostics.get(folder);
if (workspaceDiagnostics) {
return workspaceDiagnostics;
}
else {
const workspaceDiagnostics = vscode.languages.createDiagnosticCollection('mypy');
diagnostics.set(folder, workspaceDiagnostics);
_context.subscriptions.push(workspaceDiagnostics);
return workspaceDiagnostics;
}
}
function getActiveInterpreter(folder, currentCheck) {
return __awaiter(this, void 0, void 0, function* () {
const path = yield getPythonPathFromPythonExtension(folder, currentCheck);
if (path === undefined) {
return undefined;
}
if (!fs.existsSync(path)) {
warn(`The selected Python interpreter does not exist: ${path}`, false, currentCheck);
return undefined;
}
return path;
});
}
// The VS Code Python extension manages its own internal Python interpreter configuration. This
// function was originally taken from pyright but modified to work with the new environments API:
// https://github.com/microsoft/vscode-python/wiki/Python-Environment-APIs
function getPythonPathFromPythonExtension(scopeUri, currentCheck) {
return __awaiter(this, void 0, void 0, function* () {
try {
const api = yield getPythonExtensionAPI(currentCheck);
if (api === undefined) {
return;
}
const environmentPath = api.environments.getActiveEnvironmentPath(scopeUri);
const environment = yield api.environments.resolveEnvironment(environmentPath);
if (environment === undefined) {
output('Invalid Python environment returned by Python extension', currentCheck);
return;
}
if (environment.executable.uri === undefined) {
output('Invalid Python executable path returned by Python extension', currentCheck);
return;
}
const result = environment.executable.uri.fsPath;
output(`Received Python path from Python extension: ${result}`, currentCheck);
return result;
}
catch (error) {
output(`Exception when reading Python path from Python extension: ${errorToString(error)}`, currentCheck);
}
return undefined;
});
}
function activeInterpreterChanged(e) {
var _a;
const resource = e.resource;
if (resource === undefined) {
output(`Active interpreter changed for resource: unknown`);
(_a = vscode.workspace.workspaceFolders) === null || _a === void 0 ? void 0 : _a.map(folder => checkWorkspace(folder.uri));
}
else {
output(`Active interpreter changed for resource: ${resource.uri.fsPath}`);
checkWorkspace(resource.uri);
}
}
function getPythonExtensionAPI(currentCheck) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const extension = vscode.extensions.getExtension('ms-python.python');
if (!extension) {
output('Python extension not found', currentCheck);
return undefined;
}
if (!extension.isActive) {
output('Waiting for Python extension to load', currentCheck);
yield extension.activate();
output('Python extension loaded', currentCheck);
}
const environmentsAPI = (_a = extension.exports) === null || _a === void 0 ? void 0 : _a.environments;
if (!environmentsAPI) {
output('Python extension version is too old (it does not expose the environments API). ' +
'Please upgrade the Python extension to the latest version.', currentCheck);
return undefined;
}
return extension.exports;
});
}
function warn(warning, show = false, currentCheck, detailsButton = false, helpURL) {
return __awaiter(this, void 0, void 0, function* () {
output(warning, currentCheck);
if (show) {
const items = [];
if (detailsButton) {
items.push("Details");
}
if (helpURL) {
items.push("Help");
}
const result = yield vscode.window.showWarningMessage(warning, ...items);
if (result === "Details") {
outputChannel.show();
}
else if (result === "Help") {
vscode.env.openExternal(vscode.Uri.parse(helpURL));
}
}
});
}
function filesDeleted(e) {
return __awaiter(this, void 0, void 0, function* () {
yield filesChanged(e.files);
});
}
function filesRenamed(e) {
return __awaiter(this, void 0, void 0, function* () {
const changedUris = e.files.map(f => f.oldUri).concat(...e.files.map(f => f.newUri));
yield filesChanged(changedUris);
});
}
function filesCreated(e) {
return __awaiter(this, void 0, void 0, function* () {
yield filesChanged(e.files, true);
});
}
function filesChanged(files, created = false) {
return __awaiter(this, void 0, void 0, function* () {
const folders = new Set();
for (let file of files) {
const folder = vscode.workspace.getWorkspaceFolder(file);
if (folder === undefined)
continue;
const path = file.fsPath;
if (path.endsWith(".py") || path.endsWith(".pyi")) {
folders.add(folder.uri);
}
else if (isMaybeConfigFile(folder, path)) {
// Don't trigger mypy run if config file has just been created and is empty, because
// mypy would error. Give the user a chance to edit the file.
const justCreatedAndEmpty = created && fs.statSync(path).size === 0;
if (!justCreatedAndEmpty) {
folders.add(folder.uri);
}
}
}
if (folders.size === 0) {
return;
}
const foldersString = Array.from(folders).map(f => f.fsPath).join(", ");
output(`Files changed in folders: ${foldersString}`);
yield forEachFolder(Array.from(folders), folder => checkWorkspace(folder));
});
}
function output(line, currentCheck) {
if (currentCheck !== undefined) {
line = `[${currentCheck}] ${line}`;
}
if (logFile) {
try {
var tzoffset = (new Date()).getTimezoneOffset() * 60000;
var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0, -1);
fs.appendFileSync(logFile, `${localISOTime} [${process.pid}] ${line}\n`);
}
catch (e) {
// Ignore
}
}
try {
outputChannel.appendLine(line);
}
catch (e) {
// Ignore error. This can happen when VS Code is closing and it calls our deactivate
// function, and the output channel is already closed.
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
//# sourceMappingURL=extension.js.map