mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[dart:io] Move Platform.ansiSupported to {Stdin,Stdout}.supportsAnsiEscapes
On Windows, some Windows 10 builds support only ANSI output, but not input, so these need to be separated. I'm also improving the detection on Mac and Linux to avoid hardcoding the result. Instead, supportsAnsiEscapes will be true if isatty() and the TERM environment variable contains the string 'xterm'. related #28614 R=lrn@google.com Review-Url: https://codereview.chromium.org/2753233002 .
This commit is contained in:
parent
09886f491f
commit
b3093ecee6
|
@ -14,7 +14,7 @@
|
||||||
* `dart:io`: Added functions `File.lastAccessed`, `File.lastAccessedSync`,
|
* `dart:io`: Added functions `File.lastAccessed`, `File.lastAccessedSync`,
|
||||||
`File.setLastModified`, `File.setLastModifiedSync`, `File.setLastAccessed`,
|
`File.setLastModified`, `File.setLastModifiedSync`, `File.setLastAccessed`,
|
||||||
and `File.setLastAccessedSync`.
|
and `File.setLastAccessedSync`.
|
||||||
* `dart:io`: Added `Platform.ansiSupported`.
|
* `dart:io`: Added `{Stdin,Stdout}.supportsAnsiEscapes`.
|
||||||
|
|
||||||
### Dart VM
|
### Dart VM
|
||||||
* Calls to `print()` and `Stdout.write*()` now correctly print unicode
|
* Calls to `print()` and `Stdout.write*()` now correctly print unicode
|
||||||
|
|
|
@ -92,7 +92,6 @@ namespace bin {
|
||||||
V(Platform_Environment, 0) \
|
V(Platform_Environment, 0) \
|
||||||
V(Platform_ExecutableArguments, 0) \
|
V(Platform_ExecutableArguments, 0) \
|
||||||
V(Platform_GetVersion, 0) \
|
V(Platform_GetVersion, 0) \
|
||||||
V(Platform_AnsiSupported, 0) \
|
|
||||||
V(Process_Start, 11) \
|
V(Process_Start, 11) \
|
||||||
V(Process_Wait, 5) \
|
V(Process_Wait, 5) \
|
||||||
V(Process_KillPid, 2) \
|
V(Process_KillPid, 2) \
|
||||||
|
@ -148,7 +147,9 @@ namespace bin {
|
||||||
V(Stdin_SetEchoMode, 1) \
|
V(Stdin_SetEchoMode, 1) \
|
||||||
V(Stdin_GetLineMode, 0) \
|
V(Stdin_GetLineMode, 0) \
|
||||||
V(Stdin_SetLineMode, 1) \
|
V(Stdin_SetLineMode, 1) \
|
||||||
|
V(Stdin_AnsiSupported, 0) \
|
||||||
V(Stdout_GetTerminalSize, 1) \
|
V(Stdout_GetTerminalSize, 1) \
|
||||||
|
V(Stdout_AnsiSupported, 1) \
|
||||||
V(StringToSystemEncoding, 1) \
|
V(StringToSystemEncoding, 1) \
|
||||||
V(SystemEncodingToString, 1) \
|
V(SystemEncodingToString, 1) \
|
||||||
V(X509_Subject, 1) \
|
V(X509_Subject, 1) \
|
||||||
|
|
|
@ -109,11 +109,6 @@ void FUNCTION_NAME(Platform_GetVersion)(Dart_NativeArguments args) {
|
||||||
Dart_SetReturnValue(args, Dart_NewStringFromCString(Dart_VersionString()));
|
Dart_SetReturnValue(args, Dart_NewStringFromCString(Dart_VersionString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FUNCTION_NAME(Platform_AnsiSupported)(Dart_NativeArguments args) {
|
|
||||||
Dart_SetBooleanReturnValue(args, Platform::AnsiSupported());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace bin
|
} // namespace bin
|
||||||
} // namespace dart
|
} // namespace dart
|
||||||
|
|
||||||
|
|
|
@ -83,8 +83,6 @@ class Platform {
|
||||||
static int GetScriptIndex() { return script_index_; }
|
static int GetScriptIndex() { return script_index_; }
|
||||||
static char** GetArgv() { return argv_; }
|
static char** GetArgv() { return argv_; }
|
||||||
|
|
||||||
static bool AnsiSupported();
|
|
||||||
|
|
||||||
static DART_NORETURN void Exit(int exit_code);
|
static DART_NORETURN void Exit(int exit_code);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -85,11 +85,6 @@ const char* Platform::ResolveExecutablePath() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Platform::AnsiSupported() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Platform::Exit(int exit_code) {
|
void Platform::Exit(int exit_code) {
|
||||||
exit(exit_code);
|
exit(exit_code);
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,11 +109,6 @@ const char* Platform::ResolveExecutablePath() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Platform::AnsiSupported() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Platform::Exit(int exit_code) {
|
void Platform::Exit(int exit_code) {
|
||||||
exit(exit_code);
|
exit(exit_code);
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,11 +110,6 @@ const char* Platform::ResolveExecutablePath() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Platform::AnsiSupported() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Platform::Exit(int exit_code) {
|
void Platform::Exit(int exit_code) {
|
||||||
exit(exit_code);
|
exit(exit_code);
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,11 +154,6 @@ const char* Platform::ResolveExecutablePath() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Platform::AnsiSupported() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Platform::Exit(int exit_code) {
|
void Platform::Exit(int exit_code) {
|
||||||
exit(exit_code);
|
exit(exit_code);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
native "Platform_ExecutableArguments";
|
native "Platform_ExecutableArguments";
|
||||||
@patch static String _version()
|
@patch static String _version()
|
||||||
native "Platform_GetVersion";
|
native "Platform_GetVersion";
|
||||||
@patch static bool _ansiSupported()
|
|
||||||
native "Platform_AnsiSupported";
|
|
||||||
|
|
||||||
@patch static String _packageRoot()
|
@patch static String _packageRoot()
|
||||||
=> VMLibraryHooks.packageRootString;
|
=> VMLibraryHooks.packageRootString;
|
||||||
|
|
|
@ -64,12 +64,6 @@ void FUNCTION_NAME(Platform_GetVersion)(Dart_NativeArguments args) {
|
||||||
"Platform is not supported on this platform"));
|
"Platform is not supported on this platform"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FUNCTION_NAME(Platform_AnsiSupported)(Dart_NativeArguments args) {
|
|
||||||
Dart_ThrowException(DartUtils::NewInternalError(
|
|
||||||
"Platform is not supported on this platform"));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace bin
|
} // namespace bin
|
||||||
} // namespace dart
|
} // namespace dart
|
||||||
|
|
||||||
|
|
|
@ -83,23 +83,18 @@ class PlatformWin {
|
||||||
SetConsoleOutputCP(CP_UTF8);
|
SetConsoleOutputCP(CP_UTF8);
|
||||||
SetConsoleCP(CP_UTF8);
|
SetConsoleCP(CP_UTF8);
|
||||||
|
|
||||||
ansi_supported_ = true;
|
// Try to set the bits for ANSI support, but swallow any failures.
|
||||||
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
|
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
DWORD out_mode;
|
DWORD out_mode;
|
||||||
if ((out != INVALID_HANDLE_VALUE) && GetConsoleMode(out, &out_mode)) {
|
if ((out != INVALID_HANDLE_VALUE) && GetConsoleMode(out, &out_mode)) {
|
||||||
const DWORD request = out_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
const DWORD request = out_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
ansi_supported_ = ansi_supported_ && SetConsoleMode(out, request);
|
SetConsoleMode(out, request);
|
||||||
} else {
|
|
||||||
ansi_supported_ = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
|
HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
DWORD in_mode;
|
DWORD in_mode;
|
||||||
if ((in != INVALID_HANDLE_VALUE) && GetConsoleMode(in, &in_mode)) {
|
if ((in != INVALID_HANDLE_VALUE) && GetConsoleMode(in, &in_mode)) {
|
||||||
const DWORD request = in_mode | ENABLE_VIRTUAL_TERMINAL_INPUT;
|
const DWORD request = in_mode | ENABLE_VIRTUAL_TERMINAL_INPUT;
|
||||||
ansi_supported_ = ansi_supported_ && SetConsoleMode(in, request);
|
SetConsoleMode(in, request);
|
||||||
} else {
|
|
||||||
ansi_supported_ = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,13 +103,10 @@ class PlatformWin {
|
||||||
RestoreConsoleLocked();
|
RestoreConsoleLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ansi_supported() { return ansi_supported_; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Mutex* platform_win_mutex_;
|
static Mutex* platform_win_mutex_;
|
||||||
static int saved_output_cp_;
|
static int saved_output_cp_;
|
||||||
static int saved_input_cp_;
|
static int saved_input_cp_;
|
||||||
static bool ansi_supported_;
|
|
||||||
|
|
||||||
static void RestoreConsoleLocked() {
|
static void RestoreConsoleLocked() {
|
||||||
// STD_OUTPUT_HANDLE and STD_INPUT_HANDLE may have been closed or
|
// STD_OUTPUT_HANDLE and STD_INPUT_HANDLE may have been closed or
|
||||||
|
@ -179,7 +171,6 @@ class PlatformWin {
|
||||||
int PlatformWin::saved_output_cp_ = -1;
|
int PlatformWin::saved_output_cp_ = -1;
|
||||||
int PlatformWin::saved_input_cp_ = -1;
|
int PlatformWin::saved_input_cp_ = -1;
|
||||||
Mutex* PlatformWin::platform_win_mutex_ = NULL;
|
Mutex* PlatformWin::platform_win_mutex_ = NULL;
|
||||||
bool PlatformWin::ansi_supported_ = false;
|
|
||||||
|
|
||||||
bool Platform::Initialize() {
|
bool Platform::Initialize() {
|
||||||
PlatformWin::InitOnce();
|
PlatformWin::InitOnce();
|
||||||
|
@ -276,11 +267,6 @@ const char* Platform::ResolveExecutablePath() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Platform::AnsiSupported() {
|
|
||||||
return PlatformWin::ansi_supported();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Platform::Exit(int exit_code) {
|
void Platform::Exit(int exit_code) {
|
||||||
// TODO(zra): Remove once VM shuts down cleanly.
|
// TODO(zra): Remove once VM shuts down cleanly.
|
||||||
::dart::private_flag_windows_run_tls_destructors = false;
|
::dart::private_flag_windows_run_tls_destructors = false;
|
||||||
|
|
|
@ -69,6 +69,16 @@ void FUNCTION_NAME(Stdin_SetLineMode)(Dart_NativeArguments args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FUNCTION_NAME(Stdin_AnsiSupported)(Dart_NativeArguments args) {
|
||||||
|
bool supported = false;
|
||||||
|
if (Stdin::AnsiSupported(&supported)) {
|
||||||
|
Dart_SetBooleanReturnValue(args, supported);
|
||||||
|
} else {
|
||||||
|
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void FUNCTION_NAME(Stdout_GetTerminalSize)(Dart_NativeArguments args) {
|
void FUNCTION_NAME(Stdout_GetTerminalSize)(Dart_NativeArguments args) {
|
||||||
if (!Dart_IsInteger(Dart_GetNativeArgument(args, 0))) {
|
if (!Dart_IsInteger(Dart_GetNativeArgument(args, 0))) {
|
||||||
OSError os_error(-1, "Invalid argument", OSError::kUnknown);
|
OSError os_error(-1, "Invalid argument", OSError::kUnknown);
|
||||||
|
@ -92,6 +102,26 @@ void FUNCTION_NAME(Stdout_GetTerminalSize)(Dart_NativeArguments args) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FUNCTION_NAME(Stdout_AnsiSupported)(Dart_NativeArguments args) {
|
||||||
|
if (!Dart_IsInteger(Dart_GetNativeArgument(args, 0))) {
|
||||||
|
OSError os_error(-1, "Invalid argument", OSError::kUnknown);
|
||||||
|
Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
intptr_t fd = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 0));
|
||||||
|
if ((fd != 1) && (fd != 2)) {
|
||||||
|
Dart_SetReturnValue(args, Dart_NewApiError("Terminal fd must be 1 or 2"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool supported = false;
|
||||||
|
if (Stdout::AnsiSupported(fd, &supported)) {
|
||||||
|
Dart_SetBooleanReturnValue(args, supported);
|
||||||
|
} else {
|
||||||
|
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace bin
|
} // namespace bin
|
||||||
} // namespace dart
|
} // namespace dart
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ class Stdin {
|
||||||
static bool GetLineMode(bool* enabled);
|
static bool GetLineMode(bool* enabled);
|
||||||
static bool SetLineMode(bool enabled);
|
static bool SetLineMode(bool enabled);
|
||||||
|
|
||||||
|
static bool AnsiSupported(bool* supported);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_ALLOCATION();
|
DISALLOW_ALLOCATION();
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Stdin);
|
DISALLOW_IMPLICIT_CONSTRUCTORS(Stdin);
|
||||||
|
@ -36,6 +38,7 @@ class Stdin {
|
||||||
class Stdout {
|
class Stdout {
|
||||||
public:
|
public:
|
||||||
static bool GetTerminalSize(intptr_t fd, int size[2]);
|
static bool GetTerminalSize(intptr_t fd, int size[2]);
|
||||||
|
static bool AnsiSupported(intptr_t fd, bool* supported);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_ALLOCATION();
|
DISALLOW_ALLOCATION();
|
||||||
|
|
|
@ -83,6 +83,21 @@ bool Stdin::SetLineMode(bool enabled) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool TermHasXTerm() {
|
||||||
|
const char* term = getenv("TERM");
|
||||||
|
if (term == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return strstr(term, "xterm") != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Stdin::AnsiSupported(bool* supported) {
|
||||||
|
*supported = isatty(STDIN_FILENO) && TermHasXTerm();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
|
bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
|
||||||
struct winsize w;
|
struct winsize w;
|
||||||
int status = NO_RETRY_EXPECTED(ioctl(fd, TIOCGWINSZ, &w));
|
int status = NO_RETRY_EXPECTED(ioctl(fd, TIOCGWINSZ, &w));
|
||||||
|
@ -94,6 +109,12 @@ bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Stdout::AnsiSupported(intptr_t fd, bool* supported) {
|
||||||
|
*supported = isatty(fd) && TermHasXTerm();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace bin
|
} // namespace bin
|
||||||
} // namespace dart
|
} // namespace dart
|
||||||
|
|
||||||
|
|
|
@ -42,11 +42,23 @@ bool Stdin::SetLineMode(bool enabled) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Stdin::AnsiSupported(bool* supported) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
|
bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Stdout::AnsiSupported(intptr_t fd, bool* supported) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace bin
|
} // namespace bin
|
||||||
} // namespace dart
|
} // namespace dart
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,21 @@ bool Stdin::SetLineMode(bool enabled) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool TermHasXTerm() {
|
||||||
|
const char* term = getenv("TERM");
|
||||||
|
if (term == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return strstr(term, "xterm") != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Stdin::AnsiSupported(bool* supported) {
|
||||||
|
*supported = isatty(STDIN_FILENO) && TermHasXTerm();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
|
bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
|
||||||
struct winsize w;
|
struct winsize w;
|
||||||
int status = NO_RETRY_EXPECTED(ioctl(fd, TIOCGWINSZ, &w));
|
int status = NO_RETRY_EXPECTED(ioctl(fd, TIOCGWINSZ, &w));
|
||||||
|
@ -94,6 +109,12 @@ bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Stdout::AnsiSupported(intptr_t fd, bool* supported) {
|
||||||
|
*supported = isatty(fd) && TermHasXTerm();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace bin
|
} // namespace bin
|
||||||
} // namespace dart
|
} // namespace dart
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,21 @@ bool Stdin::SetLineMode(bool enabled) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool TermHasXTerm() {
|
||||||
|
const char* term = getenv("TERM");
|
||||||
|
if (term == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return strstr(term, "xterm") != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Stdin::AnsiSupported(bool* supported) {
|
||||||
|
*supported = isatty(STDIN_FILENO) && TermHasXTerm();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
|
bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
|
||||||
struct winsize w;
|
struct winsize w;
|
||||||
int status = NO_RETRY_EXPECTED(ioctl(fd, TIOCGWINSZ, &w));
|
int status = NO_RETRY_EXPECTED(ioctl(fd, TIOCGWINSZ, &w));
|
||||||
|
@ -94,6 +109,12 @@ bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Stdout::AnsiSupported(intptr_t fd, bool* supported) {
|
||||||
|
*supported = isatty(fd) && TermHasXTerm();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace bin
|
} // namespace bin
|
||||||
} // namespace dart
|
} // namespace dart
|
||||||
|
|
||||||
|
|
|
@ -83,11 +83,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@patch bool get supportsAnsiEscapes {
|
||||||
|
var result = _supportsAnsiEscapes();
|
||||||
|
if (result is OSError) {
|
||||||
|
throw new StdinException("Error determining ANSI support", result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static _echoMode() native "Stdin_GetEchoMode";
|
static _echoMode() native "Stdin_GetEchoMode";
|
||||||
static _setEchoMode(bool enabled) native "Stdin_SetEchoMode";
|
static _setEchoMode(bool enabled) native "Stdin_SetEchoMode";
|
||||||
static _lineMode() native "Stdin_GetLineMode";
|
static _lineMode() native "Stdin_GetLineMode";
|
||||||
static _setLineMode(bool enabled) native "Stdin_SetLineMode";
|
static _setLineMode(bool enabled) native "Stdin_SetLineMode";
|
||||||
static _readByte() native "Stdin_ReadByte";
|
static _readByte() native "Stdin_ReadByte";
|
||||||
|
static _supportsAnsiEscapes() native "Stdin_AnsiSupported";
|
||||||
}
|
}
|
||||||
|
|
||||||
@patch class Stdout {
|
@patch class Stdout {
|
||||||
|
@ -112,6 +121,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
static _getTerminalSize(int fd) native "Stdout_GetTerminalSize";
|
static _getTerminalSize(int fd) native "Stdout_GetTerminalSize";
|
||||||
|
|
||||||
|
@patch static bool _supportsAnsiEscapes(int fd) {
|
||||||
|
var result = _getAnsiSupported(fd);
|
||||||
|
if (result is! bool) {
|
||||||
|
throw new StdoutException("Error determining ANSI support", result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static _getAnsiSupported(int fd) native "Stdout_AnsiSupported";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,11 +41,23 @@ void FUNCTION_NAME(Stdin_SetLineMode)(Dart_NativeArguments args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FUNCTION_NAME(Stdin_AnsiSupported)(Dart_NativeArguments args) {
|
||||||
|
Dart_ThrowException(
|
||||||
|
DartUtils::NewDartArgumentError("Stdin unsupported on this platform"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void FUNCTION_NAME(Stdout_GetTerminalSize)(Dart_NativeArguments args) {
|
void FUNCTION_NAME(Stdout_GetTerminalSize)(Dart_NativeArguments args) {
|
||||||
Dart_ThrowException(
|
Dart_ThrowException(
|
||||||
DartUtils::NewDartArgumentError("Stdout unsupported on this platform"));
|
DartUtils::NewDartArgumentError("Stdout unsupported on this platform"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FUNCTION_NAME(Stdout_AnsiSupported)(Dart_NativeArguments args) {
|
||||||
|
Dart_ThrowException(
|
||||||
|
DartUtils::NewDartArgumentError("Stdout unsupported on this platform"));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace bin
|
} // namespace bin
|
||||||
} // namespace dart
|
} // namespace dart
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,16 @@
|
||||||
|
|
||||||
#include "bin/stdio.h"
|
#include "bin/stdio.h"
|
||||||
|
|
||||||
|
// These are not always defined in the header files. See:
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
|
||||||
|
#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT
|
||||||
|
#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||||
|
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace dart {
|
namespace dart {
|
||||||
namespace bin {
|
namespace bin {
|
||||||
|
|
||||||
|
@ -77,6 +87,23 @@ bool Stdin::SetLineMode(bool enabled) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Stdin::AnsiSupported(bool* supported) {
|
||||||
|
ASSERT(supported != NULL);
|
||||||
|
HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
if (h == INVALID_HANDLE_VALUE) {
|
||||||
|
*supported = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DWORD mode;
|
||||||
|
if (!GetConsoleMode(h, &mode)) {
|
||||||
|
*supported = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*supported = (mode & ENABLE_VIRTUAL_TERMINAL_INPUT) != 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
|
bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
if (fd == 1) {
|
if (fd == 1) {
|
||||||
|
@ -93,6 +120,28 @@ bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Stdout::AnsiSupported(intptr_t fd, bool* supported) {
|
||||||
|
ASSERT(supported != NULL);
|
||||||
|
HANDLE h;
|
||||||
|
if (fd == 1) {
|
||||||
|
h = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
} else {
|
||||||
|
h = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
}
|
||||||
|
if (h == INVALID_HANDLE_VALUE) {
|
||||||
|
*supported = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DWORD mode;
|
||||||
|
if (!GetConsoleMode(h, &mode)) {
|
||||||
|
*supported = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*supported = (mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace bin
|
} // namespace bin
|
||||||
} // namespace dart
|
} // namespace dart
|
||||||
|
|
||||||
|
|
|
@ -250,11 +250,6 @@ class _Platform {
|
||||||
static String _version() {
|
static String _version() {
|
||||||
throw new UnsupportedError("Platform._version");
|
throw new UnsupportedError("Platform._version");
|
||||||
}
|
}
|
||||||
|
|
||||||
@patch
|
|
||||||
static bool _ansiSupported() {
|
|
||||||
throw new UnsupportedError("Platform._ansiSupported");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@ -550,6 +545,11 @@ class Stdin {
|
||||||
void set lineMode(bool enabled) {
|
void set lineMode(bool enabled) {
|
||||||
throw new UnsupportedError("Stdin.lineMode");
|
throw new UnsupportedError("Stdin.lineMode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@patch
|
||||||
|
bool get supportsAnsiEscapes {
|
||||||
|
throw new UnsupportedError("Stdin.supportsAnsiEscapes");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
@ -568,6 +568,11 @@ class Stdout {
|
||||||
int _terminalLines(int fd) {
|
int _terminalLines(int fd) {
|
||||||
throw new UnsupportedError("Stdout.terminalLines");
|
throw new UnsupportedError("Stdout.terminalLines");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@patch
|
||||||
|
static bool _supportsAnsiEscapes(int fd) {
|
||||||
|
throw new UnsupportedError("Stdout.supportsAnsiEscapes");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@patch
|
@patch
|
||||||
|
|
|
@ -71,7 +71,6 @@ class Platform {
|
||||||
static final _operatingSystem = _Platform.operatingSystem;
|
static final _operatingSystem = _Platform.operatingSystem;
|
||||||
static final _localHostname = _Platform.localHostname;
|
static final _localHostname = _Platform.localHostname;
|
||||||
static final _version = _Platform.version;
|
static final _version = _Platform.version;
|
||||||
static final _ansiSupported = _Platform.ansiSupported;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of processors of the machine.
|
* Get the number of processors of the machine.
|
||||||
|
@ -125,14 +124,6 @@ class Platform {
|
||||||
*/
|
*/
|
||||||
static final bool isFuchsia = (_operatingSystem == "fuchsia");
|
static final bool isFuchsia = (_operatingSystem == "fuchsia");
|
||||||
|
|
||||||
/**
|
|
||||||
* When stdio is connected to a terminal, whether ANSI codes are supported.
|
|
||||||
*
|
|
||||||
* This value is hard-coded to `true`, except on Windows where only more
|
|
||||||
* recent versions of Windows 10 support the codes.
|
|
||||||
*/
|
|
||||||
static final bool ansiSupported = _ansiSupported;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the environment for this process.
|
* Get the environment for this process.
|
||||||
*
|
*
|
||||||
|
|
|
@ -11,7 +11,6 @@ class _Platform {
|
||||||
external static _localHostname();
|
external static _localHostname();
|
||||||
external static _executable();
|
external static _executable();
|
||||||
external static _resolvedExecutable();
|
external static _resolvedExecutable();
|
||||||
external static bool _ansiSupported();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the entries of the process environment.
|
* Retrieve the entries of the process environment.
|
||||||
|
@ -46,7 +45,6 @@ class _Platform {
|
||||||
static int get numberOfProcessors => _numberOfProcessors();
|
static int get numberOfProcessors => _numberOfProcessors();
|
||||||
static String get pathSeparator => _pathSeparator();
|
static String get pathSeparator => _pathSeparator();
|
||||||
static String get operatingSystem => _operatingSystem();
|
static String get operatingSystem => _operatingSystem();
|
||||||
static bool get ansiSupported => _ansiSupported();
|
|
||||||
static Uri script;
|
static Uri script;
|
||||||
|
|
||||||
static String get localHostname {
|
static String get localHostname {
|
||||||
|
|
|
@ -136,6 +136,30 @@ class Stdin extends _StdStream implements Stream<List<int>> {
|
||||||
*/
|
*/
|
||||||
external void set lineMode(bool enabled);
|
external void set lineMode(bool enabled);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether connected to a terminal that supports ANSI escape sequences.
|
||||||
|
*
|
||||||
|
* Not all terminals are recognized, and not all recognized terminals can
|
||||||
|
* report whether they support ANSI escape sequences, so this value is a
|
||||||
|
* best-effort attempt at detecting the support.
|
||||||
|
*
|
||||||
|
* The actual escape sequence support may differ between terminals,
|
||||||
|
* with some terminals supporting more escape sequences than others,
|
||||||
|
* and some terminals even differing in behavior for the same escape
|
||||||
|
* sequence.
|
||||||
|
*
|
||||||
|
* The ANSI color selection is generally supported.
|
||||||
|
*
|
||||||
|
* Currently, a `TERM` environment variable containing the string `xterm`
|
||||||
|
* will be taken as evidence that ANSI escape sequences are supported.
|
||||||
|
* On Windows, only versions of Windows 10 after v.1511
|
||||||
|
* ("TH2", OS build 10586) will be detected as supporting the output of
|
||||||
|
* ANSI escape sequences, and only versions after v.1607 ("Anniversery
|
||||||
|
* Update", OS build 14393) will be detected as supporting the input of
|
||||||
|
* ANSI escape sequences.
|
||||||
|
*/
|
||||||
|
external bool get supportsAnsiEscapes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronously read a byte from stdin. This call will block until a byte is
|
* Synchronously read a byte from stdin. This call will block until a byte is
|
||||||
* available.
|
* available.
|
||||||
|
@ -178,7 +202,7 @@ class Stdout extends _StdFileSink implements IOSink {
|
||||||
*/
|
*/
|
||||||
int get terminalColumns => _terminalColumns(_fd);
|
int get terminalColumns => _terminalColumns(_fd);
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Get the number of lines of the terminal.
|
* Get the number of lines of the terminal.
|
||||||
*
|
*
|
||||||
* If no terminal is attached to stdout, a [StdoutException] is thrown. See
|
* If no terminal is attached to stdout, a [StdoutException] is thrown. See
|
||||||
|
@ -186,9 +210,34 @@ class Stdout extends _StdFileSink implements IOSink {
|
||||||
*/
|
*/
|
||||||
int get terminalLines => _terminalLines(_fd);
|
int get terminalLines => _terminalLines(_fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether connected to a terminal that supports ANSI escape sequences.
|
||||||
|
*
|
||||||
|
* Not all terminals are recognized, and not all recognized terminals can
|
||||||
|
* report whether they support ANSI escape sequences, so this value is a
|
||||||
|
* best-effort attempt at detecting the support.
|
||||||
|
*
|
||||||
|
* The actual escape sequence support may differ between terminals,
|
||||||
|
* with some terminals supporting more escape sequences than others,
|
||||||
|
* and some terminals even differing in behavior for the same escape
|
||||||
|
* sequence.
|
||||||
|
*
|
||||||
|
* The ANSI color selection is generally supported.
|
||||||
|
*
|
||||||
|
* Currently, a `TERM` environment variable containing the string `xterm`
|
||||||
|
* will be taken as evidence that ANSI escape sequences are supported.
|
||||||
|
* On Windows, only versions of Windows 10 after v.1511
|
||||||
|
* ("TH2", OS build 10586) will be detected as supporting the output of
|
||||||
|
* ANSI escape sequences, and only versions after v.1607 ("Anniversery
|
||||||
|
* Update", OS build 14393) will be detected as supporting the input of
|
||||||
|
* ANSI escape sequences.
|
||||||
|
*/
|
||||||
|
bool get supportsAnsiEscapes => _supportsAnsiEscapes(_fd);
|
||||||
|
|
||||||
external bool _hasTerminal(int fd);
|
external bool _hasTerminal(int fd);
|
||||||
external int _terminalColumns(int fd);
|
external int _terminalColumns(int fd);
|
||||||
external int _terminalLines(int fd);
|
external int _terminalLines(int fd);
|
||||||
|
external static bool _supportsAnsiEscapes(int fd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a non-blocking `IOSink`.
|
* Get a non-blocking `IOSink`.
|
||||||
|
|
|
@ -6,18 +6,30 @@ import 'dart:io';
|
||||||
|
|
||||||
import "package:expect/expect.dart";
|
import "package:expect/expect.dart";
|
||||||
|
|
||||||
main() {
|
testStdout(Stdout s) {
|
||||||
try {
|
try {
|
||||||
Platform.ansiSupported;
|
s.supportsAnsiEscapes;
|
||||||
} catch (e, s) {
|
} catch (e, st) {
|
||||||
Expect.fail("Platform.ansiSupported threw: $e\n$s\n");
|
Expect.fail("$s.supportsAnsiEscapes threw: $e\n$st\n");
|
||||||
}
|
}
|
||||||
Expect.isNotNull(Platform.ansiSupported);
|
Expect.isNotNull(s.supportsAnsiEscapes);
|
||||||
Expect.isTrue(Platform.ansiSupported is bool);
|
Expect.isTrue(s.supportsAnsiEscapes is bool);
|
||||||
if (stdout.hasTerminal && Platform.ansiSupported) {
|
if (s.supportsAnsiEscapes) {
|
||||||
stdout.writeln('\x1b[31mThis text has a red foreground using SGR.31.');
|
s.writeln('\x1b[31mThis text has a red foreground using SGR.31.');
|
||||||
stdout.writeln('\x1b[39mThis text has restored the foreground color.');
|
s.writeln('\x1b[39mThis text has restored the foreground color.');
|
||||||
} else {
|
} else {
|
||||||
stdout.writeln('ANSI codes not supported on this platform');
|
s.writeln('ANSI escape codes are not supported on this platform');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
testStdout(stdout);
|
||||||
|
testStdout(stderr);
|
||||||
|
try {
|
||||||
|
stdin.supportsAnsiEscapes;
|
||||||
|
} catch (e, st) {
|
||||||
|
Expect.fail("stdin.supportsAnsiEscapes threw: $e\n$st\n");
|
||||||
|
}
|
||||||
|
Expect.isNotNull(stdin.supportsAnsiEscapes);
|
||||||
|
Expect.isTrue(stdin.supportsAnsiEscapes is bool);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue