1
0
forked from Mirror/wren

Add Stdin.isRaw.

This commit is contained in:
Bob Nystrom
2016-05-20 15:19:18 -07:00
parent 500dd41ccd
commit 5d98d20175
6 changed files with 103 additions and 19 deletions

View File

@ -4,6 +4,18 @@ The standard input stream.
## Static Methods
### **isRaw**
Returns `true` if stdin is in raw mode. When in raw mode, input is not echoed
or buffered, and all characters, even non-printing and control characters go
into stdin.
Defaults to `false`.
### **isRaw**=(value)
Sets raw mode on or off.
### **readByte**()
Reads one byte of input from stdin. Blocks the current fiber until a byte has

View File

@ -35,6 +35,8 @@ extern void statSpecialDevice(WrenVM* vm);
extern void statUser(WrenVM* vm);
extern void statIsDirectory(WrenVM* vm);
extern void statIsFile(WrenVM* vm);
extern void stdinIsRaw(WrenVM* vm);
extern void stdinIsRawSet(WrenVM* vm);
extern void stdinReadStart(WrenVM* vm);
extern void stdinReadStop(WrenVM* vm);
extern void schedulerCaptureMethods(WrenVM* vm);
@ -141,6 +143,8 @@ static ModuleRegistry modules[] =
METHOD("isFile", statIsFile)
END_CLASS
CLASS(Stdin)
STATIC_METHOD("isRaw", stdinIsRaw)
STATIC_METHOD("isRaw=(_)", stdinIsRawSet)
STATIC_METHOD("readStart_()", stdinReadStart)
STATIC_METHOD("readStop_()", stdinReadStop)
END_CLASS

View File

@ -46,6 +46,9 @@ static WrenValue* stdinOnData = NULL;
// The stream used to read from stdin. Initialized on the first read.
static uv_stream_t* stdinStream = NULL;
// True if stdin has been set to raw mode.
static bool isStdinRaw = false;
// Frees all resources related to stdin.
static void shutdownStdin()
{
@ -67,6 +70,8 @@ static void shutdownStdin()
wrenReleaseValue(getVM(), stdinOnData);
stdinOnData = NULL;
}
uv_tty_reset_mode();
}
void ioShutdown()
@ -487,6 +492,53 @@ void statIsFile(WrenVM* vm)
wrenSetSlotBool(vm, 0, S_ISREG(stat->st_mode));
}
// Sets up the stdin stream if not already initialized.
static void initStdin()
{
if (stdinStream == NULL)
{
if (uv_guess_handle(stdinDescriptor) == UV_TTY)
{
// stdin is connected to a terminal.
uv_tty_t* handle = (uv_tty_t*)malloc(sizeof(uv_tty_t));
uv_tty_init(getLoop(), handle, stdinDescriptor, true);
stdinStream = (uv_stream_t*)handle;
}
else
{
// stdin is a pipe or a file.
uv_pipe_t* handle = (uv_pipe_t*)malloc(sizeof(uv_pipe_t));
uv_pipe_init(getLoop(), handle, false);
uv_pipe_open(handle, stdinDescriptor);
stdinStream = (uv_stream_t*)handle;
}
}
}
void stdinIsRaw(WrenVM* vm)
{
wrenSetSlotBool(vm, 0, isStdinRaw);
}
void stdinIsRawSet(WrenVM* vm)
{
initStdin();
isStdinRaw = wrenGetSlotBool(vm, 1);
if (uv_guess_handle(stdinDescriptor) == UV_TTY)
{
uv_tty_t* handle = (uv_tty_t*)stdinStream;
uv_tty_set_mode(handle, isStdinRaw ? UV_TTY_MODE_RAW : UV_TTY_MODE_NORMAL);
}
else
{
// Can't set raw mode when not talking to a TTY.
// TODO: Make this a runtime error?
}
}
static void allocCallback(uv_handle_t* handle, size_t suggestedSize,
uv_buf_t* buf)
{
@ -540,25 +592,7 @@ static void stdinReadCallback(uv_stream_t* stream, ssize_t numRead,
void stdinReadStart(WrenVM* vm)
{
if (stdinStream == NULL)
{
if (uv_guess_handle(stdinDescriptor) == UV_TTY)
{
// stdin is connected to a terminal.
uv_tty_t* handle = (uv_tty_t*)malloc(sizeof(uv_tty_t));
uv_tty_init(getLoop(), handle, stdinDescriptor, true);
stdinStream = (uv_stream_t*)handle;
}
else
{
// stdin is a pipe or a file.
uv_pipe_t* handle = (uv_pipe_t*)malloc(sizeof(uv_pipe_t));
uv_pipe_init(getLoop(), handle, false);
uv_pipe_open(handle, stdinDescriptor);
stdinStream = (uv_stream_t*)handle;
}
}
initStdin();
uv_read_start(stdinStream, allocCallback, stdinReadCallback);
// TODO: Check return.
}

View File

@ -215,6 +215,9 @@ foreign class Stat {
}
class Stdin {
foreign static isRaw
foreign static isRaw=(value)
static readByte() {
return read_ {
// Peel off the first byte.

View File

@ -217,6 +217,9 @@ static const char* ioModuleSource =
"}\n"
"\n"
"class Stdin {\n"
" foreign static isRaw\n"
" foreign static isRaw=(value)\n"
"\n"
" static readByte() {\n"
" return read_ {\n"
" // Peel off the first byte.\n"

28
test/io/stdin/is_raw.wren Normal file
View File

@ -0,0 +1,28 @@
import "io" for Stdin
// Defaults to false.
System.print(Stdin.isRaw) // expect: false
// stdin: abcdefgh
for (i in 1..4) {
System.print(Stdin.readByte())
}
// expect: 97
// expect: 98
// expect: 99
// expect: 100
Stdin.isRaw = true
System.print(Stdin.isRaw) // expect: true
for (i in 1..4) {
System.print(Stdin.readByte())
}
// expect: 101
// expect: 102
// expect: 103
// expect: 104
// TODO: This doesn't actually detect a visible difference between raw and
// non-raw mode. Maybe add support to the test runner for writing non-printing
// characters to stdin?