mirror of
https://github.com/wxWidgets/wxWidgets.git
synced 2026-09-24 07:24:31 +08:00
Wrap help text shown by wxCmdLineParser at terminal width
By default, wrap the options descriptions to make output prettier. It is also possible to disable this by explicitly passing wxCMD_LINE_WRAP_NONE to Parse() and related functions or always wrap at 80 columns, for example.
This commit is contained in:
+10
-4
@@ -75,6 +75,10 @@ enum wxCmdLineSwitchState
|
||||
wxCMD_SWITCH_ON // Found in normal state.
|
||||
};
|
||||
|
||||
// Constants determining how (and if) to wrap the usage message
|
||||
constexpr int wxCMD_LINE_WRAP_AUTO = -1;
|
||||
constexpr int wxCMD_LINE_WRAP_NONE = 0;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxCmdLineEntryDesc is a description of one command line
|
||||
// switch/option/parameter
|
||||
@@ -295,14 +299,16 @@ public:
|
||||
// syntax error occurred
|
||||
//
|
||||
// if showUsage is true, Usage() is called in case of syntax error or if
|
||||
// help was requested
|
||||
int Parse(bool showUsage = true);
|
||||
// help was requested and if wrapColumn is not 0, the usage message is
|
||||
// wrapped at the specified column, which will be the terminal width for
|
||||
// its default value
|
||||
int Parse(bool showUsage = true, int wrapColumn = wxCMD_LINE_WRAP_AUTO);
|
||||
|
||||
// give the usage message describing all program options
|
||||
void Usage() const;
|
||||
void Usage(int wrapColumn = wxCMD_LINE_WRAP_AUTO) const;
|
||||
|
||||
// return the usage string, call Usage() to directly show it to the user
|
||||
wxString GetUsageString() const;
|
||||
wxString GetUsageString(int wrapColumn = wxCMD_LINE_WRAP_AUTO) const;
|
||||
|
||||
// get the command line arguments
|
||||
// ------------------------------
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: wx/private/terminal.h
|
||||
// Purpose: Helpers for working with terminal output
|
||||
// Author: Vadim Zeitlin
|
||||
// Created: 2024-11-22
|
||||
// Copyright: (c) 2024 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _WX_PRIVATE_TERMINAL_H_
|
||||
#define _WX_PRIVATE_TERMINAL_H_
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include "wx/utils.h"
|
||||
|
||||
#include "wx/msw/wrapwin.h"
|
||||
#endif
|
||||
|
||||
#ifdef __UNIX__
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
namespace wxTerminal
|
||||
{
|
||||
|
||||
// Return the current terminal width or 0 if we couldn't find it.
|
||||
inline int GetWidth()
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
if ( ::GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi) )
|
||||
return csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
||||
#elif defined TIOCGWINSZ
|
||||
winsize w;
|
||||
int fd = fileno(stdout);
|
||||
if ( fd != -1 && ioctl(fd, TIOCGWINSZ, &w) == 0 )
|
||||
return w.ws_col;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace wxTerminal
|
||||
|
||||
#endif // _WX_PRIVATE_TERMINAL_H_
|
||||
+42
-3
@@ -98,6 +98,29 @@ enum wxCmdLineSwitchState
|
||||
wxCMD_SWITCH_ON
|
||||
};
|
||||
|
||||
/**
|
||||
Value indicating that wxCmdLineParser::Parse() should determine the wrap
|
||||
column automatically.
|
||||
|
||||
This is the default value for the @c wrapColumn parameter of
|
||||
wxCmdLineParser::Parse() and means that the text will be wrapped at the
|
||||
window boundary if it is possible to find it (which may not be the case if
|
||||
the output is redirected and doesn't appear on a terminal at all, for
|
||||
example).
|
||||
|
||||
@since 3.3.0
|
||||
*/
|
||||
constexpr int wxCMD_LINE_WRAP_AUTO = -1;
|
||||
|
||||
/**
|
||||
Value indicating that wxCmdLineParser::Parse() should not wrap the output.
|
||||
|
||||
Passing this value as @c wrapColumn parameter of wxCmdLineParser::Parse()
|
||||
means that the text should not be wrapped at all.
|
||||
|
||||
@since 3.3.0
|
||||
*/
|
||||
constexpr int wxCMD_LINE_WRAP_NONE = 0;
|
||||
|
||||
/**
|
||||
Flags determining wxCmdLineParser::ConvertStringToArgs() behaviour.
|
||||
@@ -682,8 +705,16 @@ public:
|
||||
requested. If @false, only error messages about possible syntax
|
||||
errors are given, use Usage to show the usage message from the
|
||||
caller if needed.
|
||||
@param wrapColumn
|
||||
When @a giveUsage is @true, this parameter specifies the column at
|
||||
which the help text should be wrapped if given. When left as its
|
||||
default value of wxCMD_LINE_WRAP_AUTO, the text will be wrapped at
|
||||
the window boundary, if it was possible to detect it, or not at all
|
||||
otherwise. If the value of this parameter is wxCMD_LINE_WRAP_NONE,
|
||||
the text is never wrapped. Any other value specifies the column at
|
||||
which to wrap, e.g. 80. This parameter is new since wxWidgets 3.3.0.
|
||||
*/
|
||||
int Parse(bool giveUsage = true);
|
||||
int Parse(bool giveUsage = true, int wrapColumn = wxCMD_LINE_WRAP_AUTO);
|
||||
|
||||
///@{
|
||||
/**
|
||||
@@ -760,15 +791,23 @@ public:
|
||||
resulting message will not be helpful to the user unless the
|
||||
descriptions were indeed specified.
|
||||
|
||||
@param wrapColumn
|
||||
See Parse() for the description of this parameter. This parameter
|
||||
is new since wxWidgets 3.3.0.
|
||||
|
||||
@see SetLogo(), SetUsageSynopsis()
|
||||
*/
|
||||
void Usage() const;
|
||||
void Usage(int wrapColumn = wxCMD_LINE_WRAP_AUTO) const;
|
||||
|
||||
/**
|
||||
Return the string containing the program usage description.
|
||||
|
||||
Call Usage() to directly show this string to the user.
|
||||
|
||||
@param wrapColumn
|
||||
See Parse() for the description of this parameter. This parameter
|
||||
is new since wxWidgets 3.3.0.
|
||||
*/
|
||||
wxString GetUsageString() const;
|
||||
wxString GetUsageString(int wrapColumn = wxCMD_LINE_WRAP_AUTO) const;
|
||||
};
|
||||
|
||||
|
||||
+51
-9
@@ -40,6 +40,9 @@
|
||||
#include "wx/apptrait.h"
|
||||
#include "wx/scopeguard.h"
|
||||
|
||||
#include "wx/private/terminal.h"
|
||||
#include "wx/private/wordwrap.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// private functions
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -784,7 +787,7 @@ void wxCmdLineParser::Reset()
|
||||
// the real work is done here
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int wxCmdLineParser::Parse(bool showUsage)
|
||||
int wxCmdLineParser::Parse(bool showUsage, int wrapColumn)
|
||||
{
|
||||
bool maybeOption = true; // can the following arg be an option?
|
||||
bool ok = true; // true until an error is detected
|
||||
@@ -1237,7 +1240,7 @@ int wxCmdLineParser::Parse(bool showUsage)
|
||||
if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) )
|
||||
{
|
||||
if ( showUsage )
|
||||
Usage();
|
||||
Usage(wrapColumn);
|
||||
|
||||
wxSafeMessageOutput(errorMsg);
|
||||
}
|
||||
@@ -1249,12 +1252,12 @@ int wxCmdLineParser::Parse(bool showUsage)
|
||||
// give the usage message
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxCmdLineParser::Usage() const
|
||||
void wxCmdLineParser::Usage(int wrapColumn) const
|
||||
{
|
||||
wxSafeMessageOutput(GetUsageString(wrapColumn));
|
||||
}
|
||||
|
||||
wxString wxCmdLineParser::GetUsageString() const
|
||||
wxString wxCmdLineParser::GetUsageString(int wrapColumn) const
|
||||
{
|
||||
wxString appname;
|
||||
if ( m_data->m_arguments.empty() )
|
||||
@@ -1416,22 +1419,61 @@ wxString wxCmdLineParser::GetUsageString() const
|
||||
lenMax = len;
|
||||
}
|
||||
|
||||
// Leave some space between the options and their descriptions.
|
||||
constexpr int MARGIN = 3;
|
||||
const int widthName = lenMax + MARGIN;
|
||||
|
||||
// Determine the column to wrap at, if necessary.
|
||||
if ( wrapColumn == wxCMD_LINE_WRAP_AUTO )
|
||||
{
|
||||
// Note that GetWidth() returns 0 if the terminal size couldn't be
|
||||
// determined, which happens to be exactly wxCMD_LINE_WRAP_NONE.
|
||||
wrapColumn = wxTerminal::GetWidth();
|
||||
}
|
||||
|
||||
// Check that we end up with reasonable layout, where descriptions column
|
||||
// is at least as wide as the names one.
|
||||
if ( wrapColumn != wxCMD_LINE_WRAP_NONE && wrapColumn < 2*widthName )
|
||||
{
|
||||
// It doesn't make sense to wrap anything if there is so little space.
|
||||
wrapColumn = wxCMD_LINE_WRAP_NONE;
|
||||
}
|
||||
|
||||
// This is only used when wrapColumn is not wxCMD_LINE_WRAP_NONE.
|
||||
const int widthDesc = wrapColumn - widthName;
|
||||
|
||||
for ( size_t n = 0; n < namesOptions.size(); n++ )
|
||||
{
|
||||
if ( n == count )
|
||||
usage << wxT('\n') << stdDesc;
|
||||
|
||||
const auto& desc = descOptions[n];
|
||||
|
||||
// desc contains text if name is empty
|
||||
if ( namesOptions[n].empty() )
|
||||
{
|
||||
usage << descOptions[n] << wxT('\n');
|
||||
usage << desc << wxT('\n');
|
||||
}
|
||||
else
|
||||
{
|
||||
usage << wxString::Format("%-*s\t%s\n",
|
||||
static_cast<int>(lenMax),
|
||||
namesOptions[n],
|
||||
descOptions[n]);
|
||||
// Check if the description fits on the same line if we wrap it.
|
||||
if ( wrapColumn == wxCMD_LINE_WRAP_NONE ||
|
||||
static_cast<int>(desc.length()) <= widthDesc )
|
||||
{
|
||||
// Note that we use TAB as separator here for compatibility.
|
||||
usage << wxString::Format("%-*s%*s%s\n",
|
||||
static_cast<int>(lenMax),
|
||||
namesOptions[n],
|
||||
MARGIN, "",
|
||||
desc);
|
||||
}
|
||||
else // We need to wrap it.
|
||||
{
|
||||
usage << wxString::Format("%s\n", namesOptions[n]);
|
||||
|
||||
for ( const auto& s : wxWordWrap(desc, widthDesc) )
|
||||
usage << wxString::Format("%*s%s\n", widthName, "", s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user