Skip to content

Commit

Permalink
Merge pull request directvt#573 from o-sdn-o/gui-bridge
Browse files Browse the repository at this point in the history
Fix cli usage output for non-UTF-8 code pages
  • Loading branch information
o-sdn-o authored Feb 18, 2024
2 parents e2a3602 + 8afe8ab commit c0b2d48
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 91 deletions.
2 changes: 1 addition & 1 deletion src/netxs/desktopio/application.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace netxs::app

namespace netxs::app::shared
{
static const auto version = "v0.9.71";
static const auto version = "v0.9.72";
static const auto repository = "https://github.com/directvt/vtm";
static const auto usr_config = "~/.config/vtm/settings.xml"s;
static const auto sys_config = "/etc/vtm/settings.xml"s;
Expand Down
5 changes: 3 additions & 2 deletions src/netxs/desktopio/console.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ namespace netxs::ui
{
static auto id = std::pair<ui32, time>{};
static constexpr auto mouse = 1 << 0;
static constexpr auto nt = 1 << 5; // Use win32 console api for input.
static constexpr auto redirio = 1 << 6;
static constexpr auto nt = 1 << 6; // Use win32 console api for input.
static constexpr auto redirio = 1 << 7;
//todo make 3-bit field for color mode
static constexpr auto vtrgb = 0;
static constexpr auto nt16 = 1 << 1;
static constexpr auto vt16 = 1 << 2;
static constexpr auto vt256 = 1 << 3;
static constexpr auto direct = 1 << 4;
static constexpr auto gui = 1 << 5;

template<class T>
auto str(T mode)
Expand Down
3 changes: 2 additions & 1 deletion src/netxs/desktopio/richtext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2065,6 +2065,7 @@ namespace netxs::ui
auto blk(bool ) { }
};

template<bool UseSGR = true>
auto to_utf8() const
{
auto dest = utf8_dest_t{};
Expand All @@ -2081,7 +2082,7 @@ namespace netxs::ui
curln.lyric->each([&](cell c)
{
if (c.isspc()) c.txt(whitespace);
if (c.wdt() != 3) c.scan(dest.base, dest);
if (c.wdt() != 3) c.scan<svga::vtrgb, UseSGR>(dest.base, dest);
});
}
return dest.data;
Expand Down
56 changes: 53 additions & 3 deletions src/netxs/desktopio/system.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,10 @@ namespace netxs::os
static constexpr auto unexpected = " returns unexpected result"sv;
static auto autosync = true; // Auto sync viewport with cursor position (win7/8 console).
static auto finalized = flag{ faux }; // Ready flag for clean exit.
void release()
static auto logbuffer = text{};
void release(bool clear_log = true)
{
if (clear_log) os::logbuffer.clear(); // Graceful exit w/o errors.
os::finalized.exchange(true);
os::finalized.notify_all();
}
Expand Down Expand Up @@ -3377,7 +3379,7 @@ namespace netxs::os
}
return winsz;
}
auto initialize()
auto initialize(bool trygui = faux)
{
#if defined(_WIN32)
os::stdin_fd = fd_t{ ptr::test(::GetStdHandle(STD_INPUT_HANDLE ), os::invalid_fd) };
Expand Down Expand Up @@ -3489,6 +3491,30 @@ namespace netxs::os
else
{
dtvt::win_sz = dtvt::consize();
trygui = faux; // Not implemented.
if (trygui)
{
#if defined(_WIN32)
if (::FreeConsole() && ::AttachConsole(ATTACH_PARENT_PROCESS)) // We are hosted by a shell.
{
os::stdin_fd = fd_t{ ptr::test(::GetStdHandle(STD_INPUT_HANDLE ), os::invalid_fd) };
os::stdout_fd = fd_t{ ptr::test(::GetStdHandle(STD_OUTPUT_HANDLE), os::invalid_fd) };
os::stderr_fd = fd_t{ ptr::test(::GetStdHandle(STD_ERROR_HANDLE ), os::invalid_fd) };
}
else // Run gui console.
{
os::stdin_fd = os::invalid_fd;
os::stdout_fd = os::invalid_fd;
os::stderr_fd = os::invalid_fd;
dtvt::vtmode |= ui::console::gui;
auto term = "Native GUI console";
log(prompt::os, "Terminal type: ", term);
return;
}
#else
#endif
}

#if defined(_WIN32)
{
//todo revise
Expand Down Expand Up @@ -3563,7 +3589,8 @@ namespace netxs::os
}
auto checkpoint()
{
if (dtvt::active || dtvt::vtmode & ui::console::redirio) return;
if (dtvt::active || dtvt::vtmode & ui::console::redirio
|| dtvt::vtmode & ui::console::gui) return;
#if defined(_WIN32)

ok(::GetConsoleMode(os::stdout_fd, &dtvt::backup.omode), "::GetConsoleMode(os::stdout_fd)", os::unexpected);
Expand Down Expand Up @@ -4490,15 +4517,38 @@ namespace netxs::os
auto logger()
{
static auto dtvt_output = [](auto& data){ io::send(os::stdout_fd, data); };
if (dtvt::vtmode & ui::console::gui)
{
auto errmsg = []
{
if (os::logbuffer.size())
{
#if defined(_WIN32)
auto utf8log = ui::page{ utf::trunc(os::logbuffer, 32) }.to_utf8<faux>();
auto message = utf::to_utf(utf::trim_front(view{ utf8log }, '\n'));
auto caption = utf::to_utf(os::process::binary());
::MessageBoxW(NULL, message.data(), caption.data(), MB_OK);
#else
#endif
}
};
std::atexit(errmsg);
}
return netxs::logger::attach([](qiew utf8)
{
if (dtvt::vtmode & ui::console::gui) // Deferred logs in gui mode.
{
os::logbuffer += utf8;
utf8 = os::logbuffer;
}
if (utf8.empty()) return;
if (dtvt::active || dtvt::client)
{
static auto logs = netxs::directvt::binary::logs_t{};
logs.set(os::process::id.first, os::process::id.second, utf8);
dtvt::active ? logs.sendfx(dtvt_output) // Send logs to the dtvt-app hoster.
: logs.sendby(dtvt::client); // Send logs to the dtvt-app.
os::logbuffer.clear();
}
else if (os::stdout_fd != os::invalid_fd)
{
Expand Down
5 changes: 5 additions & 0 deletions src/netxs/desktopio/utf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1406,6 +1406,11 @@ namespace netxs::utf
}
utf8.remove_prefix(std::distance(utf8.begin(), head));
}
auto trim_front(view&& utf8, char c = ' ')
{
utf::trim_front(utf8, c);
return utf8;
}
auto trim_back(view& utf8, view delims)
{
auto temp = utf8;
Expand Down
177 changes: 93 additions & 84 deletions src/vtm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

using namespace netxs;

enum class type { client, server, daemon, logmon, runapp, config };
enum class type { client, server, daemon, logmon, runapp, hlpmsg, config };
enum class code { noaccess, noserver, nodaemon, nosrvlog, interfer, errormsg };

int main(int argc, char* argv[])
Expand Down Expand Up @@ -98,88 +98,8 @@ int main(int argc, char* argv[])
}
else if (getopt.match("-?", "-h", "--help"))
{
os::dtvt::initialize();
netxs::logger::wipe();
auto syslog = os::tty::logger();
auto vtm = os::process::binary<true>();
auto pad = text(os::process::binary<true>().size(), ' ');
log("\nText-based Desktop Environment " + text{ app::shared::version } +
"\n"
"\n Syntax:"
"\n"
"\n " + vtm + " [ -c <file> ][ -q ][ -p <id> ][ -s | -d | -m ][ -x <cmds> ]"
"\n " + vtm + " [ -c <file> ][ -q ][ -r [ <type> ]][ <args...> ]"
"\n " + vtm + " [ -c <file> ] -l"
"\n " + vtm + " -i | -u | -v | -?"
"\n"
"\n <script relay via piped redirection> | " + vtm + " [ -p <id> ]"
"\n"
"\n Options:"
"\n"
"\n By default, " + vtm + " runs Desktop Client, running an additional instance"
"\n with Desktop Server in background if it is not found."
"\n"
"\n -h, -?, --help Print command-line options."
"\n -v, --version Print version."
"\n -l, --listconfig Print configuration."
"\n -i, --install Perform system-wide installation."
"\n -u, --uninstall Perform system-wide deinstallation."
"\n -q, --quiet Disable logging."
"\n -x, --script <cmds> Specifies script commands to be run by the desktop when ready."
"\n -c, --config <file> Specifies the settings file to load."
"\n -p, --pin <id> Specifies the desktop id it is pinned to."
"\n -s, --server Run Desktop Server."
"\n -d, --daemon Run Desktop Server in background."
"\n -m, --monitor Run Desktop Monitor."
"\n -r, --, --run Run desktop applet standalone."
"\n <type> Desktop applet type to run."
"\n <args...> Desktop applet arguments."
"\n"
"\n Desktop applet │ Type │ Arguments"
"\n ───────────────────────────┼──────┼─────────────────────────────────────────────────"
"\n Teletype Console (default) │ vtty │ CUI application with arguments to run."
"\n Terminal Console │ term │ CUI application with arguments to run."
"\n DirectVT Gateway │ dtvt │ DirectVT-aware application to run."
"\n DirectVT Gateway with TTY │ dtty │ CUI application to run, forwarding DirectVT I/O."
"\n"
"\n The following commands have a short form:"
"\n"
"\n 'vtm -r vtty <cui_app...>' can be shortened to 'vtm <cui_app...>'."
"\n 'vtm -r dtty ssh <user@host dtvt_app...>' can be shortened to 'vtm ssh <user@host dtvt_app...>'."
"\n"
"\n Settings loading order:"
"\n"
"\n - Initialize hardcoded settings."
"\n - In case of using the '--config <file>' option and the <file> can be loaded:"
"\n - Merge settings from the <file>."
"\n otherwise:"
"\n - Merge with system-wide settings from " + os::path::expand(app::shared::sys_config).second + "."
"\n - Merge with user-wise settings from " + os::path::expand(app::shared::usr_config).second + "."
"\n - Merge with DirectVT packet received from the hosting DirectVT Gateway."
"\n"
"\n Script commands:"
"\n"
"\n Syntax: \"<command>([<args...>])[; <command>([<args...>]); ... <command>([<args...>])]\""
"\n"
"\n Command │ Description"
"\n ──────────────────────────────┼───────────────────────────────────────────────────────"
"\n vtm.run([<attrs...>]) │ Create and run a menu item constructed using"
"\n │ a space-separated list of <attr>=<val>."
"\n │ Run a temporary menu item constructed using"
"\n │ default attributes if no arguments specified."
"\n vtm.set(id=<id> [<attrs...>]) │ Create or override a menu item using a space-separated"
"\n │ list of <attr>=<val>."
"\n vtm.del([<id>]) │ Delete the taskbar menu item by <id>."
"\n │ Delete all menu items if no <id> specified."
"\n vtm.dtvt(<dtvt_app...>) │ Create a temporary menu item and run DirectVT Gateway"
"\n │ to host specified <dtvt_app...>."
"\n vtm.selected(<id>) │ Set selected menu item using specified <id>."
"\n vtm.shutdown() │ Terminate the running desktop session."
"\n"
"\n The following characters in script commands will be de-escaped: \\e \\t \\r \\n \\a \\\" \\' \\\\"
"\n"
);
return 0;
whoami = type::hlpmsg;
break;
}
else if (getopt.match("-v", "--version"))
{
Expand All @@ -201,9 +121,98 @@ int main(int argc, char* argv[])
}
}

os::dtvt::initialize();
auto trygui = whoami == type::runapp
|| whoami == type::client
|| whoami == type::hlpmsg;
os::dtvt::initialize(trygui);
os::dtvt::checkpoint();

if (whoami == type::hlpmsg)
{
netxs::logger::wipe();
auto syslog = os::tty::logger();
auto vtm = os::process::binary<true>();
auto pad = text(os::process::binary<true>().size(), ' ');
log("\nText-based Desktop Environment " + text{ app::shared::version } +
"\n"
"\n Syntax:"
"\n"
"\n " + vtm + " [ -c <file> ][ -q ][ -p <id> ][ -s | -d | -m ][ -x <cmds> ]"
"\n " + vtm + " [ -c <file> ][ -q ][ -r [ <type> ]][ <args...> ]"
"\n " + vtm + " [ -c <file> ] -l"
"\n " + vtm + " -i | -u | -v | -?"
"\n"
"\n <script relay via piped redirection> | " + vtm + " [ -p <id> ]"
"\n"
"\n Options:"
"\n"
"\n By default, " + vtm + " runs Desktop Client, running an additional"
"\n instance with Desktop Server in background if it is not found."
"\n"
"\n -h, -?, --help Print command-line options."
"\n -v, --version Print version."
"\n -l, --listconfig Print configuration."
"\n -i, --install Perform system-wide installation."
"\n -u, --uninstall Perform system-wide deinstallation."
"\n -q, --quiet Disable logging."
"\n -x, --script <cmds> Specifies script commands."
"\n -c, --config <file> Specifies the settings file to load."
"\n -p, --pin <id> Specifies the desktop id it is pinned to."
"\n -s, --server Run Desktop Server."
"\n -d, --daemon Run Desktop Server in background."
"\n -m, --monitor Run Desktop Monitor."
"\n -r, --, --run Run desktop applet standalone."
"\n <type> Desktop applet type to run."
"\n <args...> Desktop applet arguments."
"\n"
"\n Desktop applet │ Type │ Arguments"
"\n ───────────────────────────┼──────┼─────────────────────────────────────────────────"
"\n Teletype Console (default) │ vtty │ CUI application with arguments to run."
"\n Terminal Console │ term │ CUI application with arguments to run."
"\n DirectVT Gateway │ dtvt │ DirectVT-aware application to run."
"\n DirectVT Gateway with TTY │ dtty │ CUI application to run, forwarding DirectVT I/O."
"\n"
"\n The following commands have a short form:"
"\n"
"\n 'vtm -r vtty <cui_app...>' can be shortened to 'vtm <cui_app...>'."
"\n 'vtm -r dtty ssh <user@host dtvt_app...>' can be shortened to 'vtm ssh <user@host dtvt_app...>'."
"\n"
"\n Settings loading order:"
"\n"
"\n - Initialize hardcoded settings."
"\n - In case of using the '--config <file>' option and the <file> can be loaded:"
"\n - Merge settings from the <file>."
"\n otherwise:"
"\n - Merge with system-wide settings from " + os::path::expand(app::shared::sys_config).second + "."
"\n - Merge with user-wise settings from " + os::path::expand(app::shared::usr_config).second + "."
"\n - Merge with DirectVT packet received from the hosting DirectVT Gateway."
"\n"
"\n Script commands:"
"\n"
"\n Syntax: \"<command>([<args...>])[; <command>([<args...>]); ... <command>([<args...>])]\""
"\n"
"\n Command │ Description"
"\n ──────────────────────────────┼───────────────────────────────────────────────────────"
"\n vtm.run([<attrs...>]) │ Create and run a menu item constructed using"
"\n │ a space-separated list of <attr>=<val>."
"\n │ Run a temporary menu item constructed using"
"\n │ default attributes if no arguments specified."
"\n vtm.set(id=<id> [<attrs...>]) │ Create or override a menu item using a space-separated"
"\n │ list of <attr>=<val>."
"\n vtm.del([<id>]) │ Delete the taskbar menu item by <id>."
"\n │ Delete all menu items if no <id> specified."
"\n vtm.dtvt(<dtvt_app...>) │ Create a temporary menu item and run DirectVT Gateway"
"\n │ to host specified <dtvt_app...>."
"\n vtm.selected(<id>) │ Set selected menu item using specified <id>."
"\n vtm.shutdown() │ Terminate the running desktop session."
"\n"
"\n The following characters in script commands will be de-escaped: \\e \\t \\r \\n \\a \\\" \\' \\\\"
"\n"
);
os::release(faux);
return 0;
}

if (os::dtvt::vtmode & ui::console::redirio && (whoami == type::runapp || whoami == type::client))
{
whoami = type::logmon;
Expand Down

0 comments on commit c0b2d48

Please sign in to comment.