Fix REPL write line on Linux

This commit is contained in:
Ted John 2021-02-13 00:15:27 +00:00
parent 05cb106ee7
commit 3f5698b1e0
15 changed files with 82 additions and 30 deletions

View File

@ -11,6 +11,7 @@
#include <openrct2-ui/interface/Widget.h>
#include <openrct2-ui/windows/Window.h>
#include <openrct2/Context.h>
#include <openrct2/core/Console.hpp>
#include <openrct2/core/Http.h>
#include <openrct2/core/Json.hpp>
#include <openrct2/core/String.hpp>
@ -153,7 +154,7 @@ private:
{
try
{
std::printf("Downloading %s\n", url.c_str());
Console::WriteLine("Downloading %s", url.c_str());
Http::Request req;
req.method = Http::Method::GET;
req.url = url;
@ -175,14 +176,14 @@ private:
}
else
{
std::printf(" Failed to download %s\n", name.c_str());
Console::Error::WriteLine(" Failed to download %s", name.c_str());
}
QueueNextDownload();
});
}
catch (const std::exception&)
{
std::printf(" Failed to download %s\n", name.c_str());
Console::Error::WriteLine(" Failed to download %s", name.c_str());
QueueNextDownload();
}
}
@ -226,19 +227,20 @@ private:
}
else if (response.status == Http::Status::NotFound)
{
std::printf(" %s not found\n", name.c_str());
Console::Error::WriteLine(" %s not found", name.c_str());
QueueNextDownload();
}
else
{
std::printf(" %s query failed (status %d)\n", name.c_str(), static_cast<int32_t>(response.status));
Console::Error::WriteLine(
" %s query failed (status %d)", name.c_str(), static_cast<int32_t>(response.status));
QueueNextDownload();
}
});
}
catch (const std::exception&)
{
std::printf(" Failed to query %s\n", name.c_str());
Console::Error::WriteLine(" Failed to query %s", name.c_str());
}
}
};

View File

@ -273,6 +273,11 @@ namespace OpenRCT2
_stdInOutConsole.WriteLine(s);
}
void WriteErrorLine(const std::string& s) override
{
_stdInOutConsole.WriteLineError(s);
}
/**
* Causes the OpenRCT2 game loop to finish.
*/

View File

@ -141,6 +141,7 @@ namespace OpenRCT2
virtual bool LoadParkFromStream(
IStream* stream, const std::string& path, bool loadTitleScreenFirstOnFail = false) abstract;
virtual void WriteLine(const std::string& s) abstract;
virtual void WriteErrorLine(const std::string& s) abstract;
virtual void Finish() abstract;
virtual void Quit() abstract;

View File

@ -9,6 +9,7 @@
#include "Diagnostic.h"
#include "core/Console.hpp"
#include "core/String.hpp"
#include <cstdarg>
@ -73,6 +74,15 @@ static constexpr const char* _level_strings[] = {
"FATAL", "ERROR", "WARNING", "VERBOSE", "INFO",
};
static void diagnostic_print(DiagnosticLevel level, const std::string& prefix, const std::string& msg)
{
auto stream = diagnostic_get_stream(level);
if (stream == stdout)
Console::WriteLine("%s%s", prefix.c_str(), msg.c_str());
else
Console::Error::WriteLine("%s%s", prefix.c_str(), msg.c_str());
}
void diagnostic_log(DiagnosticLevel diagnosticLevel, const char* format, ...)
{
va_list args;
@ -86,8 +96,7 @@ void diagnostic_log(DiagnosticLevel diagnosticLevel, const char* format, ...)
auto msg = String::StdFormat_VA(format, args);
va_end(args);
auto stream = diagnostic_get_stream(diagnosticLevel);
fprintf(stream, "%s%s\n", prefix.c_str(), msg.c_str());
diagnostic_print(diagnosticLevel, prefix, msg);
}
}
@ -114,8 +123,7 @@ void diagnostic_log_with_location(
auto msg = String::StdFormat_VA(format, args);
va_end(args);
auto stream = diagnostic_get_stream(diagnosticLevel);
fprintf(stream, "%s%s\n", prefix.c_str(), msg.c_str());
diagnostic_print(diagnosticLevel, prefix, msg);
}
}

