* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as vscode from 'vscode';
import * as cp from 'child_process';
import { resolveKeelsCommand } from './cjmpSdk';
import { getCjmpEmulatorsOutputChannel } from './cjmpOutputChannel';
export interface Emulator {
id: string;
name: string;
platform: string;
}
export async function LaunchEmulator(context: vscode.ExtensionContext): Promise<void> {
try {
const emulators = await listEmulators();
if (emulators.length === 0) {
vscode.window.showWarningMessage('No available simulators found.');
return;
}
const selected = await vscode.window.showQuickPick(
emulators.map(emu => ({
label: `${emu.name} (${emu.id}, ${emu.platform})`,
emulator: emu
})),
{ placeHolder: 'Select a simulator to launch.' }
);
if (!selected) {
return;
}
await launchSelectedEmulator(selected.emulator.id);
} catch (error) {
vscode.window.showErrorMessage(`Failed to start simulator: ${error}`);
}
}
export async function listEmulators(): Promise<Emulator[]> {
return new Promise((resolve, reject) => {
const keelsCommand = resolveKeelsCommand();
if (!keelsCommand) {
resolve([]);
return;
}
const outputChannel = getCjmpEmulatorsOutputChannel();
outputChannel.appendLine('');
outputChannel.appendLine('=== CJMP Emulators ===');
const command = `${keelsCommand.executablePath} emulators --list`;
outputChannel.appendLine(`> ${command}`);
let fullOutput = '';
const process = cp.spawn(command, [], {
shell: true,
env: keelsCommand.environment,
});
process.stdout.on('data', (data) => {
const output = data.toString();
outputChannel.append(output);
fullOutput += output;
});
process.stderr.on('data', (data) => {
const errorOutput = data.toString();
outputChannel.append(errorOutput);
fullOutput += errorOutput;
});
process.on('close', (code) => {
const parsed = parseEmulatorsOutput(fullOutput);
if (parsed.length > 0) {
resolve(parsed);
} else {
resolve([]);
}
});
});
}
export async function launchSelectedEmulator(emulatorId: string): Promise<void> {
const keelsCommand = resolveKeelsCommand();
if (!keelsCommand) {
return;
}
const command = `${keelsCommand.executablePath} emulators --launch ${emulatorId}`;
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
const terminal = vscode.window.createTerminal({
name: 'CJMP Emulators Terminal',
cwd: workspaceRoot,
env: keelsCommand.environment,
});
terminal.sendText(command);
terminal.show();
return Promise.resolve();
}
function parseEmulatorsOutput(output: string): Emulator[] {
const emulators: Emulator[] = [];
const lines = output.split('\n');
let foundTableStart = false;
for (const line of lines) {
const trimmedLine = line.trim();
if (!trimmedLine || trimmedLine.includes('To run an emulator')) {
continue;
}
if (trimmedLine.includes('---')) {
foundTableStart = true;
continue;
}
if (!foundTableStart) {
continue;
}
const parts = trimmedLine.split(/\s{2,}/).filter(part => part.trim());
if (parts.length >= 3) {
const id = parts[0].replace(/^(\\u2022|\u2022)\s*/, '').trim();
const name = parts[1].replace(/^(\\u2022|\u2022)\s*/, '').trim();
const platform = parts[2].replace(/^(\\u2022|\u2022)\s*/, '').trim();
emulators.push({
id: id,
name: name,
platform: platform
});
}
}
return emulators;
}