diff --git a/src/ConEmu/About.h b/src/ConEmu/About.h index 0bc39f992c..316af53ab8 100644 --- a/src/ConEmu/About.h +++ b/src/ConEmu/About.h @@ -259,6 +259,11 @@ _DBGHLP(L"-ZoneId - Try to drop :Zone.Identifier without confirmation.\r\n") \ L"Detach([])\r\n" \ L" - Detach active RealConsole from ConEmu\r\n" \ L" Flags=1: don't show confirm message\r\n" \ + L"EnvironmentReload\r\n" \ + L" - Reload environment variables from system registry\r\n" \ + L"EnvironmentList\r\n" \ + L" - Print actual `name=value` environment pairs\r\n" \ + L" Variables from ConEmu settings go after system ones\r\n" \ L"FindEditor(\"\")\r\n" \ L"FindViewer(\"\")\r\n" \ L"FindFarWindow(,\"\")\r\n" \ diff --git a/src/ConEmu/ConEmu.cpp b/src/ConEmu/ConEmu.cpp index 7f082b65fc..d69d5b4179 100644 --- a/src/ConEmu/ConEmu.cpp +++ b/src/ConEmu/ConEmu.cpp @@ -8292,9 +8292,17 @@ void CConEmuMain::ReloadEnvironmentVariables() } } + std::lock_guard lock(saved_environment_mutex_); saved_environment_ = new_environment; } +std::shared_ptr CConEmuMain::GetEnvironmentVariables() const +{ + std::lock_guard lock(saved_environment_mutex_); + std::shared_ptr data = saved_environment_; + return data; +} + void CConEmuMain::OnGlobalSettingsChanged() { UpdateGuiInfoMapping(); diff --git a/src/ConEmu/ConEmu.h b/src/ConEmu/ConEmu.h index daf857e08a..82f7adab88 100644 --- a/src/ConEmu/ConEmu.h +++ b/src/ConEmu/ConEmu.h @@ -88,6 +88,8 @@ struct ConsoleInfoArg }; #include +#include + #include "DwmHelper.h" #include "TaskBar.h" #include "FrameHolder.h" @@ -850,8 +852,10 @@ class CConEmuMain public: void ReloadEnvironmentVariables(); + std::shared_ptr GetEnvironmentVariables() const; private: std::shared_ptr saved_environment_; + mutable std::mutex saved_environment_mutex_; }; // Message Logger diff --git a/src/ConEmu/Macro.cpp b/src/ConEmu/Macro.cpp index 08f91443ed..339a662ef6 100644 --- a/src/ConEmu/Macro.cpp +++ b/src/ConEmu/Macro.cpp @@ -31,27 +31,32 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define SHOWDEBUGSTR #include "Header.h" +#include "../common/EnvVar.h" #include "../common/MGuiMacro.h" #include "../common/MStrEsc.h" +#include "../common/ProcessSetEnv.h" #include "../common/WFiles.h" -#include "RealConsole.h" -#include "VirtualConsole.h" -#include "Options.h" -#include "OptionsClass.h" -#include "TrayIcon.h" +#include + +#include "AboutDlg.h" +#include "Attach.h" #include "ConEmu.h" -#include "TabBar.h" -#include "TrayIcon.h" #include "ConEmuPipe.h" #include "Macro.h" -#include "VConGroup.h" #include "Menu.h" -#include "AboutDlg.h" -#include "Attach.h" -#include "SetDlgButtons.h" +#include "Options.h" +#include "OptionsClass.h" +#include "RealConsole.h" #include "SetCmdTask.h" #include "SetColorPalette.h" +#include "SetDlgButtons.h" +#include "SystemEnvironment.h" +#include "TabBar.h" +#include "TrayIcon.h" +#include "TrayIcon.h" +#include "VConGroup.h" +#include "VirtualConsole.h" /* ********************************* */ @@ -153,6 +158,9 @@ namespace ConEmuMacro LPWSTR Debug(GuiMacro* p, CRealConsole* apRCon, bool abFromPlugin); // Detach LPWSTR Detach(GuiMacro* p, CRealConsole* apRCon, bool abFromPlugin); + // Environment variables + LPWSTR EnvironmentReload(GuiMacro* p, CRealConsole* apRCon, bool abFromPlugin); + LPWSTR EnvironmentList(GuiMacro* p, CRealConsole* apRCon, bool abFromPlugin); // Найти окно и активировать его. // int nWindowType/*Panels=1, Viewer=2, Editor=3*/, LPWSTR asName LPWSTR FindEditor(GuiMacro* p, CRealConsole* apRCon, bool abFromPlugin); LPWSTR FindFarWindow(GuiMacro* p, CRealConsole* apRCon, bool abFromPlugin); @@ -279,6 +287,8 @@ namespace ConEmuMacro {Copy, {L"Copy"}}, {Debug, {L"Debug"}, gmf_MainThread}, {Detach, {L"Detach"}, gmf_MainThread}, + {EnvironmentReload, {L"EnvironmentReload", L"EnvReload"}, gmf_MainThread}, + {EnvironmentList, {L"EnvironmentList", L"EnvList"}}, {FindEditor, {L"FindEditor"}}, {FindFarWindow, {L"FindFarWindow"}}, {FindViewer, {L"FindViewer"}}, @@ -1000,6 +1010,8 @@ void ConEmuMacro::UnitTests() _ASSERTE(p && p->argc==1 && lstrcmp(p->argv[0].Str,L"def")==0); SafeFree(p); + CEStr env_list(EnvironmentList(nullptr, nullptr, false)); + gbUnitTest = false; } #endif @@ -1695,6 +1707,80 @@ LPWSTR ConEmuMacro::Context(GuiMacro* p, CRealConsole* apRCon, bool abFromPlugin return lstrdup(L""); } +LPWSTR ConEmuMacro::EnvironmentReload(GuiMacro* p, CRealConsole* apRCon, bool abFromPlugin) +{ + gpConEmu->ReloadEnvironmentVariables(); + return lstrdup(L"OK"); +} + +namespace { +void AppendExpandedValue(CEStrConcat& ss, const bool expandable, const wchar_t* data) +{ + if (expandable) + { + CEStr value(ExpandEnvStr(data)); + if (!value.IsEmpty()) + { + ss.Append(value.c_str(L"")); + return; + } + } + ss.Append(data); +} +}; + +LPWSTR ConEmuMacro::EnvironmentList(GuiMacro* p, CRealConsole* apRCon, bool abFromPlugin) +{ + CEStrConcat ss; + + // Pairs `name=value` from registry + std::shared_ptr data_ptr = gpConEmu->GetEnvironmentVariables(); + const auto& data = data_ptr->env_data; + for (const auto& key : data_ptr->GetKeys()) + { + const auto& v = data.at(key); + ss.Append(v.name.c_str()); + ss.Append(L"="); + AppendExpandedValue(ss, v.expandable, v.data.c_str()); + ss.Append(L"\n"); + } + + // Pairs `name=value` from ConEmu settings + if (gpSet->psEnvironmentSet) + { + CProcessEnvCmd env; + env.AddLines(gpSet->psEnvironmentSet, true); + + class Apply : public CStartEnvBase + { + private: + CEStrConcat& ss_; + public: + Apply(CEStrConcat& ss) : ss_(ss) {} + void Alias(LPCWSTR asName, LPCWSTR asValue) override {} + void ChCp(LPCWSTR asCP) override {} + void Echo(LPCWSTR asSwitches, LPCWSTR asText) override {} + void Title(LPCWSTR asTitle) override {} + void Type(LPCWSTR asSwitches, LPCWSTR asFile) override {} + void Set(LPCWSTR asName, LPCWSTR asValue) override + { + if (asName && *asName && asValue) + { + ss_.Append(asName); + ss_.Append(L"="); + AppendExpandedValue(ss_, true, asValue); + ss_.Append(L"\n"); + } + } + }; + + Apply apply(ss); + env.Apply(&apply); + } + + return ss.GetData().Detach(); +} + // Найти окно и активировать его. // LPWSTR asName LPWSTR ConEmuMacro::FindEditor(GuiMacro* p, CRealConsole* apRCon, bool abFromPlugin) { diff --git a/src/ConEmu/SystemEnvironment.cpp b/src/ConEmu/SystemEnvironment.cpp index 908ae1c216..c3e77cd7db 100644 --- a/src/ConEmu/SystemEnvironment.cpp +++ b/src/ConEmu/SystemEnvironment.cpp @@ -45,6 +45,16 @@ void SystemEnvironment::LoadFromRegistry() SysEnvValueCallback, (LPARAM)this, true); } +std::set SystemEnvironment::GetKeys() const +{ + std::set keys; + for (const auto& v : env_data) + { + keys.insert(v.first); + } + return keys; +} + std::wstring SystemEnvironment::MakeEnvName(const std::wstring& s) { // Windows environment names are case-insensitive diff --git a/src/ConEmu/SystemEnvironment.h b/src/ConEmu/SystemEnvironment.h index e575a9fc0a..ce733c4842 100644 --- a/src/ConEmu/SystemEnvironment.h +++ b/src/ConEmu/SystemEnvironment.h @@ -29,13 +29,15 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include +#include #include +#include // The class is not thread-safe struct SystemEnvironment { void LoadFromRegistry(); + std::set GetKeys() const; static std::wstring MakeEnvName(const std::wstring& s); static bool WINAPI SysEnvValueCallback(HKEY hk, LPCWSTR pszName, DWORD dwType, LPARAM lParam); diff --git a/src/common/CEStr.cpp b/src/common/CEStr.cpp index b5c0d5f89c..7ae1465094 100644 --- a/src/common/CEStr.cpp +++ b/src/common/CEStr.cpp @@ -501,3 +501,26 @@ char* CEStrA::release() clear(); // JIC return ptr; } + +// CEStrConcat +void CEStrConcat::Append(const wchar_t* str) +{ + if (!str || !*str) return; + CEStr new_str(str); + ssize_t new_len = new_str.GetLen(); + total_ += new_len; + strings_.push_back({new_len, std::move(new_str)}); +} + +CEStr CEStrConcat::GetData() const +{ + CEStr result; + wchar_t* buffer = result.GetBuffer(total_); + for (const auto& str : strings_) + { + wmemmove_s(buffer, str.first, str.second, str.first); + buffer += str.first; + } + *buffer = 0; + return result; +} diff --git a/src/common/CEStr.h b/src/common/CEStr.h index 67968c0041..2b7855709f 100644 --- a/src/common/CEStr.h +++ b/src/common/CEStr.h @@ -29,6 +29,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include "defines.h" +#include "MArray.h" // CEStr struct CEStr @@ -109,3 +110,14 @@ struct CEStrA public: char* ms_Val = nullptr; }; + +// Implements string concatenation +class CEStrConcat +{ +private: + MArray> strings_; + ssize_t total_ = 0; +public: + void Append(const wchar_t* str); + CEStr GetData() const; +}; diff --git a/src/common/MArray.h b/src/common/MArray.h index ffbe847b64..c7d7b10799 100644 --- a/src/common/MArray.h +++ b/src/common/MArray.h @@ -109,6 +109,14 @@ class MArray { return data.end(); }; + const_iterator begin() const + { + return data.cbegin(); + }; + const_iterator end() const + { + return data.cend(); + }; const_iterator cbegin() const { return data.cbegin();