forked from Mirror/wren
Add Stdin.isRaw.
This commit is contained in:
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
28
test/io/stdin/is_raw.wren
Normal 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?
|
||||
Reference in New Issue
Block a user