View File

@ -762,7 +762,7 @@ void game_autosave()
}
if (!scenario_save(path, saveFlags))
std::fprintf(stderr, "Could not autosave the scenario. Is the save folder writeable?\n");
Console::Error::WriteLine("Could not autosave the scenario. Is the save folder writeable?");
}
static void game_load_or_quit_no_save_prompt_callback(int32_t result, const utf8* path)

View File

@ -9,6 +9,7 @@
#include "Console.hpp"
#include "../Context.h"
#include "../platform/platform.h"
#include <cstdio>
@ -49,10 +50,16 @@ namespace Console
void WriteLine(const utf8* format, ...)
{
va_list args;
va_start(args, format);
auto formatLn = std::string(format) + "\n";
vfprintf(stdout, formatLn.c_str(), args);
char buffer[4096];
std::vsnprintf(buffer, sizeof(buffer), format, args);
auto ctx = OpenRCT2::GetContext();
if (ctx != nullptr)
ctx->WriteLine(buffer);
else
std::printf("%s\n", buffer);
va_end(args);
}
@ -92,8 +99,13 @@ namespace Console
void WriteLine_VA(const utf8* format, va_list args)
{
auto formatLn = std::string(format) + "\n";
vfprintf(stdout, formatLn.c_str(), args);
char buffer[4096];
std::vsnprintf(buffer, sizeof(buffer), format, args);
auto ctx = OpenRCT2::GetContext();
if (ctx != nullptr)
ctx->WriteErrorLine(buffer);
else
std::printf("%s\n", buffer);
}
} // namespace Error
} // namespace Console

View File

