From 4cb157b85bc1770b79002e36747191d69eb757c0 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Sun, 3 Mar 2019 19:07:25 -0800 Subject: libdeno: fix libdeno.print() unicode output on Windows Note that emoji are still not supported, due limitations of the Windows console. --- libdeno/binding.cc | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) (limited to 'libdeno') diff --git a/libdeno/binding.cc b/libdeno/binding.cc index 064ce2271..7346956fd 100644 --- a/libdeno/binding.cc +++ b/libdeno/binding.cc @@ -2,9 +2,18 @@ #include #include #include +#include #include #include +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#endif // _WIN32 + #include "third_party/v8/include/v8.h" #include "third_party/v8/src/base/logging.h" @@ -93,10 +102,52 @@ void Print(const v8::FunctionCallbackInfo& args) { DenoIsolate* d = DenoIsolate::FromIsolate(isolate); auto context = d->context_.Get(d->isolate_); v8::HandleScope handle_scope(isolate); - v8::String::Utf8Value str(isolate, args[0]); bool is_err = args.Length() >= 2 ? args[1]->BooleanValue(context).ToChecked() : false; FILE* file = is_err ? stderr : stdout; + +#ifdef _WIN32 + int fd = _fileno(file); + if (fd < 0) return; + + HANDLE h = reinterpret_cast(_get_osfhandle(fd)); + if (h == INVALID_HANDLE_VALUE) return; + + DWORD mode; + if (GetConsoleMode(h, &mode)) { + // Print to Windows console. Since the Windows API generally doesn't support + // UTF-8 encoded text, we have to use `WriteConsoleW()` which uses UTF-16. + v8::String::Value str(isolate, args[0]); + auto str_len = static_cast(str.length()); + auto str_wchars = reinterpret_cast(*str); + + // WriteConsoleW has some limit to how many characters can be written at + // once, which is unspecified but low enough to be encountered in practice. + // Therefore we break up the write into chunks of 8kb if necessary. + size_t chunk_start = 0; + while (chunk_start < str_len) { + size_t chunk_end = std::min(chunk_start + 8192, str_len); + + // Do not break in the middle of a surrogate pair. Note that `chunk_end` + // points to the start of the next chunk, so we check whether it contains + // the second half of a surrogate pair (a.k.a. "low surrogate"). + if (chunk_end < str_len && str_wchars[chunk_end] >= 0xdc00 && + str_wchars[chunk_end] <= 0xdfff) { + --chunk_end; + } + + // Write to the console. + DWORD chunk_len = static_cast(chunk_end - chunk_start); + DWORD _; + WriteConsoleW(h, &str_wchars[chunk_start], chunk_len, &_, nullptr); + + chunk_start = chunk_end; + } + return; + } +#endif // _WIN32 + + v8::String::Utf8Value str(isolate, args[0]); fwrite(*str, sizeof(**str), str.length(), file); fflush(file); } -- cgit v1.2.3