winget-cli icon indicating copy to clipboard operation
winget-cli copied to clipboard

flexible handling of GetConsoleWidth method's default value would be useful in scripting

Open Nejat opened this issue 4 years ago • 3 comments

Description of the new feature/enhancement

When listing output winget truncates column width(s) to accommodate for the total width of the console, which is determined by a call to GetConsoleWidth in src\AppInstallerCLICore\TableOutput.h

    namespace details
    {
        // Gets the column width of the console.
        inline size_t GetConsoleWidth()
        {
            CONSOLE_SCREEN_BUFFER_INFO consoleInfo{};
            if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo))
            {
                return static_cast<size_t>(consoleInfo.dwSize.X);
            }
            else
            {
                return 120;
            }
        }
    }

If the console is not wide enough, output of a column is truncated and a UTF8 Horizontal Ellipsis (…) is append to the end of the column, also in src\AppInstallerCLICore\TableOutput.h; see the first listing in the image below.


        void OutputLineToStream(const line_t& line)
        {
            auto out = m_reporter.Info();

            for (size_t i = 0; i < FieldCount; ++i)
            {
                const auto& col = m_columns[i];

                if (col.MaxLength)
                {
                    size_t valueLength = Utility::UTF8ColumnWidth(line[i]);

                    if (valueLength > col.MaxLength)
                    {
                        size_t actualWidth;
                        out << Utility::UTF8TrimRightToColumnWidth(line[i], col.MaxLength - 1, actualWidth) << "\xE2\x80\xA6"; // UTF8 encoding of ellipsis (…) character

                        // Some characters take 2 unit space, the trimmed string length might be 1 less than the expected length.
                        if (actualWidth != col.MaxLength - 1)
                        {
                            out << ' ';
                        }

                        if (col.SpaceAfter)
                        {
                            out << ' ';
                        }
                    }
                    else
                    {
                        out << line[i];

                        if (col.SpaceAfter)
                        {
                            out << std::string(col.MaxLength - valueLength + 1, ' ');
                        }
                    }
                }
            }

            out << std::endl;
        }

When the console is wide enough, all of the columns are output in their entirety; see the second listing in the image below.

However, if you either pipe the output to a subsequent command, such as winget upgrade | Select-Object -skip 3, or you assign it to a variable, GetConsoleWidth uses a hard coded 120 for the console width, because it can't get console buffer info for std out. Besides being truncated, the output is also garbled because it is not captured as UTF8; ; see the third listing in the image below.

image

Proposed technical implementation details (optional)

Adding native PowerShell support as proposed in #221 would be the ideal solution, however a quick simple patch to bump up the default value to 180+ would be great in the mean time.

    namespace details
    {
        // Gets the column width of the console.
        inline size_t GetConsoleWidth()
        {
            CONSOLE_SCREEN_BUFFER_INFO consoleInfo{};
            if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo))
            {
                return static_cast<size_t>(consoleInfo.dwSize.X);
            }
            else
            {
                return 180; // or more if your heart desires 😋
            }
        }
    }

Nejat avatar Jul 19 '21 17:07 Nejat

Why truncate at all? If stdout is a file or a pipe, long lines should never be truncated!

sredna avatar Jul 26 '21 12:07 sredna

Why truncate at all? If stdout is a file or a pipe, long lines should never be truncated!

I agree, but that would require more work, which would become unnecessary once powershell is natively supported, hence the simple solution suggestion to change one default.

Nejat avatar Jul 26 '21 13:07 Nejat

Duplicate #2603

panther7 avatar Jan 09 '23 19:01 panther7

[Policy] Area-Output

Trenly avatar Jun 16 '23 16:06 Trenly