Files
whetstone_DSL/editor/src/panels/MenuBarPanel.h

273 lines
12 KiB
C++

#pragma once
#include "../EditorState.h"
#include "../EditorUtils.h"
#include "../ThemeEngine.h"
static void renderMenuBar(EditorState& state) {
if (!ImGui::BeginMainMenuBar()) return;
if (ImGui::BeginMenu("File")) {
if (ImGui::MenuItem("New", state.keys.getBinding("file.new").toString().c_str()))
{
std::string lang = state.active() ? state.active()->language : "python";
state.createBuffer(state.makeUntitledName(), "", lang, state.defaultBufferMode());
}
if (ImGui::MenuItem("Open...", state.keys.getBinding("file.open").toString().c_str()))
{
auto path = FileDialog::openFile({"Open File", {"*.py","*.cpp","*.h","*.el","*.js","*.ts","*.java","*.rs","*.go","*.org","*.md","*.txt","*.docx","*.*"}, state.lastDialogPath});
if (!path.empty()) {
state.lastDialogPath = path;
state.doOpen(path, state.defaultBufferMode());
}
}
if (ImGui::MenuItem("Open Project...")) {
auto path = FileDialog::openFile({"Open Project", {"*.whetstone"}, state.lastDialogPath});
if (!path.empty()) {
if (!state.loadProject(path)) {
state.notify(NotificationLevel::Error,
"Failed to open project: " + path);
} else {
state.lastDialogPath = path;
}
}
}
if (ImGui::MenuItem("Open Folder...")) {
auto path = FileDialog::openFolder({"Open Folder", state.workspaceRoot});
if (!path.empty()) {
std::string error;
if (!state.setWorkspaceRoot(path, &error)) {
state.notify(NotificationLevel::Error,
"Failed to open folder: " + error);
} else {
state.lastDialogPath = path;
}
}
}
if (ImGui::MenuItem("Save", state.keys.getBinding("file.save").toString().c_str()))
{
if (!state.active()) {
// no-op
} else if (state.active()->path.rfind("(untitled", 0) == 0) {
auto path = FileDialog::saveFile({"Save File", {"*.*"}, state.lastDialogPath});
if (!path.empty()) {
state.active()->path = path;
state.lastDialogPath = path;
state.doSave();
}
} else {
state.doSave();
}
}
if (ImGui::MenuItem("Save Project...")) {
auto path = FileDialog::saveFile({"Save Project", {"*.whetstone"}, state.lastDialogPath});
if (!path.empty()) {
if (!state.saveProject(path)) {
state.notify(NotificationLevel::Error,
"Failed to save project: " + path);
} else {
state.lastDialogPath = path;
}
}
}
ImGui::Separator();
if (ImGui::MenuItem("Exit")) state.exitRequested = true;
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Edit")) {
if (ImGui::MenuItem("Undo", state.keys.getBinding("edit.undo").toString().c_str(),
false, state.active() ? state.active()->orchestrator.getUndoDepth() > 0 : false))
state.doUndo();
if (ImGui::MenuItem("Redo", state.keys.getBinding("edit.redo").toString().c_str(),
false, state.active() ? state.active()->orchestrator.getRedoDepth() > 0 : false))
state.doRedo();
ImGui::Separator();
if (ImGui::MenuItem("Find/Replace", state.keys.getBinding("search.find").toString().c_str())) {
state.search.showFind = true;
state.search.showReplace = true;
}
if (ImGui::MenuItem("Find in Files", state.keys.getBinding("search.findInFiles").toString().c_str()))
state.search.showProjectSearch = !state.search.showProjectSearch;
ImGui::EndMenu();
}
if (ImGui::BeginMenu("View")) {
ImGui::MenuItem("Show Whitespace", nullptr, &state.ui.showWhitespace);
ImGui::MenuItem("Show Minimap", nullptr, &state.ui.showMinimap);
ImGui::MenuItem("Inline Completion Helper", nullptr, &state.ui.showCompletionHelper);
ImGui::MenuItem("Show Annotations", nullptr, &state.ui.showAnnotations);
ImGui::MenuItem("Show Outline", nullptr, &state.ui.showOutline);
ImGui::MenuItem("Terminal", state.keys.getBinding("view.toggleTerminal").toString().c_str(),
&state.build.showTerminalPanel);
ImGui::MenuItem("Dependencies", nullptr, &state.library.showDependencyPanel);
ImGui::MenuItem("Libraries", nullptr, &state.library.showLibraryBrowserPanel);
ImGui::MenuItem("Compose", nullptr, &state.library.showCompositionPanel);
ImGui::MenuItem("Memory Strategies", nullptr, &state.ui.showMemoryStrategies);
ImGui::MenuItem("Agent Chat", nullptr, &state.ui.showAgentChatPanel);
ImGui::MenuItem("Emacs Packages", nullptr, &state.emacsState.showEmacsPackagesPanel);
ImGui::MenuItem("Emacs Bridge", nullptr, &state.emacsState.showEmacsBridgePanel);
ImGui::MenuItem("Settings", nullptr, &state.ui.showSettingsPanel);
ImGui::MenuItem("Keyboard Shortcuts", nullptr, &state.ui.showShortcutReference);
ImGui::MenuItem("LSP Servers...", nullptr, &state.ui.showLspSettings);
if (state.active()) {
bool textMode = state.active()->bufferMode == BufferManager::BufferMode::Text;
if (ImGui::MenuItem("Text-Editor Mode", nullptr, textMode)) {
state.active()->bufferMode = textMode ?
BufferManager::BufferMode::Structured :
BufferManager::BufferMode::Text;
state.buffers.setBufferMode(state.active()->path, state.active()->bufferMode);
if (state.active()->bufferMode == BufferManager::BufferMode::Text) {
state.suggestions.clear();
state.whetstoneDiagnostics.clear();
state.analysisPending = false;
} else {
state.onTextChanged();
}
if (state.active()->path.rfind("(untitled", 0) != 0) {
state.welcome.addRecentFile(state.active()->path,
state.active()->language,
bufferModeToString(state.active()->bufferMode));
state.saveRecentFiles();
}
}
}
if (ImGui::BeginMenu("Layout")) {
if (ImGui::MenuItem("VSCode", nullptr, state.ui.layoutPreset == LayoutPreset::VSCode))
state.ui.layoutPreset = LayoutPreset::VSCode;
if (ImGui::MenuItem("Emacs", nullptr, state.ui.layoutPreset == LayoutPreset::Emacs))
state.ui.layoutPreset = LayoutPreset::Emacs;
if (ImGui::MenuItem("JetBrains", nullptr, state.ui.layoutPreset == LayoutPreset::JetBrains))
state.ui.layoutPreset = LayoutPreset::JetBrains;
ImGui::Separator();
if (ImGui::MenuItem("Reset Layout")) {
state.ui.requestLayoutReset = true;
}
ImGui::EndMenu();
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Navigate")) {
if (ImGui::MenuItem("Go to Line...", state.keys.getBinding("nav.goToLine").toString().c_str())) {
state.search.showGoToLine = true;
state.search.goToLineBuf[0] = '\0';
state.search.goToLineError = false;
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Build")) {
if (ImGui::MenuItem("Run", state.keys.getBinding("build.run").toString().c_str())) {
state.runActiveFile(false);
}
if (ImGui::MenuItem("Build", state.keys.getBinding("build.build").toString().c_str())) {
state.runActiveFile(true);
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Language")) {
if (ImGui::MenuItem("Python", nullptr, state.active() && state.active()->language == "python"))
state.setLanguage("python");
if (ImGui::MenuItem("C++", nullptr, state.active() && state.active()->language == "cpp"))
state.setLanguage("cpp");
if (ImGui::MenuItem("Elisp", nullptr, state.active() && state.active()->language == "elisp"))
state.setLanguage("elisp");
if (ImGui::MenuItem("JavaScript", nullptr, state.active() && state.active()->language == "javascript"))
state.setLanguage("javascript");
if (ImGui::MenuItem("TypeScript", nullptr, state.active() && state.active()->language == "typescript"))
state.setLanguage("typescript");
if (ImGui::MenuItem("Java", nullptr, state.active() && state.active()->language == "java"))
state.setLanguage("java");
if (ImGui::MenuItem("Rust", nullptr, state.active() && state.active()->language == "rust"))
state.setLanguage("rust");
if (ImGui::MenuItem("Go", nullptr, state.active() && state.active()->language == "go"))
state.setLanguage("go");
if (ImGui::MenuItem("Org", nullptr, state.active() && state.active()->language == "org"))
state.setLanguage("org");
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Refactor")) {
bool canRefactor = state.isStructured() && state.active() && !state.active()->readOnly;
if (!canRefactor) ImGui::BeginDisabled();
if (ImGui::MenuItem("Rename Variable")) {
state.refactorAction = 1;
state.showRefactorPopup = true;
state.refactorNameA[0] = '\0';
state.refactorNameB[0] = '\0';
ImGui::OpenPopup("RefactorPopup");
}
if (ImGui::MenuItem("Extract Function")) {
state.refactorAction = 2;
state.showRefactorPopup = true;
state.refactorNameA[0] = '\0';
state.refactorNameB[0] = '\0';
ImGui::OpenPopup("RefactorPopup");
}
if (ImGui::MenuItem("Inline Variable")) {
state.refactorAction = 3;
state.showRefactorPopup = true;
state.refactorNameA[0] = '\0';
state.refactorNameB[0] = '\0';
ImGui::OpenPopup("RefactorPopup");
}
if (!canRefactor) ImGui::EndDisabled();
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Workflow")) {
bool hasAst = state.activeAST() != nullptr;
if (!hasAst) ImGui::BeginDisabled();
if (ImGui::MenuItem("Annotate File Wizard")) {
state.ui.showAnnotateWizard = true;
}
if (ImGui::MenuItem("Cross-Language Project Wizard")) {
state.ui.showProjectWizard = true;
}
if (!hasAst) ImGui::EndDisabled();
if (ImGui::MenuItem("Connect Agent Wizard")) {
state.ui.showAgentWizard = true;
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Keybindings")) {
for (auto p : KeybindingManager::availableProfiles()) {
if (ImGui::MenuItem(KeybindingManager::profileName(p), nullptr,
state.keys.getProfile() == p)) {
state.keys.setProfile(p);
state.registerCommands();
}
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Help")) {
ImGui::MenuItem("Documentation", nullptr, &state.ui.showHelpPanel);
ImGui::EndMenu();
}
const bool canProject = state.activeAST() != nullptr;
ImGui::SameLine();
ImGui::Dummy(ImVec2(12.0f, 0.0f));
ImGui::SameLine();
if (!canProject) ImGui::BeginDisabled();
if (ImGui::Button("Project to...")) {
ImGui::OpenPopup("ProjectToPopup");
}
if (ImGui::BeginPopup("ProjectToPopup")) {
if (ImGui::MenuItem("Python")) state.projectToLanguage("python");
if (ImGui::MenuItem("C++")) state.projectToLanguage("cpp");
if (ImGui::MenuItem("Elisp")) state.projectToLanguage("elisp");
ImGui::EndPopup();
}
if (!canProject) ImGui::EndDisabled();
ImGui::SameLine();
ImGui::Dummy(ImVec2(12.0f, 0.0f));
ImGui::SameLine();
bool canRunFile = state.active() && !state.active()->readOnly;
if (!canRunFile) ImGui::BeginDisabled();
if (ImGui::Button("Run >")) {
state.runActiveFile(false);
}
ImGui::SameLine();
if (ImGui::Button("Build")) {
state.runActiveFile(true);
}
if (!canRunFile) ImGui::EndDisabled();
ImGui::EndMainMenuBar();
}