feat: Enhance project file management and agent settings

- Added support for loading and saving agent settings in the project format, including AI provider, model, and custom prompts.
- Implemented RecentFilesManager for managing recent files with functionality to save and load recent file paths.
- Introduced a new ProjectFileEditor for editing .yaze project files with syntax highlighting and validation features.
- Enhanced the AgentChatWidget with file editing capabilities, allowing users to open, create, and save files directly within the interface.
- Improved configuration directory handling and path expansion for better cross-platform compatibility.
This commit is contained in:
scawful
2025-10-04 21:27:39 -04:00
parent 85bc14e93e
commit dec8314a55
9 changed files with 882 additions and 51 deletions

View File

@@ -654,6 +654,18 @@ void AgentChatWidget::Draw() {
ImGui::EndTabItem();
}
// File Editor Tabs
if (ImGui::BeginTabItem(ICON_MD_EDIT_NOTE " Files")) {
RenderFileEditorTabs();
ImGui::EndTabItem();
}
// System Prompt Editor Tab
if (ImGui::BeginTabItem(ICON_MD_SETTINGS_SUGGEST " System Prompt")) {
RenderSystemPromptEditor();
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
@@ -1628,5 +1640,284 @@ void AgentChatWidget::HandleProposalReceived(
}
}
void AgentChatWidget::RenderSystemPromptEditor() {
ImGui::BeginChild("SystemPromptEditor", ImVec2(0, 0), false);
// Toolbar
if (ImGui::Button(ICON_MD_FOLDER_OPEN " Load Default")) {
// Load system_prompt_v2.txt
std::string prompt_path = core::GetConfigDirectory() + "/../assets/agent/system_prompt_v2.txt";
std::ifstream file(prompt_path);
if (file.is_open()) {
// Find or create system prompt tab
bool found = false;
for (auto& tab : open_files_) {
if (tab.is_system_prompt) {
std::stringstream buffer;
buffer << file.rdbuf();
tab.editor.SetText(buffer.str());
tab.filepath = prompt_path;
found = true;
break;
}
}
if (!found) {
FileEditorTab tab;
tab.filename = "system_prompt_v2.txt";
tab.filepath = prompt_path;
tab.is_system_prompt = true;
tab.editor.SetLanguageDefinition(TextEditor::LanguageDefinition::CPlusPlus());
std::stringstream buffer;
buffer << file.rdbuf();
tab.editor.SetText(buffer.str());
open_files_.push_back(std::move(tab));
active_file_tab_ = static_cast<int>(open_files_.size()) - 1;
}
if (toast_manager_) {
toast_manager_->Show("System prompt loaded", ToastType::kSuccess);
}
} else if (toast_manager_) {
toast_manager_->Show("Could not load system prompt file", ToastType::kError);
}
}
ImGui::SameLine();
if (ImGui::Button(ICON_MD_SAVE " Save")) {
// Save the current system prompt
for (auto& tab : open_files_) {
if (tab.is_system_prompt && !tab.filepath.empty()) {
std::ofstream file(tab.filepath);
if (file.is_open()) {
file << tab.editor.GetText();
tab.modified = false;
if (toast_manager_) {
toast_manager_->Show("System prompt saved", ToastType::kSuccess);
}
} else if (toast_manager_) {
toast_manager_->Show("Failed to save system prompt", ToastType::kError);
}
break;
}
}
}
ImGui::SameLine();
if (ImGui::Button(ICON_MD_NOTE_ADD " Create New")) {
CreateNewFileInEditor("system_prompt_custom.txt");
if (!open_files_.empty()) {
open_files_.back().is_system_prompt = true;
open_files_.back().editor.SetText("# Custom System Prompt\n\nEnter your custom system prompt here...\n");
}
}
ImGui::Separator();
// Find and render system prompt editor
bool found_prompt = false;
for (size_t i = 0; i < open_files_.size(); ++i) {
if (open_files_[i].is_system_prompt) {
found_prompt = true;
ImVec2 editor_size = ImVec2(0, ImGui::GetContentRegionAvail().y);
open_files_[i].editor.Render("##SystemPromptEditor", editor_size);
if (open_files_[i].editor.IsTextChanged()) {
open_files_[i].modified = true;
}
break;
}
}
if (!found_prompt) {
ImGui::TextWrapped("No system prompt loaded. Click 'Load Default' to edit the system prompt.");
}
ImGui::EndChild();
}
void AgentChatWidget::RenderFileEditorTabs() {
ImGui::BeginChild("FileEditorArea", ImVec2(0, 0), false);
// Toolbar
if (ImGui::Button(ICON_MD_NOTE_ADD " New File")) {
ImGui::OpenPopup("NewFilePopup");
}
ImGui::SameLine();
if (ImGui::Button(ICON_MD_FOLDER_OPEN " Open File")) {
auto filepath = core::FileDialogWrapper::ShowOpenFileDialog();
if (!filepath.empty()) {
OpenFileInEditor(filepath);
}
}
// New file popup
static char new_filename_buffer[256] = {};
if (ImGui::BeginPopup("NewFilePopup")) {
ImGui::Text("Create New File");
ImGui::Separator();
ImGui::InputText("Filename", new_filename_buffer, sizeof(new_filename_buffer));
if (ImGui::Button("Create")) {
if (strlen(new_filename_buffer) > 0) {
CreateNewFileInEditor(new_filename_buffer);
memset(new_filename_buffer, 0, sizeof(new_filename_buffer));
ImGui::CloseCurrentPopup();
}
}
ImGui::SameLine();
if (ImGui::Button("Cancel")) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
ImGui::Separator();
// File tabs
if (!open_files_.empty()) {
if (ImGui::BeginTabBar("FileTabs", ImGuiTabBarFlags_Reorderable |
ImGuiTabBarFlags_FittingPolicyScroll)) {
for (size_t i = 0; i < open_files_.size(); ++i) {
if (open_files_[i].is_system_prompt) continue; // Skip system prompt in file tabs
bool open = true;
std::string tab_label = open_files_[i].filename;
if (open_files_[i].modified) {
tab_label += " *";
}
if (ImGui::BeginTabItem(tab_label.c_str(), &open)) {
active_file_tab_ = static_cast<int>(i);
// File toolbar
if (ImGui::Button(ICON_MD_SAVE " Save")) {
if (!open_files_[i].filepath.empty()) {
std::ofstream file(open_files_[i].filepath);
if (file.is_open()) {
file << open_files_[i].editor.GetText();
open_files_[i].modified = false;
if (toast_manager_) {
toast_manager_->Show("File saved", ToastType::kSuccess);
}
} else if (toast_manager_) {
toast_manager_->Show("Failed to save file", ToastType::kError);
}
} else {
auto save_path = core::FileDialogWrapper::ShowSaveFileDialog(
open_files_[i].filename, "");
if (!save_path.empty()) {
std::ofstream file(save_path);
if (file.is_open()) {
file << open_files_[i].editor.GetText();
open_files_[i].filepath = save_path;
open_files_[i].modified = false;
if (toast_manager_) {
toast_manager_->Show("File saved", ToastType::kSuccess);
}
}
}
}
}
ImGui::SameLine();
ImGui::TextDisabled("%s", open_files_[i].filepath.empty() ?
"(unsaved)" : open_files_[i].filepath.c_str());
ImGui::Separator();
// Editor
ImVec2 editor_size = ImVec2(0, ImGui::GetContentRegionAvail().y);
open_files_[i].editor.Render("##FileEditor", editor_size);
if (open_files_[i].editor.IsTextChanged()) {
open_files_[i].modified = true;
}
ImGui::EndTabItem();
}
if (!open) {
// Tab was closed
open_files_.erase(open_files_.begin() + i);
if (active_file_tab_ >= static_cast<int>(i)) {
active_file_tab_--;
}
break;
}
}
ImGui::EndTabBar();
}
} else {
ImGui::TextWrapped("No files open. Create a new file or open an existing one.");
}
ImGui::EndChild();
}
void AgentChatWidget::OpenFileInEditor(const std::string& filepath) {
// Check if file is already open
for (size_t i = 0; i < open_files_.size(); ++i) {
if (open_files_[i].filepath == filepath) {
active_file_tab_ = static_cast<int>(i);
return;
}
}
// Load the file
std::ifstream file(filepath);
if (!file.is_open()) {
if (toast_manager_) {
toast_manager_->Show("Could not open file", ToastType::kError);
}
return;
}
FileEditorTab tab;
tab.filepath = filepath;
// Extract filename from path
size_t last_slash = filepath.find_last_of("/\\");
tab.filename = (last_slash != std::string::npos) ?
filepath.substr(last_slash + 1) : filepath;
// Set language based on extension
std::string ext = core::GetFileExtension(filepath);
if (ext == "cpp" || ext == "cc" || ext == "h" || ext == "hpp") {
tab.editor.SetLanguageDefinition(TextEditor::LanguageDefinition::CPlusPlus());
} else if (ext == "c") {
tab.editor.SetLanguageDefinition(TextEditor::LanguageDefinition::C());
} else if (ext == "lua") {
tab.editor.SetLanguageDefinition(TextEditor::LanguageDefinition::Lua());
}
std::stringstream buffer;
buffer << file.rdbuf();
tab.editor.SetText(buffer.str());
open_files_.push_back(std::move(tab));
active_file_tab_ = static_cast<int>(open_files_.size()) - 1;
if (toast_manager_) {
toast_manager_->Show("File loaded", ToastType::kSuccess);
}
}
void AgentChatWidget::CreateNewFileInEditor(const std::string& filename) {
FileEditorTab tab;
tab.filename = filename;
tab.modified = true;
// Set language based on extension
std::string ext = core::GetFileExtension(filename);
if (ext == "cpp" || ext == "cc" || ext == "h" || ext == "hpp") {
tab.editor.SetLanguageDefinition(TextEditor::LanguageDefinition::CPlusPlus());
} else if (ext == "c") {
tab.editor.SetLanguageDefinition(TextEditor::LanguageDefinition::C());
} else if (ext == "lua") {
tab.editor.SetLanguageDefinition(TextEditor::LanguageDefinition::Lua());
}
open_files_.push_back(std::move(tab));
active_file_tab_ = static_cast<int>(open_files_.size()) - 1;
}
} // namespace editor
} // namespace yaze