ChannelStreams.h (4140B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #pragma once 4 #include "Resources.h" 5 #include "VTSupport.h" 6 #include <winget/LocIndependent.h> 7 8 #include <ostream> 9 #include <string> 10 11 12 namespace AppInstaller::CLI::Execution 13 { 14 // Gets the current console width. 15 size_t GetConsoleWidth(); 16 17 // The base stream for all channels. 18 struct BaseStream 19 { 20 BaseStream(std::ostream& out, bool enabled, bool VTEnabled); 21 22 template <typename T> 23 BaseStream& operator<<(const T& t) 24 { 25 Write<T>(t, false); 26 return *this; 27 } 28 29 BaseStream& operator<<(std::ostream& (__cdecl* f)(std::ostream&)); 30 BaseStream& operator<<(const VirtualTerminal::Sequence& sequence); 31 BaseStream& operator<<(const VirtualTerminal::ConstructedSequence& sequence); 32 33 void SetVTEnabled(bool enabled); 34 35 void RestoreDefault(); 36 37 void Disable(); 38 39 std::ostream& Get(); 40 41 private: 42 template <typename T> 43 void Write(const T& t, bool bypass) 44 { 45 if (bypass || m_enabled) 46 { 47 m_out << t; 48 } 49 }; 50 51 std::ostream& m_out; 52 std::atomic_bool m_enabled; 53 std::atomic_bool m_VTUpdated; 54 bool m_VTEnabled; 55 }; 56 57 // Holds output formatting information. 58 struct OutputStream 59 { 60 OutputStream(BaseStream& out, bool enabled, bool VTEnabled = true); 61 62 // Adds a format to the current value. 63 void AddFormat(const VirtualTerminal::Sequence& sequence); 64 65 // Clears the current format value. 66 void ClearFormat(); 67 68 template <typename T> 69 OutputStream& operator<<(const T& t) 70 { 71 // You've found your way here because you tried to output a type that may not localized. 72 // In order to ensure that all output is localized, only the types with specializations of 73 // details::IsApprovedForOutput above can be output. 74 // * If your string is a simple message, it should be put in 75 // /src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw 76 // and referenced in /src/AppInstallerCLICore/Resources.h. Then either output the 77 // Resource::StringId, or load it manually and output the Resource::LocString. 78 // * If your string is *definitely* localization independent, you can tag it as such with 79 // the Utility::LocInd(View/String) types. 80 // * If your string came from outside of the source code, it is best to store it in a 81 // Utility::NormalizedString so that it has a normalized representation. This also 82 // informs the output that there is no localized version to use. 83 // TODO: This assertion is currently only applied to placeholders in localized strings. 84 // Convert the rest of the code base and uncomment to enforce localization. 85 //static_assert(details::IsApprovedForOutput<std::decay_t<T>>::value, "This type may not be localized, see comment for more information"); 86 if (m_enabled) 87 { 88 if (m_VTEnabled) 89 { 90 ApplyFormat(); 91 } 92 m_out << t; 93 } 94 return *this; 95 } 96 97 OutputStream& operator<<(std::ostream& (__cdecl* f)(std::ostream&)); 98 OutputStream& operator<<(const VirtualTerminal::Sequence& sequence); 99 OutputStream& operator<<(const VirtualTerminal::ConstructedSequence& sequence); 100 OutputStream& operator<<(const std::filesystem::path& path); 101 102 inline bool IsEnabled() { 103 return m_enabled; 104 } 105 106 private: 107 // Applies the format for the stream. 108 void ApplyFormat(); 109 110 BaseStream& m_out; 111 bool m_enabled; 112 bool m_VTEnabled; 113 size_t m_applyFormatAtOne = 1; 114 VirtualTerminal::ConstructedSequence m_format; 115 }; 116 }