mirror of
https://github.com/denoland/deno.git
synced 2025-01-15 10:35:19 -05:00
libdeno: fix libdeno.print() unicode output on Windows
Note that emoji are still not supported, due limitations of the Windows console.
This commit is contained in:
parent
2e9d43391f
commit
4cb157b85b
1 changed files with 52 additions and 1 deletions
|
@ -2,9 +2,18 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <io.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
#include "third_party/v8/include/v8.h"
|
#include "third_party/v8/include/v8.h"
|
||||||
#include "third_party/v8/src/base/logging.h"
|
#include "third_party/v8/src/base/logging.h"
|
||||||
|
|
||||||
|
@ -93,10 +102,52 @@ void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||||
DenoIsolate* d = DenoIsolate::FromIsolate(isolate);
|
DenoIsolate* d = DenoIsolate::FromIsolate(isolate);
|
||||||
auto context = d->context_.Get(d->isolate_);
|
auto context = d->context_.Get(d->isolate_);
|
||||||
v8::HandleScope handle_scope(isolate);
|
v8::HandleScope handle_scope(isolate);
|
||||||
v8::String::Utf8Value str(isolate, args[0]);
|
|
||||||
bool is_err =
|
bool is_err =
|
||||||
args.Length() >= 2 ? args[1]->BooleanValue(context).ToChecked() : false;
|
args.Length() >= 2 ? args[1]->BooleanValue(context).ToChecked() : false;
|
||||||
FILE* file = is_err ? stderr : stdout;
|
FILE* file = is_err ? stderr : stdout;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
int fd = _fileno(file);
|
||||||
|
if (fd < 0) return;
|
||||||
|
|
||||||
|
HANDLE h = reinterpret_cast<HANDLE>(_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<size_t>(str.length());
|
||||||
|
auto str_wchars = reinterpret_cast<WCHAR*>(*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<DWORD>(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);
|
fwrite(*str, sizeof(**str), str.length(), file);
|
||||||
fflush(file);
|
fflush(file);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue