From 8ef9e60829f991da811495a916863af2cf3c136c Mon Sep 17 00:00:00 2001 From: Oleg Korshul Date: Tue, 11 Nov 2025 10:40:10 +0300 Subject: [PATCH 1/7] Add tools for generate docx/pdf/pptx --- .../cefwrapper/client_renderer_wrapper.cpp | 5 ++ .../tools/functions/generate_docx/info.json | 15 ++++++ .../tools/functions/generate_docx/main.cpp | 45 ++++++++++++++++ .../tools/functions/generate_form/info.json | 15 ++++++ .../tools/functions/generate_form/main.cpp | 45 ++++++++++++++++ .../tools/functions/generate_pptx/info.json | 23 ++++++++ .../tools/functions/generate_pptx/main.cpp | 53 +++++++++++++++++++ .../lib/tools/functions/internal/funcs.h | 6 +++ ChromiumBasedEditors/lib/tools/tools.h | 2 + 9 files changed, 209 insertions(+) create mode 100644 ChromiumBasedEditors/lib/tools/functions/generate_docx/info.json create mode 100644 ChromiumBasedEditors/lib/tools/functions/generate_docx/main.cpp create mode 100644 ChromiumBasedEditors/lib/tools/functions/generate_form/info.json create mode 100644 ChromiumBasedEditors/lib/tools/functions/generate_form/main.cpp create mode 100644 ChromiumBasedEditors/lib/tools/functions/generate_pptx/info.json create mode 100644 ChromiumBasedEditors/lib/tools/functions/generate_pptx/main.cpp diff --git a/ChromiumBasedEditors/lib/src/cefwrapper/client_renderer_wrapper.cpp b/ChromiumBasedEditors/lib/src/cefwrapper/client_renderer_wrapper.cpp index ad83deb5..395f979a 100644 --- a/ChromiumBasedEditors/lib/src/cefwrapper/client_renderer_wrapper.cpp +++ b/ChromiumBasedEditors/lib/src/cefwrapper/client_renderer_wrapper.cpp @@ -5279,6 +5279,11 @@ window.AscDesktopEditor.CallInFrame(\"" + return files; } + virtual void ExecuteJS(const std::string& code) + { + CefV8Context::GetCurrentContext()->GetFrame()->ExecuteJavaScript(code, "", 0); + } + // Provide the reference counting implementation for this class. IMPLEMENT_REFCOUNTING(CAscEditorNativeV8Handler); }; diff --git a/ChromiumBasedEditors/lib/tools/functions/generate_docx/info.json b/ChromiumBasedEditors/lib/tools/functions/generate_docx/info.json new file mode 100644 index 00000000..20f57c73 --- /dev/null +++ b/ChromiumBasedEditors/lib/tools/functions/generate_docx/info.json @@ -0,0 +1,15 @@ +{ + "type": "function", + "name": "generate_docx", + "description": "Use this function if you are asked to generate a textual document (report, article, letter, etc.) based on a description. Input: a detailed description of what needs to be generated.", + "parameters": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Detailed description of the document to generate, including its topic, structure, tone, and format." + } + }, + "required": ["description"] + } +} \ No newline at end of file diff --git a/ChromiumBasedEditors/lib/tools/functions/generate_docx/main.cpp b/ChromiumBasedEditors/lib/tools/functions/generate_docx/main.cpp new file mode 100644 index 00000000..f0b4e996 --- /dev/null +++ b/ChromiumBasedEditors/lib/tools/functions/generate_docx/main.cpp @@ -0,0 +1,45 @@ +#include "./../internal/base.h" + +namespace generate_docx +{ + std::string description() + { + return "\ +{\ + \"type\": \"function\",\ + \"name\": \"generate_docx\",\ + \"description\": \"Use this function if you are asked to generate a textual document (report, article, letter, etc.) based on a description. Input: a detailed description of what needs to be generated.\",\ + \"parameters\": {\ + \"type\": \"object\",\ + \"properties\": {\ + \"description\": {\ + \"type\": \"string\",\ + \"description\": \"Detailed description of the document to generate, including its topic, structure, tone, and format.\"\ + }\ + },\ + \"required\": [\"description\"]\ + }\ +}"; + } + + std::string main(const std::string& arg, CAIToolsHelper* helper) + { + json returnValue = json::object(); + + json param = json::parse(arg); + if (!param.contains("description") || !param["description"].is_string()) + { + returnValue["status"] = "error"; + } + else + { + std::string description = param["description"]; + std::string code = "window.AscDesktopEditor.generateNew(\"docx\", \"ai-gen-docx\", " + json(description).dump() + ");"; + helper->ExecuteJS(code); + + returnValue["status"] = "success"; + } + + return returnValue.dump(); + } +} diff --git a/ChromiumBasedEditors/lib/tools/functions/generate_form/info.json b/ChromiumBasedEditors/lib/tools/functions/generate_form/info.json new file mode 100644 index 00000000..e90e6378 --- /dev/null +++ b/ChromiumBasedEditors/lib/tools/functions/generate_form/info.json @@ -0,0 +1,15 @@ +{ + "type": "function", + "name": "generate_form", + "description": "Use this function if you are asked to generate a form or document template (contract, any document for filling) based on a description. Input: a detailed description of the desired form or template.", + "parameters": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Detailed description of the form or template to generate, including purpose, structure." + } + }, + "required": ["description"] + } +} \ No newline at end of file diff --git a/ChromiumBasedEditors/lib/tools/functions/generate_form/main.cpp b/ChromiumBasedEditors/lib/tools/functions/generate_form/main.cpp new file mode 100644 index 00000000..f1c2f386 --- /dev/null +++ b/ChromiumBasedEditors/lib/tools/functions/generate_form/main.cpp @@ -0,0 +1,45 @@ +#include "./../internal/base.h" + +namespace generate_form +{ + std::string description() + { + return "\ +{\ + \"type\": \"function\",\ + \"name\": \"generate_form\",\ + \"description\": \"Use this function if you are asked to generate a form or document template (contract, any document for filling) based on a description. Input: a detailed description of the desired form or template.\",\ + \"parameters\": {\ + \"type\": \"object\",\ + \"properties\": {\ + \"description\": {\ + \"type\": \"string\",\ + \"description\": \"Detailed description of the form or template to generate, including purpose, structure.\"\ + }\ + },\ + \"required\": [\"description\"]\ + }\ +}"; + } + + std::string main(const std::string& arg, CAIToolsHelper* helper) + { + json returnValue = json::object(); + + json param = json::parse(arg); + if (!param.contains("description") || !param["description"].is_string()) + { + returnValue["status"] = "error"; + } + else + { + std::string description = param["description"]; + std::string code = "window.AscDesktopEditor.generateNew(\"pdf\", \"ai-gen-form\", " + json(description).dump() + ");"; + helper->ExecuteJS(code); + + returnValue["status"] = "success"; + } + + return returnValue.dump(); + } +} diff --git a/ChromiumBasedEditors/lib/tools/functions/generate_pptx/info.json b/ChromiumBasedEditors/lib/tools/functions/generate_pptx/info.json new file mode 100644 index 00000000..ac866b18 --- /dev/null +++ b/ChromiumBasedEditors/lib/tools/functions/generate_pptx/info.json @@ -0,0 +1,23 @@ +{ + "type": "function", + "name": "generate_pptx", + "description": "Use this function if you are asked to generate a complete presentation with a custom theme, fonts, and streaming content. Input: a detailed description of the presentation to create, including topic, number of slides, and style.", + "parameters": { + "type": "object", + "properties": { + "topic": { + "type": "string", + "description": "Presentation topic." + }, + "slideCount": { + "type": "string", + "description": "Number of slides to generate." + }, + "style": { + "type": "string", + "description": "Visual style of the presentation: modern, classic, minimal, or corporate." + } + }, + "required": [] + } +} \ No newline at end of file diff --git a/ChromiumBasedEditors/lib/tools/functions/generate_pptx/main.cpp b/ChromiumBasedEditors/lib/tools/functions/generate_pptx/main.cpp new file mode 100644 index 00000000..23395e50 --- /dev/null +++ b/ChromiumBasedEditors/lib/tools/functions/generate_pptx/main.cpp @@ -0,0 +1,53 @@ +#include "./../internal/base.h" + +namespace generate_pptx +{ + std::string description() + { + return "\ +{\ + \"type\": \"function\",\ + \"name\": \"generate_pptx\",\ + \"description\": \"Use this function if you are asked to generate a complete presentation with a custom theme, fonts, and streaming content. Input: a detailed description of the presentation to create, including topic, number of slides, and style.\",\ + \"parameters\": {\ + \"type\": \"object\",\ + \"properties\": {\ + \"topic\": {\ + \"type\": \"string\",\ + \"description\": \"Presentation topic.\"\ + },\ + \"slideCount\": {\ + \"type\": \"string\",\ + \"description\": \"Number of slides to generate.\"\ + },\ + \"style\": {\ + \"type\": \"string\",\ + \"description\": \"Visual style of the presentation: modern, classic, minimal, or corporate.\"\ + }\ + },\ + \"required\": []\ + }\ +}"; + } + + std::string main(const std::string& arg, CAIToolsHelper* helper) + { + json returnValue = json::object(); + + json param = json::parse(arg); + if (!param.is_object()) + { + returnValue["status"] = "error"; + } + else + { + std::string value = json(param).dump(); + std::string code = "window.AscDesktopEditor.generateNew(\"pptx\", \"ai-gen-pptx\", " + json(value).dump() + ");"; + helper->ExecuteJS(code); + + returnValue["status"] = "success"; + } + + return returnValue.dump(); + } +} diff --git a/ChromiumBasedEditors/lib/tools/functions/internal/funcs.h b/ChromiumBasedEditors/lib/tools/functions/internal/funcs.h index 490598f6..a79aacb9 100644 --- a/ChromiumBasedEditors/lib/tools/functions/internal/funcs.h +++ b/ChromiumBasedEditors/lib/tools/functions/internal/funcs.h @@ -5,6 +5,9 @@ #include "../folder_content_reader/main.cpp" #include "../form_field_analyser/main.cpp" #include "../form_field_filler/main.cpp" +#include "../generate_docx/main.cpp" +#include "../generate_form/main.cpp" +#include "../generate_pptx/main.cpp" #include "../recent_files_reader/main.cpp" struct TFuncInstance @@ -26,6 +29,9 @@ public: m_funcs.insert(std::make_pair("folder_content_reader", TFuncInstance(folder_content_reader::description(), folder_content_reader::main))); m_funcs.insert(std::make_pair("form_field_analyser", TFuncInstance(form_field_analyser::description(), form_field_analyser::main))); m_funcs.insert(std::make_pair("form_field_filler", TFuncInstance(form_field_filler::description(), form_field_filler::main))); + m_funcs.insert(std::make_pair("generate_docx", TFuncInstance(generate_docx::description(), generate_docx::main))); + m_funcs.insert(std::make_pair("generate_form", TFuncInstance(generate_form::description(), generate_form::main))); + m_funcs.insert(std::make_pair("generate_pptx", TFuncInstance(generate_pptx::description(), generate_pptx::main))); m_funcs.insert(std::make_pair("recent_files_reader", TFuncInstance(recent_files_reader::description(), recent_files_reader::main))); } }; diff --git a/ChromiumBasedEditors/lib/tools/tools.h b/ChromiumBasedEditors/lib/tools/tools.h index ce6b1bb7..c4343463 100644 --- a/ChromiumBasedEditors/lib/tools/tools.h +++ b/ChromiumBasedEditors/lib/tools/tools.h @@ -65,6 +65,8 @@ public: virtual void OpenTemplate(const std::wstring& path, const std::wstring& name = L"") = 0; virtual void OpenFile(const std::wstring& path) = 0; virtual std::vector GetRecents() = 0; + + virtual void ExecuteJS(const std::string& code) = 0; }; class CFunctions; From a8592d2cf923e126c3fe0a0064108a568f33b0da Mon Sep 17 00:00:00 2001 From: Oleg Korshul Date: Tue, 11 Nov 2025 21:40:00 +0300 Subject: [PATCH 2/7] Add tool for read file content --- .../functions/file_content_reader/main.cpp | 153 +++++++++++++++++- 1 file changed, 149 insertions(+), 4 deletions(-) diff --git a/ChromiumBasedEditors/lib/tools/functions/file_content_reader/main.cpp b/ChromiumBasedEditors/lib/tools/functions/file_content_reader/main.cpp index bacfa313..1d5d980c 100644 --- a/ChromiumBasedEditors/lib/tools/functions/file_content_reader/main.cpp +++ b/ChromiumBasedEditors/lib/tools/functions/file_content_reader/main.cpp @@ -1,5 +1,10 @@ #include "./../internal/base.h" +#include "../../../src/x2t.h" +#include "../../../../../../core/DesktopEditor/common/Directory.h" +#include "../../../../../../core/Common/OfficeFileFormatChecker.h" +//#include "../../../../../../core/DesktopEditor/graphics/BaseThread.h" + namespace file_content_reader { std::string description() @@ -28,13 +33,153 @@ namespace file_content_reader }"; } + class CConverter + { + public: + std::wstring m_sInputFile; + std::wstring m_sOutputFile; + + std::wstring m_sTempDirectory; + int m_nOutputFormat; + + CAIToolsHelper* m_pHelper; + + public: + CConverter() + { + m_sTempDirectory = NSFile::CFileBinary::CreateTempFileWithUniqueName(NSDirectory::GetTempPath(), L"CV"); + if (NSFile::CFileBinary::Exists(m_sTempDirectory)) + NSFile::CFileBinary::Remove(m_sTempDirectory); + + NSDirectory::CreateDirectory(m_sTempDirectory); + + m_sOutputFile = m_sTempDirectory + L"/output"; + } + + ~CConverter() + { + NSDirectory::DeleteDirectory(m_sTempDirectory); + } + + int Convert() + { + CAITools& tools = CAITools::getInstance(); + + NSStringUtils::CStringBuilder oBuilder; + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(m_sInputFile); + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(m_sOutputFile); + oBuilder.WriteString(L""); + + std::wstring sAdditionXml = L""; + if (AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDFA == m_nOutputFormat) + { + m_nOutputFormat = AVS_OFFICESTUDIO_FILE_CROSSPLATFORM_PDF; + sAdditionXml = L"true"; + } + + oBuilder.WriteString(std::to_wstring(m_nOutputFormat)); + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(tools.getFontsDirectory()); + oBuilder.WriteString(L""); + oBuilder.WriteString(L"false"); + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(tools.getFontsDirectory()); + oBuilder.WriteString(L"/AllFonts.js"); + + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(m_sTempDirectory); + oBuilder.WriteString(L""); + + oBuilder.WriteString(L"46"); + + if (!sAdditionXml.empty()) + oBuilder.WriteString(sAdditionXml); + + if (m_nOutputFormat & AVS_OFFICESTUDIO_FILE_IMAGE) + { + oBuilder.WriteString(L"false"); + + if (m_nOutputFormat == AVS_OFFICESTUDIO_FILE_IMAGE_JPG) + oBuilder.WriteString(L"3"); + + oBuilder.WriteString(L""); + } + + oBuilder.WriteString(L""); + + std::wstring sTempFileForParams = m_sTempDirectory + L"/params_simple_converter.xml"; + NSFile::CFileBinary::SaveToFile(sTempFileForParams, oBuilder.GetData(), true); + + CAscApplicationManager manager; + int nReturnCode = NSX2T::Convert(tools.getWorkDirectory() + L"/x2t", sTempFileForParams, &manager, false); + + return nReturnCode; + } + }; + std::string main(const std::string& arg, CAIToolsHelper* helper) { json returnValue = json::object(); returnValue["role"] = "tool"; - returnValue["status"] = "error"; - returnValue["error_message"] = "TODO: method no realized"; - returnValue["content"] = ""; - return returnValue.dump(); + + json param = json::parse(arg); + if (!param.contains("path") || !param["path"].is_string()) + { + returnValue["status"] = "error"; + returnValue["error_message"] = "The file was not opened."; + returnValue["content"] = ""; + return returnValue.dump(); + } + else + { + std::string path = param["path"]; + std::wstring pathW = UTF8_TO_U(path); + + COfficeFileFormatChecker checker; + if (!checker.isOfficeFile(pathW)) + { + returnValue["status"] = "error"; + returnValue["error_message"] = "The file was not opened."; + returnValue["content"] = ""; + return returnValue.dump(); + } + + std::string content; + if (checker.nFileType == AVS_OFFICESTUDIO_FILE_DOCUMENT_MD || + checker.nFileType == AVS_OFFICESTUDIO_FILE_DOCUMENT_TXT || + checker.nFileType == AVS_OFFICESTUDIO_FILE_SPREADSHEET_CSV) + { + NSFile::CFileBinary::ReadAllTextUtf8A(pathW, content); + } + else + { + CConverter converter; + converter.m_pHelper = helper; + converter.m_sInputFile = pathW; + + converter.m_nOutputFormat = AVS_OFFICESTUDIO_FILE_DOCUMENT_TXT; + if (checker.nFileType & AVS_OFFICESTUDIO_FILE_SPREADSHEET) + converter.m_nOutputFormat = AVS_OFFICESTUDIO_FILE_SPREADSHEET_CSV; + + int nResult = converter.Convert(); + + if (0 != nResult) + { + returnValue["status"] = "error"; + returnValue["error_message"] = "The file was not opened."; + returnValue["content"] = ""; + return returnValue.dump(); + } + + returnValue["status"] = "success"; + NSFile::CFileBinary::ReadAllTextUtf8A(converter.m_sOutputFile, content); + } + + returnValue["content"] = content; + + return returnValue.dump(); + } } } From ebf60cee7baa6b411982c6b8af082c3075188e4e Mon Sep 17 00:00:00 2001 From: Oleg Korshul Date: Tue, 11 Nov 2025 22:18:23 +0300 Subject: [PATCH 3/7] Add param for logging urls --- ChromiumBasedEditors/lib/src/applicationmanager_p.h | 8 ++++++++ ChromiumBasedEditors/lib/src/cefview.cpp | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/ChromiumBasedEditors/lib/src/applicationmanager_p.h b/ChromiumBasedEditors/lib/src/applicationmanager_p.h index 3854f3b7..10f7a37a 100644 --- a/ChromiumBasedEditors/lib/src/applicationmanager_p.h +++ b/ChromiumBasedEditors/lib/src/applicationmanager_p.h @@ -1614,6 +1614,9 @@ public: // показывать ли консоль для дебага bool m_bDebugInfoSupport; + // логгировать ли урлы + bool m_bLoggingBrowserUrls; + bool m_bSupportMultiplugins; // экспериментальные возможности @@ -1749,6 +1752,7 @@ public: m_bDebugInfoSupport = false; m_bExperimentalFeatures = false; m_bSupportMultiplugins = false; + m_bLoggingBrowserUrls = false; m_bIsUseExternalMessageLoop = false; m_pExternalMessageLoop = NULL; @@ -2009,6 +2013,10 @@ public: if (pairComplexPlugins != _map->end() && "1" == pairComplexPlugins->second) m_bSupportMultiplugins = true; + std::map::iterator pairLogUrls = _map->find("log-browser-urls"); + if (pairLogUrls != _map->end() && "1" == pairLogUrls->second) + m_bLoggingBrowserUrls = true; + if (!NSCommon::CSystemWindowScale::IsInit()) { std::map::iterator pairUseSystemScale = _map->find("system-scale"); diff --git a/ChromiumBasedEditors/lib/src/cefview.cpp b/ChromiumBasedEditors/lib/src/cefview.cpp index a60be587..2e00b83e 100644 --- a/ChromiumBasedEditors/lib/src/cefview.cpp +++ b/ChromiumBasedEditors/lib/src/cefview.cpp @@ -2271,6 +2271,15 @@ public: { std::wstring sUrl = request->GetURL().ToWString(); + if (m_pParent->m_pInternal->m_pManager->m_pInternal->m_bLoggingBrowserUrls) + { + CCefView* pMainView = m_pParent->m_pInternal->m_pManager->m_pInternal->GetViewForSystemMessages(); + if (pMainView) + { + pMainView->ExecuteInAllFrames("console.log(\"" + U_TO_UTF8(sUrl) + "\");", true); + } + } + if (0 == sUrl.find(L"mailto")) { // disable navigation From 49ac56c63ea36886c99f5efb91e780ff3752dda4 Mon Sep 17 00:00:00 2001 From: Oleg Korshul Date: Wed, 12 Nov 2025 11:10:40 +0300 Subject: [PATCH 4/7] Fix bug with check urls with regex --- ChromiumBasedEditors/lib/src/cefview.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ChromiumBasedEditors/lib/src/cefview.cpp b/ChromiumBasedEditors/lib/src/cefview.cpp index 2e00b83e..ac4fbac7 100644 --- a/ChromiumBasedEditors/lib/src/cefview.cpp +++ b/ChromiumBasedEditors/lib/src/cefview.cpp @@ -1979,7 +1979,7 @@ public: if (0 == sTest.find(L"regex:")) { std::wstring sTestRegex = sTest.substr(6); - boost::wregex oRegEx(sTestRegex); + boost::wregex oRegEx(sTestRegex, boost::regex::icase); if (boost::regex_search(sUrl, oRegEx)) return true; } @@ -2242,6 +2242,16 @@ public: std::wstring sFrameUrl = L""; if (frame) sFrameUrl = frame->GetURL().ToWString(); + + if (m_pParent->m_pInternal->m_pManager->m_pInternal->m_bLoggingBrowserUrls) + { + CCefView* pMainView = m_pParent->m_pInternal->m_pManager->m_pInternal->GetViewForSystemMessages(); + if (pMainView) + { + pMainView->ExecuteInAllFrames("console.log(\"" + target_url.ToString() + "\");", true); + } + } + CheckPopup(target_url.ToWString(), false, (WOD_NEW_BACKGROUND_TAB == target_disposition) ? true : false, false, sFrameUrl); return true; } From 195e9ad27938f9fe84716a4dde153034af41347b Mon Sep 17 00:00:00 2001 From: "Oleg.Korshul" Date: Wed, 12 Nov 2025 23:48:28 +0300 Subject: [PATCH 5/7] Fix path env (mac/linux) --- .../cefwrapper/external_process_with_childs.h | 70 +++++++++++++++---- 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/ChromiumBasedEditors/lib/src/cefwrapper/external_process_with_childs.h b/ChromiumBasedEditors/lib/src/cefwrapper/external_process_with_childs.h index d30245d2..f87840fc 100644 --- a/ChromiumBasedEditors/lib/src/cefwrapper/external_process_with_childs.h +++ b/ChromiumBasedEditors/lib/src/cefwrapper/external_process_with_childs.h @@ -188,7 +188,7 @@ namespace NSProcesses { std::string lineBuf; char buf[4096]; - + #ifdef _WIN32 DWORD n; #else @@ -240,21 +240,49 @@ namespace NSProcesses } #ifdef _LINUX + std::string getPathVariable() + { + std::string pathEnv = ""; + + const char* pathEnvPtr = std::getenv("PATH"); + if (pathEnvPtr) + pathEnv = std::string(pathEnvPtr); + + std::string systemPath = ""; + FILE* fp = popen("bash -l -c 'echo $PATH'", "r"); + if (fp) + { + char buffer[1024]; + while (fgets(buffer, sizeof(buffer), fp)) + systemPath += buffer; + fclose(fp); + } + + if (!systemPath.empty() && systemPath[systemPath.size() - 1] == '\n') + systemPath.pop_back(); + + std::string pathValue = systemPath; + if (!pathEnv.empty()) + { + if (!pathValue.empty()) + pathValue += ":"; + pathValue += pathEnv; + } + + if (!pathValue.empty()) + pathValue += ":"; + + pathValue += "/usr/bin:/bin:/usr/local/bin:/opt/homebrew/bin"; + return pathValue; + } + std::string findBinary(const std::string& cmd) { if (!cmd.empty() && access(cmd.c_str(), X_OK) == 0) return cmd; - const char* pathEnv = std::getenv("PATH"); - if (!pathEnv) - return cmd; - - std::string sPathEnv(pathEnv); - if (!sPathEnv.empty()) - sPathEnv += ":"; - - sPathEnv += "/usr/bin:/bin:/usr/local/bin:/opt/homebrew/bin"; - + std::string sPathEnv = getPathVariable(); + std::istringstream iss(sPathEnv); std::string dir; while (std::getline(iss, dir, ':')) @@ -366,7 +394,9 @@ namespace NSProcesses for (auto& s : args) argv.push_back(const_cast(s.c_str())); argv.push_back(nullptr); - + + std::string systemPath = getPathVariable(); + std::map mergedEnv; for (char **env = environ; *env; ++env) { @@ -374,7 +404,17 @@ namespace NSProcesses auto pos = s.find('='); if (pos != std::string::npos) { - mergedEnv[s.substr(0, pos)] = s.substr(pos + 1); + std::string keyName = s.substr(0, pos); + std::string value = s.substr(pos + 1); + + if (keyName == "PATH" && !systemPath.empty()) + { + if (!value.empty()) + value += ":"; + value += systemPath; + } + + mergedEnv[keyName] = value; } } for (auto &kv : m_env) @@ -412,11 +452,11 @@ namespace NSProcesses std::thread t_out = std::thread([this]() { - readOutLoop(m_stdoutPipe[0], StreamType::StdOut); + readOutLoop(m_stdoutPipe[0], StreamType::StdOut); }); std::thread t_err = std::thread([this]() { - readOutLoop(m_stderrPipe[0], StreamType::StdErr); + readOutLoop(m_stderrPipe[0], StreamType::StdErr); }); #endif From d4d5ffd14144689bb416c3ff789b64ccab56baad Mon Sep 17 00:00:00 2001 From: "Oleg.Korshul" Date: Thu, 13 Nov 2025 00:43:15 +0300 Subject: [PATCH 6/7] Fix previous commit --- .../cefwrapper/external_process_with_childs.h | 59 +++++++++++++++---- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/ChromiumBasedEditors/lib/src/cefwrapper/external_process_with_childs.h b/ChromiumBasedEditors/lib/src/cefwrapper/external_process_with_childs.h index f87840fc..07c7bb10 100644 --- a/ChromiumBasedEditors/lib/src/cefwrapper/external_process_with_childs.h +++ b/ChromiumBasedEditors/lib/src/cefwrapper/external_process_with_childs.h @@ -240,6 +240,52 @@ namespace NSProcesses } #ifdef _LINUX + std::string getShellPath() + { + std::array buffer; + std::string result; + + const char* shell = getenv("SHELL"); + if (!shell) { + #ifdef _MAC + shell = "/bin/zsh"; + #else + shell = "/bin/bash"; + #endif + } + + std::string shellPath = shell; + std::string cmd; + + // fish + if (shellPath.find("fish") != std::string::npos) + { + cmd = std::string(shell) + " -l -c 'echo $PATH' 2>/dev/null"; + } + else + { + cmd = std::string(shell) + " -l -i -c 'echo $PATH' 2>/dev/null"; + } + + FILE* pipe = popen(cmd.c_str(), "r"); + if (!pipe) + return ""; + + while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) + { + result += buffer.data(); + } + + pclose(pipe); + + if (!result.empty() && result.back() == '\n') + { + result.pop_back(); + } + + return result; + } + std::string getPathVariable() { std::string pathEnv = ""; @@ -248,18 +294,7 @@ namespace NSProcesses if (pathEnvPtr) pathEnv = std::string(pathEnvPtr); - std::string systemPath = ""; - FILE* fp = popen("bash -l -c 'echo $PATH'", "r"); - if (fp) - { - char buffer[1024]; - while (fgets(buffer, sizeof(buffer), fp)) - systemPath += buffer; - fclose(fp); - } - - if (!systemPath.empty() && systemPath[systemPath.size() - 1] == '\n') - systemPath.pop_back(); + std::string systemPath = getShellPath(); std::string pathValue = systemPath; if (!pathEnv.empty()) From 7206b1267cb2ef09ae7a65256d0136d029a57692 Mon Sep 17 00:00:00 2001 From: Oleg Korshul Date: Thu, 13 Nov 2025 02:19:41 +0300 Subject: [PATCH 7/7] Fix find binary on windows --- .../cefwrapper/client_renderer_wrapper.cpp | 7 + .../cefwrapper/external_process_with_childs.h | 202 +++++++++++++++++- 2 files changed, 203 insertions(+), 6 deletions(-) diff --git a/ChromiumBasedEditors/lib/src/cefwrapper/client_renderer_wrapper.cpp b/ChromiumBasedEditors/lib/src/cefwrapper/client_renderer_wrapper.cpp index 395f979a..bfa5cbca 100644 --- a/ChromiumBasedEditors/lib/src/cefwrapper/client_renderer_wrapper.cpp +++ b/ChromiumBasedEditors/lib/src/cefwrapper/client_renderer_wrapper.cpp @@ -4604,6 +4604,13 @@ window.AscDesktopEditor.CallInFrame(\"" + } else if (name == "_createProcess") { + std::string sCurrentUrl = CefV8Context::GetCurrentContext()->GetFrame()->GetURL().ToString(); + if (0 != sCurrentUrl.find("onlyoffice://")) + { + retval = CefV8Value::CreateInt(-1); + return true; + } + if (!m_external_processes) m_external_processes = new NSProcesses::CProcessManager(this); diff --git a/ChromiumBasedEditors/lib/src/cefwrapper/external_process_with_childs.h b/ChromiumBasedEditors/lib/src/cefwrapper/external_process_with_childs.h index 07c7bb10..52940db4 100644 --- a/ChromiumBasedEditors/lib/src/cefwrapper/external_process_with_childs.h +++ b/ChromiumBasedEditors/lib/src/cefwrapper/external_process_with_childs.h @@ -6,6 +6,7 @@ #include #include #include +#include #ifdef _WIN32 #include @@ -16,7 +17,6 @@ #include #include #include -#include #include #endif @@ -32,6 +32,7 @@ extern char **environ; #include "../../../../../core/DesktopEditor/common/File.h" #include "../../../../../core/DesktopEditor/graphics/TemporaryCS.h" #include "../../../../../core/DesktopEditor/graphics/BaseThread.h" +#include "../../../../../core/DesktopEditor/common/SystemUtils.h" namespace NSProcesses { @@ -239,6 +240,181 @@ namespace NSProcesses m_callback->process_callback(m_id, type, lineBuf); } +#ifdef _WIN32 + std::wstring getPathVariable() + { + std::wstring pathEnv = NSSystemUtils::GetEnvVariable(L"PATH"); + std::wstring systemEnv = L""; + std::wstring userEnv = L""; + + if (true) + { + HKEY hKey; + if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Environment", 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + DWORD size = 0; + RegQueryValueExW(hKey, L"PATH", nullptr, nullptr, nullptr, &size); + + if (size > 0) + { + int charCount = (size / sizeof(wchar_t)) + 1; + wchar_t* buffer = new wchar_t[charCount]; + if (RegQueryValueExW(hKey, L"PATH", nullptr, nullptr, (LPBYTE)buffer, &size) == ERROR_SUCCESS) + { + buffer[charCount - 1] = '\0'; + userEnv = std::wstring(buffer); + } + delete [] buffer; + } + + RegCloseKey(hKey); + } + } + + if (true) + { + HKEY hKey; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + DWORD size = 0; + RegQueryValueExW(hKey, L"PATH", nullptr, nullptr, nullptr, &size); + + if (size > 0) + { + int charCount = (size / sizeof(wchar_t)) + 1; + wchar_t* buffer = new wchar_t[charCount]; + if (RegQueryValueExW(hKey, L"PATH", nullptr, nullptr, (LPBYTE)buffer, &size) == ERROR_SUCCESS) + { + buffer[charCount - 1] = '\0'; + systemEnv = std::wstring(buffer); + } + delete [] buffer; + } + + RegCloseKey(hKey); + } + } + + std::wstring result; + + if (!userEnv.empty()) + result = userEnv; + + if (!systemEnv.empty()) + { + if (!result.empty()) + result += L";"; + + result += systemEnv; + } + + if (!pathEnv.empty()) + { + if (!result.empty()) + result += L";"; + + result += pathEnv; + } + + return result; + } + + std::map getEnv() + { + std::map env; + + wchar_t* envStrings = GetEnvironmentStringsW(); + if (!envStrings) + return env; + + wchar_t* current = envStrings; + + while (*current != L'\0') + { + size_t len = wcslen(current) + 1; // +1 for \0 + + std::wstring all(current, len - 1); + auto pos = all.find('='); + if (pos != std::wstring::npos) + { + std::wstring keyName = all.substr(0, pos); + std::wstring value = all.substr(pos + 1); + + if (keyName == L"PATH" || keyName == L"Path") + { + std::wstring systemPath = getPathVariable(); + + if (!systemPath.empty()) + { + if (!value.empty()) + value += L";"; + value += systemPath; + } + } + + if (!keyName.empty()) + env[keyName] = value; + } + + current += len; + } + + FreeEnvironmentStringsW(envStrings); + + return env; + } + + std::wstring findBinary(const std::wstring& cmd) + { + if (cmd.empty()) + return cmd; + + std::vector extensions = {L"", L".exe", L".bat"}; + + if (true) + { + for (const auto& ext : extensions) + { + std::wstring test = cmd + ext; + DWORD attr = GetFileAttributesW(test.c_str()); + + if (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY)) + return test; + } + } + + std::wstring pathEnv = getPathVariable(); + std::wistringstream iss(pathEnv); + std::wstring dir; + + while (std::getline(iss, dir, L';')) + { + if (dir.empty()) + continue; + + if (!dir.empty() && dir.front() == '"') + dir = dir.substr(1); + if (!dir.empty() && dir.back() == '"') + dir.pop_back(); + + if (!dir.empty() && dir.back() != '\\' && dir.back() != '/') + dir += L"\\"; + + // Проверяем с разными расширениями + for (const auto& ext : extensions) + { + std::wstring test = dir + cmd + ext; + DWORD attr = GetFileAttributesW(test.c_str()); + + if (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY)) + return test; + } + } + + return cmd; + } +#endif + #ifdef _LINUX std::string getShellPath() { @@ -352,21 +528,35 @@ namespace NSProcesses si.hStdError = m_hStdErrWr; si.dwFlags |= STARTF_USESTDHANDLES; - std::wstring envBlock; + std::map env = getEnv(); for (auto& kv : m_env) { - envBlock += (UTF8_TO_U((kv.first)) + L"=" + UTF8_TO_U((kv.second))); + env[UTF8_TO_U((kv.first))] = UTF8_TO_U((kv.second)); + } + + env[L"LANG"] = L"C.UTF-8"; + + std::wstring envBlock; + for (auto& kv : env) + { + envBlock += kv.first + L"=" + kv.second; envBlock.push_back(L'\0'); } - envBlock += L"LANG=C.UTF-8\0"; envBlock.push_back(L'\0'); std::wstring commandW = UTF8_TO_U(m_command); - if (!CreateProcessW(nullptr, (LPWSTR)commandW.c_str(), nullptr, nullptr, TRUE, CREATE_SUSPENDED | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, + std::wstring prog = commandW; + std::wstring::size_type posProg = commandW.find(L" "); + if (posProg != std::wstring::npos) + prog = commandW.substr(0, posProg); + prog = findBinary(prog); + if (prog == commandW) + prog = L""; + + if (!CreateProcessW(prog.empty() ? nullptr : prog.c_str(), (LPWSTR)commandW.c_str(), nullptr, nullptr, TRUE, CREATE_SUSPENDED | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, (LPVOID)(envBlock.c_str()), nullptr, &si, &m_pi)) { DWORD dwError = GetLastError(); - m_callback->process_callback(m_id, StreamType::Terminate, ""); return; }