UP 优化调用实现 简单颜色匹配优化 加入主题切换

main
jixieshi 2025-09-08 23:34:24 +08:00
parent 0ab3543aa4
commit d2113117cc
4 changed files with 131 additions and 173 deletions

View File

@ -127,10 +127,10 @@ private:
mutable std::mutex encoding_mutex_; mutable std::mutex encoding_mutex_;
OutputEncoding output_encoding_; OutputEncoding output_encoding_;
// 新增:工作目录相关 // 工作目录相关
mutable std::mutex working_dir_mutex_; mutable std::mutex working_dir_mutex_;
std::string working_directory_; std::string working_directory_;
bool use_auto_working_dir_; bool use_auto_working_dir_;
}; };
#endif // CLIPROCESS_H #endif // CLIPROCESS_H

View File

@ -7,6 +7,7 @@ AppState::AppState() :
show_main_window(true), show_main_window(true),
auto_start(false), auto_start(false),
auto_scroll_logs(true), auto_scroll_logs(true),
enable_colored_logs(true),
max_log_lines(1000), max_log_lines(1000),
stop_timeout_ms(5000), stop_timeout_ms(5000),
use_stop_command(false), use_stop_command(false),
@ -285,4 +286,4 @@ void AppState::ApplySettings() {
// 新增:应用输出编码设置 // 新增:应用输出编码设置
cli_process.SetOutputEncoding(output_encoding); cli_process.SetOutputEncoding(output_encoding);
} }

View File