@ -12,6 +12,7 @@
# include "Http.h"
# include "../Version.h"
# include "../core/Console.hpp"
# include "String.hpp"
# include <cstdio>
@ -226,7 +227,7 @@ namespace Http
catch ([[maybe_unused]] const std::exception& e)
{
# ifdef DEBUG
std::fprintf(stderr, "HTTP request failed: %s\n", e.what());
Console::Error::WriteLine("HTTP request failed: %s", e.what());
# endif
WinHttpCloseHandle(hSession);
WinHttpCloseHandle(hConnect);

View File

@ -53,6 +53,7 @@ class StdInOutConsole final : public InteractiveConsole
{
private:
std::queue<std::tuple<std::promise<void>, std::string>> _evalQueue;
bool _isPromptShowing{};
public:
void Start();

View File

@ -510,7 +510,7 @@ static void benchgfx_render_screenshots(const char* inputPath, std::unique_ptr<I
}
catch (const std::exception& e)
{
std::fprintf(stderr, "%s", e.what());
Console::Error::WriteLine("%s", e.what());
}
for (auto& dpi : dpis)

View File

@ -24,8 +24,8 @@ using namespace OpenRCT2;
void StdInOutConsole::Start()
{
// Only start if stdin is a TTY
if (!isatty(fileno(stdin)))
// Only start if stdin/stdout is a TTY
if (!isatty(fileno(stdin)) || !isatty(fileno(stdout)))
{
return;
}
@ -40,7 +40,9 @@ void StdInOutConsole::Start()
{
std::string line;
std::string left = prompt;
_isPromptShowing = true;
auto quit = linenoise::Readline(left.c_str(), line);
_isPromptShowing = false;
if (quit)
{
if (lastPromptQuit)
@ -51,7 +53,7 @@ void StdInOutConsole::Start()
else
{
lastPromptQuit = true;
std::puts("(To exit, press ^C again or type exit)");
std::puts("(To exit, press ^C again)");
}
}
else
@ -123,12 +125,23 @@ void StdInOutConsole::WriteLine(const std::string& s, FormatToken colourFormat)
break;
}
if (formatBegin.empty() || !Platform::IsColourTerminalSupported())
if (!Platform::IsColourTerminalSupported())
{
std::printf("%s\n", s.c_str());
std::fflush(stdout);
}
else
{
std::printf("%s%s%s\n", formatBegin.c_str(), s.c_str(), "\x1b[0m");
if (_isPromptShowing)
{
std::printf("\r%s%s\x1b[0m\x1b[0K\r\n", formatBegin.c_str(), s.c_str());
std::fflush(stdout);
linenoise::linenoiseEditRefreshLine();
}
else
{
std::printf("%s%s\x1b[0m\n", formatBegin.c_str(), s.c_str());
std::fflush(stdout);
}
}
}

View File

@ -391,7 +391,7 @@ bool NetworkBase::BeginServer(uint16_t port, const std::string& address)
}
auto* szAddress = address.empty() ? "*" : address.c_str();
std::printf("Listening for clients on %s:%hu\n", szAddress, port);
Console::WriteLine("Listening for clients on %s:%hu", szAddress, port);
network_chat_show_connected_message();
network_chat_show_server_greeting();

View File

@ -148,7 +148,7 @@ private:
{
if (_lastAdvertiseTime == 0)
{
std::printf("Registering server on master server\n");
Console::WriteLine("Registering server on master server");
}
SendRegistration(_forceIPv4);
}
@ -237,6 +237,7 @@ private:
if (status == MasterServerStatus::Ok)
{
Console::WriteLine("Server successfully registered on master server");
json_t jsonToken = jsonRoot["token"];
if (jsonToken.is_string())
{

View File

@ -11,6 +11,7 @@
#ifdef ENABLE_SCRIPTING
# include "../core/Console.hpp"
# include "../world/Map.h"
# include <cstdio>
@ -195,7 +196,7 @@ namespace OpenRCT2::Scripting
{
duk_set_top(_ctx, _top);
_ctx = {};
std::fprintf(stderr, "duktape stack was not returned to original state!");
Console::Error::WriteLine("duktape stack was not returned to original state!");
}
_ctx = {};
}

View File

@ -528,7 +528,7 @@ void ScriptEngine::SetupHotReloading()
}
catch (const std::exception& e)
{
std::fprintf(stderr, "Unable to enable hot reloading of plugins: %s\n", e.what());
Console::Error::WriteLine("Unable to enable hot reloading of plugins: %s", e.what());
}
}
@ -1199,7 +1199,7 @@ void ScriptEngine::LoadSharedStorage()
}
catch (const std::exception&)
{
fprintf(stderr, "Unable to read '%s'\n", path.c_str());
Console::Error::WriteLine("Unable to read '%s'", path.c_str());
}
}
@ -1216,7 +1216,7 @@ void ScriptEngine::SaveSharedStorage()
}
catch (const std::exception&)
{
fprintf(stderr, "Unable to write to '%s'\n", path.c_str());
Console::Error::WriteLine("Unable to write to '%s'", path.c_str());
}
}

View File

@ -1094,6 +1094,8 @@ struct linenoiseState {
int history_index; /* The history index we are currently editing. */
};
static struct linenoiseState lnstate;
enum KEY_ACTION {
KEY_NULL = 0, /* NULL */
CTRL_A = 1, /* Ctrl+a */
@ -2088,6 +2090,11 @@ inline void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
refreshLine(l);
}
inline void linenoiseEditRefreshLine()
{
refreshLine(&lnstate);
}
/* This function is the core of the line editing capability of linenoise.
* It expects 'fd' to be already in "raw mode" so that every key pressed
* will be returned ASAP to read().
@ -2098,7 +2105,7 @@ inline void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
* The function returns the length of the current buffer. */
inline int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, int buflen, const char *prompt)
{
struct linenoiseState l;
auto& l = lnstate;
/* Populate the linenoise state that we pass to functions implementing
* specific editing functionalities. */