Files
JiboSDK/lib/main-pulsar.js
2026-03-22 03:21:45 +02:00

249 lines
7.0 KiB
JavaScript

"use strict";
const fs = require("fs");
const path = require("path");
const _ = require("lodash");
const $ = require("jquery");
const React = require("react");
const { CompositeDisposable } = require("atom");
const atomIntegration = require("./atom-react/atom-integration");
const jsonOpener = require("./common/json-opener");
const packageGeneratorModal = require("./package-generator/package-generator-modal");
const launcher = require("./launcher/launcher");
const treeViewHelper = require("./common/tree-view-helper");
const CheatSheetTab = require("./cheat-sheet/cheat-sheat-tab");
const StyleguideEditor = require("./atom-react/styleguide/styleguide-editor");
const JiboSim = require("./animation-preview/jibo-sim");
const AnimationEditor = require("./animation-editor/animation-editor");
const BehaviorEditor = require("./behavior-editor/behavior-editor");
const AnimationModel = require("./animation-editor/models/animation-model");
const BehaviorTreeModel = require("./behavior-editor/tree-model");
function createUniquePath(directory, baseName, extension) {
let candidate = path.join(directory, `${baseName}.${extension}`);
let i = 1;
while (fs.existsSync(candidate)) {
candidate = path.join(directory, `${baseName}-${i}.${extension}`);
i += 1;
}
return candidate;
}
function getSelectedProjectSubdir(subdirName) {
return treeViewHelper.getFolderPathWithDirectory(
treeViewHelper.getFolderPathOfSelection(),
subdirName,
);
}
function notifyError(title, err) {
if (!atom.notifications) return;
atom.notifications.addError(title, {
detail: String((err && err.stack) || err),
dismissable: true,
});
}
module.exports = {
config: {
AnimationEditorBackgroundColor: {
type: "color",
default: "#4C4C4C",
description: "The background color in the Animation Editor",
},
AnimationEditorGridColor: {
type: "color",
default: "#E5E5E5",
description: "The grid color in the Animation Editor",
},
"RunConfiguration.type": {
type: "string",
enum: ["local", "remote"],
default: "local",
description: "Which mode to use when running/debugging your skill.",
},
"RunConfiguration.host": {
type: "string",
default: "",
description: "The host or ip of the robot you want to target.",
},
"RunConfiguration.run-dir": {
type: "string",
default: "${project}",
description:
"The directory to run your skill from if it's not the root of your opened project.",
},
DisableRunSkillShortcut: {
type: "boolean",
default: false,
description:
"Disable the shortcut for running skills, if you prefer it binding to built in the Symbol-Viewer toggle.",
},
},
activate() {
this.disposables = new CompositeDisposable();
try {
atomIntegration.activate();
this.disposables.add(
atom.workspace.addOpener((uri) => {
return this.openURI(uri);
}),
);
this.disposables.add(
atom.commands.add("atom-workspace", {
"jibo-sdk:new-project": () => {
try {
packageGeneratorModal();
} catch (err) {
notifyError("Jibo: New Project failed", err);
}
},
"jibo-sdk:open-as-json": () => {
try {
jsonOpener.open();
} catch (err) {
notifyError("Jibo: Open as JSON failed", err);
}
},
"jibo-sdk:new-animation-file": () => {
try {
const dir = getSelectedProjectSubdir("animations");
if (!dir) {
alert(
"You must have a valid project loaded in order to create a new animation.",
);
return;
}
const filePath = createUniquePath(dir, "new-animation", "keys");
if (!AnimationEditor.isValidDirectory(filePath)) {
alert('You must save animations under the "animations" folder.');
return;
}
AnimationModel.createNewFile(filePath);
atom.workspace.open(filePath);
} catch (err) {
notifyError("Jibo: New Animation failed", err);
}
},
"jibo-sdk:new-behavior-tree-file": () => {
try {
const dir = getSelectedProjectSubdir("behaviors");
if (!dir) {
alert(
"You must have a valid project loaded in order to create a new behavior tree file.",
);
return;
}
const filePath = createUniquePath(dir, "new-behavior", "bt");
if (!BehaviorEditor.isValidDirectory(filePath)) {
alert('You must save behavior trees under the "behaviors" folder.');
return;
}
const schema = BehaviorEditor.getNewSchema(filePath);
BehaviorTreeModel.createNewFile(filePath, schema.core.schema.Sequence);
atom.workspace.open(filePath);
} catch (err) {
notifyError("Jibo: New Behavior Tree failed", err);
}
},
"jibo-sdk:play": () => {
try {
launcher.play();
} catch (err) {
notifyError("Jibo: Play failed", err);
}
},
"jibo-sdk:play-animation": () => {
try {
launcher.play();
} catch (err) {
notifyError("Jibo: Play Animation failed", err);
}
},
"jibo-sdk:stop": () => {
try {
launcher.stop();
} catch (err) {
notifyError("Jibo: Stop failed", err);
}
},
"jibo-sdk:cheat-sheet": () => {
try {
atom.workspace.open("atom://jibo-cheat-sheet");
} catch (err) {
notifyError("Jibo: Open Cheat Sheet failed", err);
}
},
"atom-react:styleguide": () => {
try {
atom.workspace.open("atom://atom-react-styleguide");
} catch (err) {
notifyError("Jibo: Open Styleguide failed", err);
}
},
"jibo-sdk:run-skill": (event) => {
if (atom.config.get("jibo-sdk.DisableRunSkillShortcut")) {
if (event && typeof event.abortKeyBinding === "function") event.abortKeyBinding();
return;
}
try {
launcher.togglePlayer();
} catch (err) {
notifyError("Jibo: Run Skill failed", err);
}
},
"jibo-sdk:login": () => {
// Legacy login gating is no longer supported; keep as no-op.
if (atom.notifications) {
atom.notifications.addInfo("Jibo: Login is not required in Pulsar", {
detail:
"The original Atom-era login flow depended on deprecated Electron APIs.",
dismissable: true,
});
}
},
}),
);
} catch (err) {
notifyError("Jibo SDK failed to activate", err);
}
},
deactivate() {
if (this.disposables) this.disposables.dispose();
try {
atomIntegration.deactivate();
} catch (err) {
// ignore
}
},
openURI(uri) {
// Always handle package URIs.
if (uri === "atom://jibo-cheat-sheet") return new CheatSheetTab(uri, true);
if (uri === "atom://atom-react-styleguide") return new StyleguideEditor(uri, true);
// Respect JSON opener toggle for file-based editors.
if (jsonOpener.useDefaultEditor() === false) return undefined;
const handlers = {
".anim": JiboSim,
".keys": AnimationEditor,
".bt": BehaviorEditor,
};
const ext = path.extname(uri).toLowerCase();
if (_.has(handlers, ext)) return new handlers[ext](uri);
return undefined;
},
};