mirror of
https://github.com/omltcat/dcs-lua-runner.git
synced 2025-11-10 15:49:49 +00:00
277 lines
13 KiB
TypeScript
277 lines
13 KiB
TypeScript
import * as vscode from 'vscode';
|
|
import axios from 'axios';
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
|
|
async function runLua(lua: string, outputChannel: vscode.OutputChannel, filename: string = 'none') {
|
|
const lua_base64 = Buffer.from(lua).toString('base64');
|
|
const config = vscode.workspace.getConfiguration('dcsLuaRunner');
|
|
const returnDisplay = config.get('returnDisplay') === 'Output Panel (Scrolling Plain Text)' ? 'output' : 'file' as string;
|
|
const returnDisplayFormat = config.get('returnDisplayFormat') === 'JSON' ? 'json' : 'lua' as string;
|
|
const runCodeLocally = config.get('runCodeLocally') as boolean;
|
|
const runInMissionEnv = config.get('runInMissionEnv') as boolean;
|
|
const serverAddressMission = runCodeLocally ? '127.0.0.1' : config.get('serverAddress') as string;
|
|
const serverAddressGUI = (runCodeLocally || !config.get('serverAddressGUI')) ? serverAddressMission : config.get('serverAddressGUI') as string;
|
|
const serverAddress = runInMissionEnv ? serverAddressMission : serverAddressGUI;
|
|
const serverPortMission = runCodeLocally ? 12080 : config.get('serverPort') as number
|
|
const serverPortGUI = (runCodeLocally || !config.get('serverPortGUI')) ? (serverPortMission + 1) : config.get('serverPortGUI') as number;
|
|
const serverPort = runInMissionEnv ? serverPortMission : serverPortGUI;
|
|
const useHttps = runCodeLocally ? false : config.get('useHttps') as boolean;
|
|
const authUsername = config.get('webAuthUsername') as string;
|
|
const authPassword = config.get('webAuthPassword') as string;
|
|
const protocol = useHttps ? 'https' : 'http';
|
|
const envName = runInMissionEnv ? 'Mission' : 'GUI';
|
|
|
|
const logInfo = `${envName}@${serverAddress}:${serverPort} <- ${filename}`
|
|
|
|
const displayOutput = async (output: Object) => {
|
|
if (returnDisplay === 'output') {
|
|
outputChannel.show(true);
|
|
outputChannel.appendLine(`[DCS] ${new Date().toLocaleString()} (${logInfo}):\n${format(JSON.stringify(output, null, 4))}`);
|
|
} else if (returnDisplay === 'file') {
|
|
const activeEditor = vscode.window.activeTextEditor;
|
|
const workspaceFolder = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0].uri.fsPath : '';
|
|
const vscodeFolderPath = `${workspaceFolder}/.vscode`;
|
|
const filePath = `${vscodeFolderPath}/dcs_lua_output.${returnDisplayFormat}`;
|
|
|
|
// Create the .vscode directory if it doesn't exist
|
|
if (!fs.existsSync(vscodeFolderPath)) {
|
|
fs.mkdirSync(vscodeFolderPath);
|
|
}
|
|
// Create the file if it doesn't exist
|
|
if (!fs.existsSync(filePath)) {
|
|
fs.writeFileSync(filePath, '');
|
|
}
|
|
|
|
const document = await vscode.workspace.openTextDocument(vscode.Uri.file(filePath));
|
|
const viewColumn = vscode.window.activeTextEditor && vscode.window.activeTextEditor.viewColumn === vscode.ViewColumn.Two ? vscode.ViewColumn.Two : vscode.ViewColumn.Beside;
|
|
const editor = await vscode.window.showTextDocument(document, viewColumn);
|
|
await editor.edit(editBuilder => {
|
|
editBuilder.replace(new vscode.Range(document.lineAt(0).range.start, document.lineAt(document.lineCount - 1).range.end), format(JSON.stringify(output, null, 4)));
|
|
});
|
|
await document.save();
|
|
|
|
if (activeEditor) {
|
|
vscode.window.showTextDocument(activeEditor.document, activeEditor.viewColumn);
|
|
}
|
|
}
|
|
}
|
|
const format = (jsonString: string): string => {
|
|
if (returnDisplayFormat === 'json') {
|
|
return jsonString;
|
|
}
|
|
|
|
let luaString = jsonString;
|
|
// Replace JSON syntax with Lua syntax
|
|
luaString = luaString.replace(/null/g, 'nil'); // Replace null with nil
|
|
luaString = luaString.replace(/"((?:[^"\\]|\\.)+)":/g, '["$1"] ='); // Replace "key": with ["key"] =
|
|
luaString = luaString.replace(/\["_([0-9]+)"\]\s*=/g, '[$1] ='); // Replace ["_n"] = with [n] =
|
|
luaString = luaString.replace(/\[\]/g, '{}'); // Replace [] with {}
|
|
luaString = luaString.replace(/\[\n/g, '{\n'); // Replace [ followed by a line break with { followed by a line break
|
|
luaString = luaString.replace(/]\n/g, '}\n'); // Replace ] followed by a line break with } followed by a line break
|
|
luaString = luaString.replace(/],/g, '},'); // Replace ], with },
|
|
luaString = luaString.replace(/]\s*$/g, '}'); // Replace ] at the end of the string with }
|
|
|
|
if (returnDisplay === 'file') {
|
|
luaString = `return --${logInfo}\n` + luaString;
|
|
}
|
|
return luaString;
|
|
}
|
|
|
|
try {
|
|
const response = await axios.get(`${protocol}://${serverAddress}:${serverPort}/${lua_base64}?env=default`, {
|
|
auth: {
|
|
username: authUsername,
|
|
password: authPassword
|
|
},
|
|
timeout: 3000
|
|
});
|
|
|
|
if (response.data.hasOwnProperty('result')) {
|
|
displayOutput(response.data.result);
|
|
} else {
|
|
displayOutput("SUCCESSFUL EXECUTION - NO RETURN VALUE");
|
|
}
|
|
} catch (error: any) {
|
|
if (error.response && error.response.status === 500) {
|
|
vscode.window.showErrorMessage('Internal server error occurred.');
|
|
displayOutput(error.response.data.error);
|
|
} else {
|
|
vscode.window.showErrorMessage(`Error: ${error}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
function getCurrentFileLua() {
|
|
const editor = vscode.window.activeTextEditor;
|
|
if (editor) {
|
|
const document = editor.document;
|
|
if (document.languageId === 'lua') {
|
|
const lua = document.getText();
|
|
const filename = path.basename(document.uri.fsPath);
|
|
return { lua, filename };
|
|
} else {
|
|
vscode.window.showErrorMessage('The active file is not a Lua file.');
|
|
}
|
|
} else {
|
|
vscode.window.showErrorMessage('No active file.');
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function activate(context: vscode.ExtensionContext) {
|
|
// context.globalState.update('firstRunDone', false);
|
|
const isFirstRun = !context.globalState.get('firstRunDone');
|
|
if (isFirstRun) {
|
|
context.globalState.update('firstRunDone', true);
|
|
const installMdPath = vscode.Uri.file(context.asAbsolutePath('INSTALL.md'));
|
|
vscode.commands.executeCommand('markdown.showPreview', installMdPath);
|
|
}
|
|
|
|
const config = vscode.workspace.getConfiguration('dcsLuaRunner');
|
|
let outputChannel = vscode.window.createOutputChannel("DCS Lua Runner");
|
|
|
|
context.subscriptions.push(vscode.commands.registerCommand('dcs-lua-runner.open-settings', () => {
|
|
vscode.commands.executeCommand('workbench.action.openSettings', 'dcsLuaRunner');
|
|
}));
|
|
|
|
context.subscriptions.push(vscode.commands.registerCommand('dcs-lua-runner.get-theatre', async () => {
|
|
const lua = 'return env.mission.theatre';
|
|
await runLua(lua, outputChannel, 'env.mission.theatre');
|
|
}));
|
|
|
|
context.subscriptions.push(vscode.commands.registerCommand('dcs-lua-runner.run-file', async () => {
|
|
const currentFileLua = getCurrentFileLua();
|
|
if (currentFileLua) {
|
|
const { lua, filename } = currentFileLua;
|
|
await runLua(lua, outputChannel, filename);
|
|
}
|
|
}));
|
|
|
|
context.subscriptions.push(vscode.commands.registerCommand('dcs-lua-runner.run-selected', async () => {
|
|
const editor = vscode.window.activeTextEditor;
|
|
if (editor && editor.selection) {
|
|
const document = editor.document;
|
|
const selection = editor.selection;
|
|
const lua = document.getText(selection);
|
|
const start = selection.start.line + 1;
|
|
const end = selection.end.line + 1;
|
|
const lineNumbers = start === end ? start : `${start}-${end}`;
|
|
const filename = path.basename(document.uri.fsPath) + ':' + lineNumbers;
|
|
await runLua(lua, outputChannel, filename);
|
|
}
|
|
}));
|
|
|
|
const displayRunTarget = () => {
|
|
const config = vscode.workspace.getConfiguration('dcsLuaRunner');
|
|
const runCodeLocally = config.get('runCodeLocally') as boolean;
|
|
const runInMissionEnv = config.get('runInMissionEnv') as boolean;
|
|
const runEnv = runInMissionEnv ? 'mission' : 'GUI';
|
|
const serverAddressMission = runCodeLocally ? '127.0.0.1' : config.get('serverAddress') as string;
|
|
const serverAddressGUI = (runCodeLocally || !config.get('serverAddressGUI')) ? serverAddressMission : config.get('serverAddressGUI') as string;
|
|
const serverAddress = runInMissionEnv ? serverAddressMission : serverAddressGUI;
|
|
const serverPortMission = runCodeLocally ? 12080 : config.get('serverPort') as number
|
|
const serverPortGUI = (runCodeLocally || !config.get('serverPortGUI')) ? (serverPortMission + 1) : config.get('serverPortGUI') as number;
|
|
const serverPort = runInMissionEnv ? serverPortMission : serverPortGUI;
|
|
const useHttps = runCodeLocally ? false : config.get('useHttps') as boolean;
|
|
const protocol = useHttps ? 'https' : 'http';
|
|
if (config.get('returnDisplay') === 'Console Output') {
|
|
outputChannel.show(true);
|
|
outputChannel.appendLine(`[DCS] Settings: Run code in ${runEnv} environment on ${protocol}://${serverAddress}:${serverPort}.`);
|
|
} else {
|
|
vscode.window.showInformationMessage(`Run code in ${runEnv} environment on ${protocol}://${serverAddress}:${serverPort}`);
|
|
}
|
|
};
|
|
|
|
const updateSetting = async (setting: string, targetState: boolean) => {
|
|
const config = vscode.workspace.getConfiguration('dcsLuaRunner');
|
|
if (setting === 'runCodeLocally' && targetState === false && !config.get('serverAddress')) {
|
|
vscode.window.showErrorMessage('Remote DCS server address not set.', 'Open Settings').then((choice) => {
|
|
if (choice === 'Open Settings') {
|
|
vscode.commands.executeCommand('workbench.action.openSettings', 'dcsLuaRunner');
|
|
}
|
|
});
|
|
await config.update(setting, true, vscode.ConfigurationTarget.Global);
|
|
return;
|
|
} else {
|
|
await config.update(setting, targetState, vscode.ConfigurationTarget.Global);
|
|
displayRunTarget();
|
|
}
|
|
};
|
|
|
|
context.subscriptions.push(vscode.commands.registerCommand('dcs-lua-runner.set-local', () => updateSetting('runCodeLocally', true)));
|
|
context.subscriptions.push(vscode.commands.registerCommand('dcs-lua-runner.set-local-button', () => updateSetting('runCodeLocally', true)));
|
|
context.subscriptions.push(vscode.commands.registerCommand('dcs-lua-runner.set-remote', () => updateSetting('runCodeLocally', false)));
|
|
context.subscriptions.push(vscode.commands.registerCommand('dcs-lua-runner.set-remote-button', () => updateSetting('runCodeLocally', false)));
|
|
|
|
context.subscriptions.push(vscode.commands.registerCommand('dcs-lua-runner.set-missionEnv', () => updateSetting('runInMissionEnv', true)));
|
|
context.subscriptions.push(vscode.commands.registerCommand('dcs-lua-runner.set-missionEnv-button', () => updateSetting('runInMissionEnv', true)));
|
|
context.subscriptions.push(vscode.commands.registerCommand('dcs-lua-runner.set-guiEnv', () => updateSetting('runInMissionEnv', false)));
|
|
context.subscriptions.push(vscode.commands.registerCommand('dcs-lua-runner.set-guiEnv-button', () => updateSetting('runInMissionEnv', false)));
|
|
context.subscriptions.push(vscode.commands.registerCommand('dcs-lua-runner.show-setup-guide', () => {
|
|
const installMdPath = vscode.Uri.file(context.asAbsolutePath('INSTALL.md'));
|
|
vscode.commands.executeCommand('markdown.showPreview', installMdPath);
|
|
}));
|
|
|
|
// Update the 'luaFileActive' context when the active editor changes
|
|
vscode.window.onDidChangeActiveTextEditor(editor => {
|
|
if (editor) {
|
|
vscode.commands.executeCommand('setContext', 'luaFileActive', editor.document.languageId === 'lua');
|
|
}
|
|
});
|
|
|
|
// Set the 'luaFileActive' context for the current active editor
|
|
if (vscode.window.activeTextEditor) {
|
|
vscode.commands.executeCommand('setContext', 'luaFileActive', vscode.window.activeTextEditor.document.languageId === 'lua');
|
|
}
|
|
let statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
|
|
// statusBarItem.tooltip = 'DCS Lua Runner: Click to change settings';
|
|
statusBarItem.show();
|
|
statusBarItem.command = 'extension.showQuickPick';
|
|
context.subscriptions.push(statusBarItem);
|
|
|
|
function updateStatusBarItem() {
|
|
const config = vscode.workspace.getConfiguration('dcsLuaRunner');
|
|
const editor = vscode.window.activeTextEditor;
|
|
const isLuaFile = editor && editor.document.languageId === 'lua';
|
|
const runCodeLocally = config.get('runCodeLocally') ? 'Local' : 'Remote';
|
|
const runInMissionEnv = config.get('runInMissionEnv') ? 'Mission' : 'GUI';
|
|
|
|
if (isLuaFile) {
|
|
statusBarItem.text = `DCS: ${runCodeLocally}, Env: ${runInMissionEnv}`;
|
|
statusBarItem.show();
|
|
} else {
|
|
statusBarItem.hide();
|
|
}
|
|
}
|
|
|
|
vscode.commands.registerCommand('extension.showQuickPick', () => {
|
|
const items = [
|
|
{ label: 'DCS Lua: Set Run Code on Local Machine', command: 'dcs-lua-runner.set-local' },
|
|
{ label: 'DCS Lua: Set Run Code on Remote Server', command: 'dcs-lua-runner.set-remote' },
|
|
{ label: 'DCS Lua: Set Run Code in Mission Environment', command: 'dcs-lua-runner.set-missionEnv' },
|
|
{ label: 'DCS Lua: Set Run Code in GUI Environment', command: 'dcs-lua-runner.set-guiEnv' },
|
|
{ label: 'DCS Lua: Open Settings', command: 'dcs-lua-runner.open-settings' },
|
|
{ label: 'DCS Lua: Show Setup Guide', command: 'dcs-lua-runner.show-setup-guide'}
|
|
];
|
|
vscode.window.showQuickPick(items).then(selection => {
|
|
// the user picked an item from the list
|
|
if (!selection) {
|
|
return;
|
|
}
|
|
|
|
// execute the selected command
|
|
vscode.commands.executeCommand(selection.command);
|
|
});
|
|
});
|
|
|
|
// Update the status bar when the configuration changes or the active text editor changes
|
|
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(updateStatusBarItem));
|
|
context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(updateStatusBarItem));
|
|
context.subscriptions.push(vscode.workspace.onDidOpenTextDocument(updateStatusBarItem));
|
|
context.subscriptions.push(vscode.workspace.onDidCloseTextDocument(updateStatusBarItem));
|
|
|
|
updateStatusBarItem();
|
|
}
|
|
|
|
export function deactivate() {} |