@ -26,7 +26,7 @@ CLIProcess::CLIProcess() {
max_log_lines_ = 1000; max_log_lines_ = 1000;
stop_timeout_ms_ = 5000; stop_timeout_ms_ = 5000;
output_encoding_ = OutputEncoding::AUTO_DETECT; output_encoding_ = OutputEncoding::AUTO_DETECT;
use_auto_working_dir_ = true; // 新增:默认启用自动工作目录 use_auto_working_dir_ = false; // 自动工作目录
} }
CLIProcess::~CLIProcess() { CLIProcess::~CLIProcess() {
@ -383,17 +383,17 @@ void CLIProcess::Start(const std::string& command) {
Stop(); Stop();
// 确定工作目录 // 确定工作目录
std::string working_dir; std::wstring working_dir;
{ {
std::lock_guard<std::mutex> lock(working_dir_mutex_); std::lock_guard<std::mutex> lock(working_dir_mutex_);
if (use_auto_working_dir_) { if (use_auto_working_dir_) {
working_dir = ExtractDirectoryFromCommand(command); working_dir = StringToWide(ExtractDirectoryFromCommand(command));
if (working_dir.empty()) { if (working_dir.empty()) {
working_dir = std::filesystem::current_path().string(); working_dir = StringToWide(std::filesystem::current_path().string());
} }
// AddLog("自动检测工作目录: " + working_dir); // AddLog("自动检测工作目录: " + working_dir);
} else { } else {
working_dir = working_directory_; working_dir = StringToWide(working_directory_);
if (!working_dir.empty()) { if (!working_dir.empty()) {
// AddLog("使用指定工作目录: " + working_dir); // AddLog("使用指定工作目录: " + working_dir);
} }
@ -401,192 +401,141 @@ void CLIProcess::Start(const std::string& command) {
} }
#ifdef _WIN32 #ifdef _WIN32
SECURITY_ATTRIBUTES saAttr; SECURITY_ATTRIBUTES sa;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); sa.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE; sa.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = nullptr; sa.lpSecurityDescriptor = nullptr;
HANDLE hReadTmp = nullptr; if (!CreatePipe(&hReadPipe_, &hWritePipe_, &sa, 0)) {
HANDLE hWriteTmp = nullptr; AddLog("创建输出管道失败");
if (!CreatePipe(&hReadTmp, &hWriteTmp, &saAttr, 0)) {
return;
}
if (!SetHandleInformation(hReadTmp, HANDLE_FLAG_INHERIT, 0)) {
CloseHandle(hReadTmp);
CloseHandle(hWriteTmp);
return; return;
} }
HANDLE hReadTmp_stdin = nullptr; if (!CreatePipe(&hReadPipe_stdin_, &hWritePipe_stdin_, &sa, 0)) {
HANDLE hWriteTmp_stdin = nullptr; AddLog("创建输入管道失败");
if (!CreatePipe(&hReadTmp_stdin, &hWriteTmp_stdin, &saAttr, 0)) { CloseHandle(hReadPipe_);
CloseHandle(hReadTmp); CloseHandle(hWritePipe_);
CloseHandle(hWriteTmp);
return;
}
if (!SetHandleInformation(hWriteTmp_stdin, HANDLE_FLAG_INHERIT, 0)) {
CloseHandle(hReadTmp);
CloseHandle(hWriteTmp);
CloseHandle(hReadTmp_stdin);
CloseHandle(hWriteTmp_stdin);
return; return;
} }
STARTUPINFOA siStartInfo; STARTUPINFO si;
ZeroMemory(&siStartInfo, sizeof(STARTUPINFOA)); ZeroMemory(&si, sizeof(si));
siStartInfo.cb = sizeof(STARTUPINFOA); si.cb = sizeof(si);
siStartInfo.hStdError = hWriteTmp; si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
siStartInfo.hStdOutput = hWriteTmp; si.hStdOutput = hWritePipe_;
siStartInfo.hStdInput = hReadTmp_stdin; si.hStdError = hWritePipe_;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES; si.hStdInput = hReadPipe_stdin_;
si.wShowWindow = SW_HIDE;
ZeroMemory(&pi_, sizeof(pi_));
PROCESS_INFORMATION piProcInfo; // 转换命令为宽字符
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); std::wstring wcmd = StringToWide(command);
// Prepare environment block // CreateProcess需要可修改的字符串
std::string env_block; std::vector<wchar_t> cmdBuffer(wcmd.begin(), wcmd.end());
{ cmdBuffer.push_back(L'\0');
std::lock_guard<std::mutex> lock(env_mutex_);
for (const auto& kv : environment_variables_) {
env_block += kv.first + "=" + kv.second + '\0';
}
env_block += '\0';
}
// 处理工作目录 - 支持Unicode路径 // 使用Windows API设置环境变量
const char* working_dir_ptr = nullptr; std::vector<std::pair<std::string, std::string>> originalEnvVars;
std::wstring working_dir_wide; bool envVarsSet = false;
if (!working_dir.empty()) { if (!environment_variables_.empty()) {
// 验证工作目录是否存在 envVarsSet = true;
if (!DirectoryExists(working_dir)) {
// AddLog("警告: 工作目录不存在,使用当前目录: " + working_dir);
working_dir = std::filesystem::current_path().string();
}
// 转换为绝对路径 for (const auto &pair: environment_variables_) {
working_dir = GetAbsolutePath(working_dir); if (!pair.first.empty()) {
working_dir_ptr = working_dir.c_str(); // 保存原始值(如果存在)
DWORD bufferSize = GetEnvironmentVariableA(pair.first.c_str(), nullptr, 0);
if (bufferSize > 0) {
// 变量存在,保存原始值
std::vector<char> buffer(bufferSize);
if (GetEnvironmentVariableA(pair.first.c_str(), buffer.data(), bufferSize) > 0) {
originalEnvVars.emplace_back(pair.first, std::string(buffer.data()));
} else {
originalEnvVars.emplace_back(pair.first, "");
}
} else {
// 变量不存在,标记为新变量(使用空字符串表示原来不存在)
originalEnvVars.emplace_back(pair.first, "");
}
// 如果路径包含非ASCII字符需要使用CreateProcessW // 设置新的环境变量值
bool hasNonAscii = false; if (SetEnvironmentVariableA(pair.first.c_str(), pair.second.c_str())) {
for (char c : working_dir) { // AddLog("设置环境变量: " + pair.first + "=" + pair.second);
if (static_cast<unsigned char>(c) > 127) { } else {
hasNonAscii = true; AddLog("设置环境变量失败: " + pair.first + " (错误代码: " + std::to_string(GetLastError()) + ")");
break;
}
}
if (hasNonAscii) {
// 转换为宽字符用于CreateProcessW
int wideSize = MultiByteToWideChar(CP_UTF8, 0, working_dir.c_str(), -1, nullptr, 0);
if (wideSize > 0) {
working_dir_wide.resize(wideSize);
MultiByteToWideChar(CP_UTF8, 0, working_dir.c_str(), -1, &working_dir_wide[0], wideSize);
}
}
}
BOOL bSuccess = FALSE;
// 如果工作目录包含Unicode字符使用CreateProcessW
if (!working_dir_wide.empty()) {
// 转换命令为宽字符
int cmdWideSize = MultiByteToWideChar(CP_UTF8, 0, command.c_str(), -1, nullptr, 0);
if (cmdWideSize > 0) {
std::wstring command_wide(cmdWideSize, L'\0');
MultiByteToWideChar(CP_UTF8, 0, command.c_str(), -1, &command_wide[0], cmdWideSize);
// 转换环境变量为宽字符
std::wstring env_block_wide;
if (!env_block.empty()) {
int envWideSize = MultiByteToWideChar(CP_UTF8, 0, env_block.c_str(), static_cast<int>(env_block.size()), nullptr, 0);
if (envWideSize > 0) {
env_block_wide.resize(envWideSize);
MultiByteToWideChar(CP_UTF8, 0, env_block.c_str(), static_cast<int>(env_block.size()), &env_block_wide[0], envWideSize);
} }
} }
STARTUPINFOW siStartInfoW;
ZeroMemory(&siStartInfoW, sizeof(STARTUPINFOW));
siStartInfoW.cb = sizeof(STARTUPINFOW);
siStartInfoW.hStdError = hWriteTmp;
siStartInfoW.hStdOutput = hWriteTmp;
siStartInfoW.hStdInput = hReadTmp_stdin;
siStartInfoW.dwFlags |= STARTF_USESTDHANDLES;
bSuccess = CreateProcessW(
nullptr,
&command_wide[0],
nullptr,
nullptr,
TRUE,
CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
env_block_wide.empty() ? nullptr : (LPVOID)env_block_wide.data(),
working_dir_wide.c_str(),
&siStartInfoW,
&piProcInfo);
} }
// AddLog("环境变量设置完成,数量: " + std::to_string(environment_variables_.size()));
} else { } else {
// 使用ANSI版本 AddLog("未设置自定义环境变量,使用默认环境 PWD:" + WideToString(working_dir));
bSuccess = CreateProcessA(
nullptr,
const_cast<char*>(command.c_str()),
nullptr,
nullptr,
TRUE,
CREATE_NO_WINDOW,
env_block.empty() ? nullptr : static_cast<LPVOID>(env_block.data()),
working_dir_ptr,
&siStartInfo,
&piProcInfo);
} }
CloseHandle(hWriteTmp); BOOL result = CreateProcess(
CloseHandle(hReadTmp_stdin); nullptr, // lpApplicationName
cmdBuffer.data(), // lpCommandLine
nullptr, // lpProcessAttributes
nullptr, // lpThreadAttributes
TRUE, // bInheritHandles
CREATE_NO_WINDOW, // dwCreationFlags
nullptr, // lpEnvironment (使用nullptr让子进程继承当前环境)
working_dir.empty() ? nullptr : working_dir.data(), // lpCurrentDirectory
&si, // lpStartupInfo
&pi_ // lpProcessInformation
);
if (!bSuccess) { // 恢复原始环境变量
DWORD error = GetLastError(); if (envVarsSet) {
CloseHandle(hReadTmp); for (const auto &pair: originalEnvVars) {
CloseHandle(hWriteTmp_stdin); if (pair.second.empty()) {
AddLog("启动进程失败,错误代码: " + std::to_string(error)); // 原来不存在,删除变量
SetEnvironmentVariableA(pair.first.c_str(), nullptr);
// 提供更详细的错误信息 } else {
switch (error) { // 恢复原始值
case ERROR_FILE_NOT_FOUND: SetEnvironmentVariableA(pair.first.c_str(), pair.second.c_str());
AddLog("错误: 找不到指定的文件或程序"); }
break;
case ERROR_PATH_NOT_FOUND:
AddLog("错误: 找不到指定的路径");
break;
case ERROR_ACCESS_DENIED:
AddLog("错误: 访问被拒绝,可能需要管理员权限");
break;
case ERROR_INVALID_PARAMETER:
AddLog("错误: 无效的参数");
break;
default:
AddLog("错误: 未知错误,请检查命令和路径是否正确");
break;
} }
return;
} }
CloseProcessHandles(); if (result) {
AddLog("进程已启动: " + command + " PID: " + std::to_string(pi_.dwProcessId));
pi_ = piProcInfo; CloseHandle(hWritePipe_);
hReadPipe_ = hReadTmp; CloseHandle(hReadPipe_stdin_);
hWritePipe_stdin_ = hWriteTmp_stdin; hWritePipe_ = nullptr;
hReadPipe_stdin_ = nullptr;
AddLog("进程已启动PID: " + std::to_string(piProcInfo.dwProcessId)); output_thread_ = std::thread([this]() {
if (!working_dir.empty()) { ReadOutput();
AddLog("工作目录: " + working_dir); });
} else {
DWORD err = GetLastError();
// 获取详细的错误信息
LPWSTR messageBuffer = nullptr;
size_t size = FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR) &messageBuffer, 0, nullptr);
std::string errorMsg = "CreateProcess 失败 (错误代码: " + std::to_string(err) + ")";
if (messageBuffer) {
std::wstring wErrorMsg(messageBuffer);
errorMsg += " - " + WideToString(wErrorMsg);
LocalFree(messageBuffer);
}
AddLog(errorMsg);
// 清理资源
CloseHandle(hReadPipe_);
CloseHandle(hWritePipe_);
CloseHandle(hReadPipe_stdin_);
CloseHandle(hWritePipe_stdin_);
hReadPipe_ = hWritePipe_ = hReadPipe_stdin_ = hWritePipe_stdin_ = nullptr;
} }
// Start output reading thread
output_thread_ = std::thread(&CLIProcess::ReadOutput, this);
#else #else
// Unix/Linux implementation // Unix/Linux implementation
int pipe_out[2]; int pipe_out[2];

View File

@ -272,7 +272,12 @@ void Manager::RenderMenuBar() {
RenderLayoutMenu(); RenderLayoutMenu();
ImGui::EndMenu(); ImGui::EndMenu();
} }
if (ImGui::BeginMenu("主题")) {
if (ImGui::MenuItem("暗黑(Dark)")) { ImGui::StyleColorsDark(); }
if (ImGui::MenuItem("明亮(Light)")) { ImGui::StyleColorsLight(); }
if (ImGui::MenuItem("经典(Classic)")) { ImGui::StyleColorsClassic(); }
ImGui::EndMenu();
}
ImGui::EndMenuBar(); ImGui::EndMenuBar();
} }
} }
@ -994,11 +999,14 @@ void Manager::RenderLogPanel() {
ImVec4 Manager::GetLogLevelColor(const std::string& log) { ImVec4 Manager::GetLogLevelColor(const std::string& log) {
// 简单的日志级别颜色区分 // 简单的日志级别颜色区分
if (log.find("[ERROR]") != std::string::npos || log.find("error") != std::string::npos) { if (log.find("错误") != std::string::npos || log.find("[E]") != std::string::npos ||
log.find("[ERROR]") != std::string::npos || log.find("error") != std::string::npos) {
return ImVec4(1.0f, 0.4f, 0.4f, 1.0f); // 红色 return ImVec4(1.0f, 0.4f, 0.4f, 1.0f); // 红色
} else if (log.find("[WARN]") != std::string::npos || log.find("warning") != std::string::npos) { } else if (log.find("警告") != std::string::npos || log.find("[W]") != std::string::npos ||
log.find("[WARN]") != std::string::npos || log.find("warning") != std::string::npos) {
return ImVec4(1.0f, 1.0f, 0.4f, 1.0f); // 黄色 return ImVec4(1.0f, 1.0f, 0.4f, 1.0f); // 黄色
} else if (log.find("[INFO]") != std::string::npos || log.find("info") != std::string::npos) { } else if (log.find("信息") != std::string::npos || log.find("[I]") != std::string::npos ||
log.find("[INFO]") != std::string::npos || log.find("info") != std::string::npos) {
return ImVec4(0.4f, 1.0f, 0.4f, 1.0f); // 绿色 return ImVec4(0.4f, 1.0f, 0.4f, 1.0f); // 绿色
} }
return ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // 默认白色 return ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // 默认白色
@ -1793,4 +1801,4 @@ extern "C" {
void* GetMacAppDelegate(); void* GetMacAppDelegate();
void* GetMacTrayIcon(); void* GetMacTrayIcon();
} }
#endif #endif