io-console 0.4.9 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/io/console/console.c +671 -26
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cfa5eeace30a7b2e59d986f4eaa5ed2bea9f5c2e04aa6b029d7ce59ef28e2c6f
|
4
|
+
data.tar.gz: c719d7a8e91b4ae909602bacdab03267a341a11430068ba737cc43a79392c63f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd166f563c0c8cda6ee94eacd6292068e4d681539a6f3ce42872896031634ca944a3b538f6e36232b8227c6d8cf1b95d8a94637c06c83d83a801d0fc347a5a0a
|
7
|
+
data.tar.gz: 84677613df9260493c5e9ed33e490cf520a21eb50daace16e42503cc7a70885674baa662c015c3f020ba1b076cccba01f75721539d9fec0439751613b8936a0f
|
data/ext/io/console/console.c
CHANGED
@@ -48,6 +48,7 @@ typedef struct sgttyb conmode;
|
|
48
48
|
# endif
|
49
49
|
#elif defined _WIN32
|
50
50
|
#include <winioctl.h>
|
51
|
+
#include <conio.h>
|
51
52
|
typedef DWORD conmode;
|
52
53
|
|
53
54
|
#define LAST_ERROR rb_w32_map_errno(GetLastError())
|
@@ -73,7 +74,7 @@ getattr(int fd, conmode *t)
|
|
73
74
|
#define SET_LAST_ERROR (0)
|
74
75
|
#endif
|
75
76
|
|
76
|
-
static ID id_getc, id_console, id_close, id_min, id_time;
|
77
|
+
static ID id_getc, id_console, id_close, id_min, id_time, id_intr;
|
77
78
|
#if ENABLE_IO_GETPASS
|
78
79
|
static ID id_gets;
|
79
80
|
#endif
|
@@ -100,20 +101,33 @@ rb_f_send(int argc, VALUE *argv, VALUE recv)
|
|
100
101
|
typedef struct {
|
101
102
|
int vmin;
|
102
103
|
int vtime;
|
104
|
+
int intr;
|
103
105
|
} rawmode_arg_t;
|
104
106
|
|
105
107
|
static rawmode_arg_t *
|
106
|
-
rawmode_opt(int
|
108
|
+
rawmode_opt(int *argcp, VALUE *argv, int min_argc, int max_argc, rawmode_arg_t *opts)
|
107
109
|
{
|
110
|
+
int argc = *argcp;
|
108
111
|
rawmode_arg_t *optp = NULL;
|
109
|
-
VALUE vopts;
|
110
|
-
|
112
|
+
VALUE vopts = Qnil;
|
113
|
+
if (argc > min_argc) {
|
114
|
+
vopts = rb_check_hash_type(argv[argc-1]);
|
115
|
+
if (!NIL_P(vopts)) {
|
116
|
+
argv[argc-1] = vopts;
|
117
|
+
vopts = rb_extract_keywords(&argv[argc-1]);
|
118
|
+
if (!argv[argc-1]) *argcp = --argc;
|
119
|
+
if (!vopts) vopts = Qnil;
|
120
|
+
}
|
121
|
+
}
|
122
|
+
rb_check_arity(argc, min_argc, max_argc);
|
111
123
|
if (!NIL_P(vopts)) {
|
112
124
|
VALUE vmin = rb_hash_aref(vopts, ID2SYM(id_min));
|
113
125
|
VALUE vtime = rb_hash_aref(vopts, ID2SYM(id_time));
|
126
|
+
VALUE intr = rb_hash_aref(vopts, ID2SYM(id_intr));
|
114
127
|
/* default values by `stty raw` */
|
115
128
|
opts->vmin = 1;
|
116
129
|
opts->vtime = 0;
|
130
|
+
opts->intr = 0;
|
117
131
|
if (!NIL_P(vmin)) {
|
118
132
|
opts->vmin = NUM2INT(vmin);
|
119
133
|
optp = opts;
|
@@ -124,6 +138,21 @@ rawmode_opt(int argc, VALUE *argv, rawmode_arg_t *opts)
|
|
124
138
|
opts->vtime = NUM2INT(vtime);
|
125
139
|
optp = opts;
|
126
140
|
}
|
141
|
+
switch (intr) {
|
142
|
+
case Qtrue:
|
143
|
+
opts->intr = 1;
|
144
|
+
optp = opts;
|
145
|
+
break;
|
146
|
+
case Qfalse:
|
147
|
+
opts->intr = 0;
|
148
|
+
optp = opts;
|
149
|
+
break;
|
150
|
+
case Qnil:
|
151
|
+
break;
|
152
|
+
default:
|
153
|
+
rb_raise(rb_eArgError, "true or false expected as intr: %"PRIsVALUE,
|
154
|
+
intr);
|
155
|
+
}
|
127
156
|
}
|
128
157
|
return optp;
|
129
158
|
}
|
@@ -146,13 +175,21 @@ set_rawmode(conmode *t, void *arg)
|
|
146
175
|
#elif defined _WIN32
|
147
176
|
*t = 0;
|
148
177
|
#endif
|
149
|
-
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
|
150
178
|
if (arg) {
|
151
179
|
const rawmode_arg_t *r = arg;
|
180
|
+
#ifdef VMIN
|
152
181
|
if (r->vmin >= 0) t->c_cc[VMIN] = r->vmin;
|
182
|
+
#endif
|
183
|
+
#ifdef VTIME
|
153
184
|
if (r->vtime >= 0) t->c_cc[VTIME] = r->vtime;
|
154
|
-
}
|
155
185
|
#endif
|
186
|
+
#ifdef ISIG
|
187
|
+
if (r->intr) {
|
188
|
+
t->c_iflag |= BRKINT|IXON;
|
189
|
+
t->c_lflag |= ISIG|IEXTEN;
|
190
|
+
}
|
191
|
+
#endif
|
192
|
+
}
|
156
193
|
}
|
157
194
|
|
158
195
|
static void
|
@@ -232,7 +269,7 @@ get_write_fd(const rb_io_t *fptr)
|
|
232
269
|
#define FD_PER_IO 2
|
233
270
|
|
234
271
|
static VALUE
|
235
|
-
ttymode(VALUE io, VALUE (*func)(VALUE), void (*setter)(conmode *, void *), void *arg)
|
272
|
+
ttymode(VALUE io, VALUE (*func)(VALUE), VALUE farg, void (*setter)(conmode *, void *), void *arg)
|
236
273
|
{
|
237
274
|
rb_io_t *fptr;
|
238
275
|
int status = -1;
|
@@ -263,7 +300,7 @@ ttymode(VALUE io, VALUE (*func)(VALUE), void (*setter)(conmode *, void *), void
|
|
263
300
|
}
|
264
301
|
}
|
265
302
|
if (status == 0) {
|
266
|
-
result = rb_protect(func,
|
303
|
+
result = rb_protect(func, farg, &status);
|
267
304
|
}
|
268
305
|
GetOpenFile(io, fptr);
|
269
306
|
if (fd[0] != -1 && fd[0] == GetReadFD(fptr)) {
|
@@ -287,6 +324,31 @@ ttymode(VALUE io, VALUE (*func)(VALUE), void (*setter)(conmode *, void *), void
|
|
287
324
|
return result;
|
288
325
|
}
|
289
326
|
|
327
|
+
#if !defined _WIN32
|
328
|
+
struct ttymode_callback_args {
|
329
|
+
VALUE (*func)(VALUE, VALUE);
|
330
|
+
VALUE io;
|
331
|
+
VALUE farg;
|
332
|
+
};
|
333
|
+
|
334
|
+
static VALUE
|
335
|
+
ttymode_callback(VALUE args)
|
336
|
+
{
|
337
|
+
struct ttymode_callback_args *argp = (struct ttymode_callback_args *)args;
|
338
|
+
return argp->func(argp->io, argp->farg);
|
339
|
+
}
|
340
|
+
|
341
|
+
static VALUE
|
342
|
+
ttymode_with_io(VALUE io, VALUE (*func)(VALUE, VALUE), VALUE farg, void (*setter)(conmode *, void *), void *arg)
|
343
|
+
{
|
344
|
+
struct ttymode_callback_args cargs;
|
345
|
+
cargs.func = func;
|
346
|
+
cargs.io = io;
|
347
|
+
cargs.farg = farg;
|
348
|
+
return ttymode(io, ttymode_callback, (VALUE)&cargs, setter, arg);
|
349
|
+
}
|
350
|
+
#endif
|
351
|
+
|
290
352
|
/*
|
291
353
|
* call-seq:
|
292
354
|
* io.raw(min: nil, time: nil) {|io| }
|
@@ -310,8 +372,8 @@ ttymode(VALUE io, VALUE (*func)(VALUE), void (*setter)(conmode *, void *), void
|
|
310
372
|
static VALUE
|
311
373
|
console_raw(int argc, VALUE *argv, VALUE io)
|
312
374
|
{
|
313
|
-
rawmode_arg_t opts, *optp = rawmode_opt(argc, argv, &opts);
|
314
|
-
return ttymode(io, rb_yield, set_rawmode, optp);
|
375
|
+
rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
|
376
|
+
return ttymode(io, rb_yield, io, set_rawmode, optp);
|
315
377
|
}
|
316
378
|
|
317
379
|
/*
|
@@ -332,7 +394,7 @@ console_set_raw(int argc, VALUE *argv, VALUE io)
|
|
332
394
|
conmode t;
|
333
395
|
rb_io_t *fptr;
|
334
396
|
int fd;
|
335
|
-
rawmode_arg_t opts, *optp = rawmode_opt(argc, argv, &opts);
|
397
|
+
rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
|
336
398
|
|
337
399
|
GetOpenFile(io, fptr);
|
338
400
|
fd = GetReadFD(fptr);
|
@@ -357,7 +419,7 @@ console_set_raw(int argc, VALUE *argv, VALUE io)
|
|
357
419
|
static VALUE
|
358
420
|
console_cooked(VALUE io)
|
359
421
|
{
|
360
|
-
return ttymode(io, rb_yield, set_cookedmode, NULL);
|
422
|
+
return ttymode(io, rb_yield, io, set_cookedmode, NULL);
|
361
423
|
}
|
362
424
|
|
363
425
|
/*
|
@@ -385,11 +447,35 @@ console_set_cooked(VALUE io)
|
|
385
447
|
return io;
|
386
448
|
}
|
387
449
|
|
450
|
+
#ifndef _WIN32
|
388
451
|
static VALUE
|
389
452
|
getc_call(VALUE io)
|
390
453
|
{
|
391
454
|
return rb_funcallv(io, id_getc, 0, 0);
|
392
455
|
}
|
456
|
+
#else
|
457
|
+
static VALUE
|
458
|
+
nogvl_getch(void *p)
|
459
|
+
{
|
460
|
+
int len = 0;
|
461
|
+
wint_t *buf = p, c = _getwch();
|
462
|
+
|
463
|
+
switch (c) {
|
464
|
+
case WEOF:
|
465
|
+
break;
|
466
|
+
return (VALUE)0;
|
467
|
+
case 0x00:
|
468
|
+
case 0xe0:
|
469
|
+
buf[len++] = c;
|
470
|
+
c = _getwch();
|
471
|
+
/* fall through */
|
472
|
+
default:
|
473
|
+
buf[len++] = c;
|
474
|
+
break;
|
475
|
+
}
|
476
|
+
return (VALUE)len;
|
477
|
+
}
|
478
|
+
#endif
|
393
479
|
|
394
480
|
/*
|
395
481
|
* call-seq:
|
@@ -404,8 +490,53 @@ getc_call(VALUE io)
|
|
404
490
|
static VALUE
|
405
491
|
console_getch(int argc, VALUE *argv, VALUE io)
|
406
492
|
{
|
407
|
-
rawmode_arg_t opts, *optp = rawmode_opt(argc, argv, &opts);
|
408
|
-
|
493
|
+
rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
|
494
|
+
#ifndef _WIN32
|
495
|
+
return ttymode(io, getc_call, io, set_rawmode, optp);
|
496
|
+
#else
|
497
|
+
rb_io_t *fptr;
|
498
|
+
VALUE str;
|
499
|
+
wint_t c;
|
500
|
+
int w, len;
|
501
|
+
char buf[8];
|
502
|
+
wint_t wbuf[2];
|
503
|
+
struct timeval *to = NULL, tv;
|
504
|
+
|
505
|
+
GetOpenFile(io, fptr);
|
506
|
+
if (optp) {
|
507
|
+
if (optp->vtime) {
|
508
|
+
to = &tv;
|
509
|
+
tv.tv_sec = optp->vtime / 10;
|
510
|
+
tv.tv_usec = (optp->vtime % 10) * 100000;
|
511
|
+
}
|
512
|
+
if (optp->vmin != 1) {
|
513
|
+
rb_warning("min option ignored");
|
514
|
+
}
|
515
|
+
if (optp->intr) {
|
516
|
+
w = rb_wait_for_single_fd(fptr->fd, RB_WAITFD_IN, to);
|
517
|
+
if (w < 0) rb_eof_error();
|
518
|
+
if (!(w & RB_WAITFD_IN)) return Qnil;
|
519
|
+
}
|
520
|
+
}
|
521
|
+
len = (int)rb_thread_io_blocking_region(nogvl_getch, wbuf, fptr->fd);
|
522
|
+
switch (len) {
|
523
|
+
case 0:
|
524
|
+
return Qnil;
|
525
|
+
case 2:
|
526
|
+
buf[0] = (char)wbuf[0];
|
527
|
+
c = wbuf[1];
|
528
|
+
len = 1;
|
529
|
+
do {
|
530
|
+
buf[len++] = (unsigned char)c;
|
531
|
+
} while ((c >>= CHAR_BIT) && len < (int)sizeof(buf));
|
532
|
+
return rb_str_new(buf, len);
|
533
|
+
default:
|
534
|
+
c = wbuf[0];
|
535
|
+
len = rb_uv_to_utf8(buf, c);
|
536
|
+
str = rb_utf8_str_new(buf, len);
|
537
|
+
return rb_str_conv_enc(str, NULL, rb_default_external_encoding());
|
538
|
+
}
|
539
|
+
#endif
|
409
540
|
}
|
410
541
|
|
411
542
|
/*
|
@@ -423,7 +554,7 @@ console_getch(int argc, VALUE *argv, VALUE io)
|
|
423
554
|
static VALUE
|
424
555
|
console_noecho(VALUE io)
|
425
556
|
{
|
426
|
-
return ttymode(io, rb_yield, set_noecho, NULL);
|
557
|
+
return ttymode(io, rb_yield, io, set_noecho, NULL);
|
427
558
|
}
|
428
559
|
|
429
560
|
/*
|
@@ -475,6 +606,115 @@ console_echo_p(VALUE io)
|
|
475
606
|
return echo_p(&t) ? Qtrue : Qfalse;
|
476
607
|
}
|
477
608
|
|
609
|
+
static const rb_data_type_t conmode_type = {
|
610
|
+
"console-mode",
|
611
|
+
{0, RUBY_TYPED_DEFAULT_FREE,},
|
612
|
+
0, 0,
|
613
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
614
|
+
};
|
615
|
+
static VALUE cConmode;
|
616
|
+
|
617
|
+
static VALUE
|
618
|
+
conmode_alloc(VALUE klass)
|
619
|
+
{
|
620
|
+
return rb_data_typed_object_zalloc(klass, sizeof(conmode), &conmode_type);
|
621
|
+
}
|
622
|
+
|
623
|
+
static VALUE
|
624
|
+
conmode_new(VALUE klass, const conmode *t)
|
625
|
+
{
|
626
|
+
VALUE obj = conmode_alloc(klass);
|
627
|
+
*(conmode *)DATA_PTR(obj) = *t;
|
628
|
+
return obj;
|
629
|
+
}
|
630
|
+
|
631
|
+
static VALUE
|
632
|
+
conmode_init_copy(VALUE obj, VALUE obj2)
|
633
|
+
{
|
634
|
+
conmode *t = rb_check_typeddata(obj, &conmode_type);
|
635
|
+
conmode *t2 = rb_check_typeddata(obj2, &conmode_type);
|
636
|
+
*t = *t2;
|
637
|
+
return obj;
|
638
|
+
}
|
639
|
+
|
640
|
+
static VALUE
|
641
|
+
conmode_set_echo(VALUE obj, VALUE f)
|
642
|
+
{
|
643
|
+
conmode *t = rb_check_typeddata(obj, &conmode_type);
|
644
|
+
if (RTEST(f))
|
645
|
+
set_echo(t, NULL);
|
646
|
+
else
|
647
|
+
set_noecho(t, NULL);
|
648
|
+
return obj;
|
649
|
+
}
|
650
|
+
|
651
|
+
static VALUE
|
652
|
+
conmode_set_raw(int argc, VALUE *argv, VALUE obj)
|
653
|
+
{
|
654
|
+
conmode *t = rb_check_typeddata(obj, &conmode_type);
|
655
|
+
rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
|
656
|
+
|
657
|
+
set_rawmode(t, optp);
|
658
|
+
return obj;
|
659
|
+
}
|
660
|
+
|
661
|
+
static VALUE
|
662
|
+
conmode_raw_new(int argc, VALUE *argv, VALUE obj)
|
663
|
+
{
|
664
|
+
conmode *r = rb_check_typeddata(obj, &conmode_type);
|
665
|
+
conmode t = *r;
|
666
|
+
rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
|
667
|
+
|
668
|
+
set_rawmode(&t, optp);
|
669
|
+
return conmode_new(rb_obj_class(obj), &t);
|
670
|
+
}
|
671
|
+
|
672
|
+
/*
|
673
|
+
* call-seq:
|
674
|
+
* io.console_mode -> mode
|
675
|
+
*
|
676
|
+
* Returns a data represents the current console mode.
|
677
|
+
*
|
678
|
+
* You must require 'io/console' to use this method.
|
679
|
+
*/
|
680
|
+
static VALUE
|
681
|
+
console_conmode_get(VALUE io)
|
682
|
+
{
|
683
|
+
conmode t;
|
684
|
+
rb_io_t *fptr;
|
685
|
+
int fd;
|
686
|
+
|
687
|
+
GetOpenFile(io, fptr);
|
688
|
+
fd = GetReadFD(fptr);
|
689
|
+
if (!getattr(fd, &t)) rb_sys_fail(0);
|
690
|
+
|
691
|
+
return conmode_new(cConmode, &t);
|
692
|
+
}
|
693
|
+
|
694
|
+
/*
|
695
|
+
* call-seq:
|
696
|
+
* io.console_mode = mode
|
697
|
+
*
|
698
|
+
* Sets the console mode to +mode+.
|
699
|
+
*
|
700
|
+
* You must require 'io/console' to use this method.
|
701
|
+
*/
|
702
|
+
static VALUE
|
703
|
+
console_conmode_set(VALUE io, VALUE mode)
|
704
|
+
{
|
705
|
+
conmode *t, r;
|
706
|
+
rb_io_t *fptr;
|
707
|
+
int fd;
|
708
|
+
|
709
|
+
TypedData_Get_Struct(mode, conmode, &conmode_type, t);
|
710
|
+
r = *t;
|
711
|
+
GetOpenFile(io, fptr);
|
712
|
+
fd = GetReadFD(fptr);
|
713
|
+
if (!setattr(fd, &r)) rb_sys_fail(0);
|
714
|
+
|
715
|
+
return mode;
|
716
|
+
}
|
717
|
+
|
478
718
|
#if defined TIOCGWINSZ
|
479
719
|
typedef struct winsize rb_console_size_t;
|
480
720
|
#define getwinsize(fd, buf) (ioctl((fd), TIOCGWINSZ, (buf)) == 0)
|
@@ -593,6 +833,30 @@ console_set_winsize(VALUE io, VALUE size)
|
|
593
833
|
}
|
594
834
|
#endif
|
595
835
|
|
836
|
+
#ifdef _WIN32
|
837
|
+
static VALUE
|
838
|
+
console_check_winsize_changed(VALUE io)
|
839
|
+
{
|
840
|
+
rb_io_t *fptr;
|
841
|
+
HANDLE h;
|
842
|
+
DWORD num;
|
843
|
+
|
844
|
+
GetOpenFile(io, fptr);
|
845
|
+
h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(fptr));
|
846
|
+
while (GetNumberOfConsoleInputEvents(h, &num) && num > 0) {
|
847
|
+
INPUT_RECORD rec;
|
848
|
+
if (ReadConsoleInput(h, &rec, 1, &num)) {
|
849
|
+
if (rec.EventType == WINDOW_BUFFER_SIZE_EVENT) {
|
850
|
+
rb_yield(Qnil);
|
851
|
+
}
|
852
|
+
}
|
853
|
+
}
|
854
|
+
return io;
|
855
|
+
}
|
856
|
+
#else
|
857
|
+
#define console_check_winsize_changed rb_f_notimplement
|
858
|
+
#endif
|
859
|
+
|
596
860
|
/*
|
597
861
|
* call-seq:
|
598
862
|
* io.iflush
|
@@ -688,9 +952,24 @@ console_beep(VALUE io)
|
|
688
952
|
return io;
|
689
953
|
}
|
690
954
|
|
955
|
+
static int
|
956
|
+
mode_in_range(VALUE val, int high, const char *modename)
|
957
|
+
{
|
958
|
+
int mode;
|
959
|
+
if (NIL_P(val)) return 0;
|
960
|
+
if (!RB_INTEGER_TYPE_P(val)) {
|
961
|
+
wrong_value:
|
962
|
+
rb_raise(rb_eArgError, "wrong %s mode: %"PRIsVALUE, modename, val);
|
963
|
+
}
|
964
|
+
if ((mode = NUM2INT(val)) < 0 || mode > high) {
|
965
|
+
goto wrong_value;
|
966
|
+
}
|
967
|
+
return mode;
|
968
|
+
}
|
969
|
+
|
691
970
|
#if defined _WIN32
|
692
971
|
static VALUE
|
693
|
-
console_goto(VALUE io, VALUE
|
972
|
+
console_goto(VALUE io, VALUE y, VALUE x)
|
694
973
|
{
|
695
974
|
rb_io_t *fptr;
|
696
975
|
int fd;
|
@@ -718,15 +997,159 @@ console_cursor_pos(VALUE io)
|
|
718
997
|
if (!GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), &ws)) {
|
719
998
|
rb_syserr_fail(LAST_ERROR, 0);
|
720
999
|
}
|
721
|
-
return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.
|
1000
|
+
return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.Y), UINT2NUM(ws.dwCursorPosition.X));
|
722
1001
|
}
|
723
1002
|
|
724
1003
|
static VALUE
|
725
|
-
|
1004
|
+
console_move(VALUE io, int y, int x)
|
726
1005
|
{
|
727
|
-
|
728
|
-
|
729
|
-
|
1006
|
+
rb_io_t *fptr;
|
1007
|
+
HANDLE h;
|
1008
|
+
rb_console_size_t ws;
|
1009
|
+
COORD *pos = &ws.dwCursorPosition;
|
1010
|
+
|
1011
|
+
GetOpenFile(io, fptr);
|
1012
|
+
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
|
1013
|
+
if (!GetConsoleScreenBufferInfo(h, &ws)) {
|
1014
|
+
rb_syserr_fail(LAST_ERROR, 0);
|
1015
|
+
}
|
1016
|
+
pos->X += x;
|
1017
|
+
pos->Y += y;
|
1018
|
+
if (!SetConsoleCursorPosition(h, *pos)) {
|
1019
|
+
rb_syserr_fail(LAST_ERROR, 0);
|
1020
|
+
}
|
1021
|
+
return io;
|
1022
|
+
}
|
1023
|
+
|
1024
|
+
static VALUE
|
1025
|
+
console_goto_column(VALUE io, VALUE val)
|
1026
|
+
{
|
1027
|
+
rb_io_t *fptr;
|
1028
|
+
HANDLE h;
|
1029
|
+
rb_console_size_t ws;
|
1030
|
+
COORD *pos = &ws.dwCursorPosition;
|
1031
|
+
|
1032
|
+
GetOpenFile(io, fptr);
|
1033
|
+
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
|
1034
|
+
if (!GetConsoleScreenBufferInfo(h, &ws)) {
|
1035
|
+
rb_syserr_fail(LAST_ERROR, 0);
|
1036
|
+
}
|
1037
|
+
pos->X = NUM2INT(val);
|
1038
|
+
if (!SetConsoleCursorPosition(h, *pos)) {
|
1039
|
+
rb_syserr_fail(LAST_ERROR, 0);
|
1040
|
+
}
|
1041
|
+
return io;
|
1042
|
+
}
|
1043
|
+
|
1044
|
+
static void
|
1045
|
+
constat_clear(HANDLE handle, WORD attr, DWORD len, COORD pos)
|
1046
|
+
{
|
1047
|
+
DWORD written;
|
1048
|
+
|
1049
|
+
FillConsoleOutputAttribute(handle, attr, len, pos, &written);
|
1050
|
+
FillConsoleOutputCharacterW(handle, L' ', len, pos, &written);
|
1051
|
+
}
|
1052
|
+
|
1053
|
+
static VALUE
|
1054
|
+
console_erase_line(VALUE io, VALUE val)
|
1055
|
+
{
|
1056
|
+
rb_io_t *fptr;
|
1057
|
+
HANDLE h;
|
1058
|
+
rb_console_size_t ws;
|
1059
|
+
COORD *pos = &ws.dwCursorPosition;
|
1060
|
+
DWORD w;
|
1061
|
+
int mode = mode_in_range(val, 2, "line erase");
|
1062
|
+
|
1063
|
+
GetOpenFile(io, fptr);
|
1064
|
+
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
|
1065
|
+
if (!GetConsoleScreenBufferInfo(h, &ws)) {
|
1066
|
+
rb_syserr_fail(LAST_ERROR, 0);
|
1067
|
+
}
|
1068
|
+
w = winsize_col(&ws);
|
1069
|
+
switch (mode) {
|
1070
|
+
case 0: /* after cursor */
|
1071
|
+
w -= pos->X;
|
1072
|
+
break;
|
1073
|
+
case 1: /* before *and* cursor */
|
1074
|
+
w = pos->X + 1;
|
1075
|
+
pos->X = 0;
|
1076
|
+
break;
|
1077
|
+
case 2: /* entire line */
|
1078
|
+
pos->X = 0;
|
1079
|
+
break;
|
1080
|
+
}
|
1081
|
+
constat_clear(h, ws.wAttributes, w, *pos);
|
1082
|
+
return io;
|
1083
|
+
}
|
1084
|
+
|
1085
|
+
static VALUE
|
1086
|
+
console_erase_screen(VALUE io, VALUE val)
|
1087
|
+
{
|
1088
|
+
rb_io_t *fptr;
|
1089
|
+
HANDLE h;
|
1090
|
+
rb_console_size_t ws;
|
1091
|
+
COORD *pos = &ws.dwCursorPosition;
|
1092
|
+
DWORD w;
|
1093
|
+
int mode = mode_in_range(val, 3, "screen erase");
|
1094
|
+
|
1095
|
+
GetOpenFile(io, fptr);
|
1096
|
+
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
|
1097
|
+
if (!GetConsoleScreenBufferInfo(h, &ws)) {
|
1098
|
+
rb_syserr_fail(LAST_ERROR, 0);
|
1099
|
+
}
|
1100
|
+
w = winsize_col(&ws);
|
1101
|
+
switch (mode) {
|
1102
|
+
case 0: /* erase after cursor */
|
1103
|
+
w = (w * (ws.srWindow.Bottom - pos->Y + 1) - pos->X);
|
1104
|
+
break;
|
1105
|
+
case 1: /* erase before *and* cursor */
|
1106
|
+
w = (w * (pos->Y - ws.srWindow.Top) + pos->X + 1);
|
1107
|
+
pos->X = 0;
|
1108
|
+
pos->Y = ws.srWindow.Top;
|
1109
|
+
break;
|
1110
|
+
case 2: /* erase entire screen */
|
1111
|
+
w = (w * winsize_row(&ws));
|
1112
|
+
pos->X = 0;
|
1113
|
+
pos->Y = ws.srWindow.Top;
|
1114
|
+
break;
|
1115
|
+
case 3: /* erase entire screen */
|
1116
|
+
w = (w * ws.dwSize.Y);
|
1117
|
+
pos->X = 0;
|
1118
|
+
pos->Y = 0;
|
1119
|
+
break;
|
1120
|
+
}
|
1121
|
+
constat_clear(h, ws.wAttributes, w, *pos);
|
1122
|
+
return io;
|
1123
|
+
}
|
1124
|
+
|
1125
|
+
static VALUE
|
1126
|
+
console_scroll(VALUE io, int line)
|
1127
|
+
{
|
1128
|
+
rb_io_t *fptr;
|
1129
|
+
HANDLE h;
|
1130
|
+
rb_console_size_t ws;
|
1131
|
+
|
1132
|
+
GetOpenFile(io, fptr);
|
1133
|
+
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
|
1134
|
+
if (!GetConsoleScreenBufferInfo(h, &ws)) {
|
1135
|
+
rb_syserr_fail(LAST_ERROR, 0);
|
1136
|
+
}
|
1137
|
+
if (line) {
|
1138
|
+
SMALL_RECT scroll;
|
1139
|
+
COORD destination;
|
1140
|
+
CHAR_INFO fill;
|
1141
|
+
scroll.Left = 0;
|
1142
|
+
scroll.Top = line > 0 ? line : 0;
|
1143
|
+
scroll.Right = winsize_col(&ws) - 1;
|
1144
|
+
scroll.Bottom = winsize_row(&ws) - 1 + (line < 0 ? line : 0);
|
1145
|
+
destination.X = 0;
|
1146
|
+
destination.Y = line < 0 ? -line : 0;
|
1147
|
+
fill.Char.UnicodeChar = L' ';
|
1148
|
+
fill.Attributes = ws.wAttributes;
|
1149
|
+
|
1150
|
+
ScrollConsoleScreenBuffer(h, &scroll, NULL, destination, &fill);
|
1151
|
+
}
|
1152
|
+
return io;
|
730
1153
|
}
|
731
1154
|
|
732
1155
|
#include "win32_vk.inc"
|
@@ -757,12 +1180,210 @@ console_key_pressed_p(VALUE io, VALUE k)
|
|
757
1180
|
return GetKeyState(vk) & 0x80 ? Qtrue : Qfalse;
|
758
1181
|
}
|
759
1182
|
#else
|
760
|
-
|
761
|
-
|
762
|
-
|
1183
|
+
struct query_args {
|
1184
|
+
const char *qstr;
|
1185
|
+
int opt;
|
1186
|
+
};
|
1187
|
+
|
1188
|
+
static int
|
1189
|
+
direct_query(VALUE io, const struct query_args *query)
|
1190
|
+
{
|
1191
|
+
if (RB_TYPE_P(io, T_FILE)) {
|
1192
|
+
rb_io_t *fptr;
|
1193
|
+
VALUE wio;
|
1194
|
+
GetOpenFile(io, fptr);
|
1195
|
+
wio = fptr->tied_io_for_writing;
|
1196
|
+
if (wio) {
|
1197
|
+
VALUE s = rb_str_new_cstr(query->qstr);
|
1198
|
+
rb_io_write(wio, s);
|
1199
|
+
rb_io_flush(wio);
|
1200
|
+
return 1;
|
1201
|
+
}
|
1202
|
+
if (write(fptr->fd, query->qstr, strlen(query->qstr)) != -1) {
|
1203
|
+
return 1;
|
1204
|
+
}
|
1205
|
+
if (fptr->fd == 0 &&
|
1206
|
+
write(1, query->qstr, strlen(query->qstr)) != -1) {
|
1207
|
+
return 1;
|
1208
|
+
}
|
1209
|
+
}
|
1210
|
+
return 0;
|
1211
|
+
}
|
1212
|
+
|
1213
|
+
static VALUE
|
1214
|
+
read_vt_response(VALUE io, VALUE query)
|
1215
|
+
{
|
1216
|
+
struct query_args *qargs = (struct query_args *)query;
|
1217
|
+
VALUE result, b;
|
1218
|
+
int opt = 0;
|
1219
|
+
int num = 0;
|
1220
|
+
if (qargs) {
|
1221
|
+
opt = qargs->opt;
|
1222
|
+
if (!direct_query(io, qargs)) return Qnil;
|
1223
|
+
}
|
1224
|
+
if (rb_io_getbyte(io) != INT2FIX(0x1b)) return Qnil;
|
1225
|
+
if (rb_io_getbyte(io) != INT2FIX('[')) return Qnil;
|
1226
|
+
result = rb_ary_new();
|
1227
|
+
while (!NIL_P(b = rb_io_getbyte(io))) {
|
1228
|
+
int c = NUM2UINT(b);
|
1229
|
+
if (c == ';') {
|
1230
|
+
rb_ary_push(result, INT2NUM(num));
|
1231
|
+
num = 0;
|
1232
|
+
}
|
1233
|
+
else if (ISDIGIT(c)) {
|
1234
|
+
num = num * 10 + c - '0';
|
1235
|
+
}
|
1236
|
+
else if (opt && c == opt) {
|
1237
|
+
opt = 0;
|
1238
|
+
}
|
1239
|
+
else {
|
1240
|
+
char last = (char)c;
|
1241
|
+
rb_ary_push(result, INT2NUM(num));
|
1242
|
+
b = rb_str_new(&last, 1);
|
1243
|
+
break;
|
1244
|
+
}
|
1245
|
+
}
|
1246
|
+
return rb_ary_push(result, b);
|
1247
|
+
}
|
1248
|
+
|
1249
|
+
static VALUE
|
1250
|
+
console_vt_response(int argc, VALUE *argv, VALUE io, const struct query_args *qargs)
|
1251
|
+
{
|
1252
|
+
rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 1, &opts);
|
1253
|
+
VALUE query = (VALUE)qargs;
|
1254
|
+
VALUE ret = ttymode_with_io(io, read_vt_response, query, set_rawmode, optp);
|
1255
|
+
return ret;
|
1256
|
+
}
|
1257
|
+
|
1258
|
+
static VALUE
|
1259
|
+
console_cursor_pos(VALUE io)
|
1260
|
+
{
|
1261
|
+
static const struct query_args query = {"\033[6n", 0};
|
1262
|
+
VALUE resp = console_vt_response(0, 0, io, &query);
|
1263
|
+
VALUE row, column, term;
|
1264
|
+
unsigned int r, c;
|
1265
|
+
if (!RB_TYPE_P(resp, T_ARRAY) || RARRAY_LEN(resp) != 3) return Qnil;
|
1266
|
+
term = RARRAY_AREF(resp, 2);
|
1267
|
+
if (!RB_TYPE_P(term, T_STRING) || RSTRING_LEN(term) != 1) return Qnil;
|
1268
|
+
if (RSTRING_PTR(term)[0] != 'R') return Qnil;
|
1269
|
+
row = RARRAY_AREF(resp, 0);
|
1270
|
+
column = RARRAY_AREF(resp, 1);
|
1271
|
+
rb_ary_resize(resp, 2);
|
1272
|
+
r = NUM2UINT(row) - 1;
|
1273
|
+
c = NUM2UINT(column) - 1;
|
1274
|
+
RARRAY_ASET(resp, 0, INT2NUM(r));
|
1275
|
+
RARRAY_ASET(resp, 1, INT2NUM(c));
|
1276
|
+
return resp;
|
1277
|
+
}
|
1278
|
+
|
1279
|
+
static VALUE
|
1280
|
+
console_goto(VALUE io, VALUE y, VALUE x)
|
1281
|
+
{
|
1282
|
+
rb_io_write(io, rb_sprintf("\x1b[%d;%dH", NUM2UINT(y)+1, NUM2UINT(x)+1));
|
1283
|
+
return io;
|
1284
|
+
}
|
1285
|
+
|
1286
|
+
static VALUE
|
1287
|
+
console_move(VALUE io, int y, int x)
|
1288
|
+
{
|
1289
|
+
if (x || y) {
|
1290
|
+
VALUE s = rb_str_new_cstr("");
|
1291
|
+
if (y) rb_str_catf(s, "\x1b[%d%c", y < 0 ? -y : y, y < 0 ? 'A' : 'B');
|
1292
|
+
if (x) rb_str_catf(s, "\x1b[%d%c", x < 0 ? -x : x, x < 0 ? 'D' : 'C');
|
1293
|
+
rb_io_write(io, s);
|
1294
|
+
rb_io_flush(io);
|
1295
|
+
}
|
1296
|
+
return io;
|
1297
|
+
}
|
1298
|
+
|
1299
|
+
static VALUE
|
1300
|
+
console_goto_column(VALUE io, VALUE val)
|
1301
|
+
{
|
1302
|
+
rb_io_write(io, rb_sprintf("\x1b[%dG", NUM2UINT(val)+1));
|
1303
|
+
return io;
|
1304
|
+
}
|
1305
|
+
|
1306
|
+
static VALUE
|
1307
|
+
console_erase_line(VALUE io, VALUE val)
|
1308
|
+
{
|
1309
|
+
int mode = mode_in_range(val, 2, "line erase");
|
1310
|
+
rb_io_write(io, rb_sprintf("\x1b[%dK", mode));
|
1311
|
+
return io;
|
1312
|
+
}
|
1313
|
+
|
1314
|
+
static VALUE
|
1315
|
+
console_erase_screen(VALUE io, VALUE val)
|
1316
|
+
{
|
1317
|
+
int mode = mode_in_range(val, 3, "screen erase");
|
1318
|
+
rb_io_write(io, rb_sprintf("\x1b[%dJ", mode));
|
1319
|
+
return io;
|
1320
|
+
}
|
1321
|
+
|
1322
|
+
static VALUE
|
1323
|
+
console_scroll(VALUE io, int line)
|
1324
|
+
{
|
1325
|
+
if (line) {
|
1326
|
+
VALUE s = rb_sprintf("\x1b[%d%c", line < 0 ? -line : line,
|
1327
|
+
line < 0 ? 'T' : 'S');
|
1328
|
+
rb_io_write(io, s);
|
1329
|
+
}
|
1330
|
+
return io;
|
1331
|
+
}
|
763
1332
|
# define console_key_pressed_p rb_f_notimplement
|
764
1333
|
#endif
|
765
1334
|
|
1335
|
+
static VALUE
|
1336
|
+
console_cursor_set(VALUE io, VALUE cpos)
|
1337
|
+
{
|
1338
|
+
cpos = rb_convert_type(cpos, T_ARRAY, "Array", "to_ary");
|
1339
|
+
if (RARRAY_LEN(cpos) != 2) rb_raise(rb_eArgError, "expected 2D coordinate");
|
1340
|
+
return console_goto(io, RARRAY_AREF(cpos, 0), RARRAY_AREF(cpos, 1));
|
1341
|
+
}
|
1342
|
+
|
1343
|
+
static VALUE
|
1344
|
+
console_cursor_up(VALUE io, VALUE val)
|
1345
|
+
{
|
1346
|
+
return console_move(io, -NUM2INT(val), 0);
|
1347
|
+
}
|
1348
|
+
|
1349
|
+
static VALUE
|
1350
|
+
console_cursor_down(VALUE io, VALUE val)
|
1351
|
+
{
|
1352
|
+
return console_move(io, +NUM2INT(val), 0);
|
1353
|
+
}
|
1354
|
+
|
1355
|
+
static VALUE
|
1356
|
+
console_cursor_left(VALUE io, VALUE val)
|
1357
|
+
{
|
1358
|
+
return console_move(io, 0, -NUM2INT(val));
|
1359
|
+
}
|
1360
|
+
|
1361
|
+
static VALUE
|
1362
|
+
console_cursor_right(VALUE io, VALUE val)
|
1363
|
+
{
|
1364
|
+
return console_move(io, 0, +NUM2INT(val));
|
1365
|
+
}
|
1366
|
+
|
1367
|
+
static VALUE
|
1368
|
+
console_scroll_forward(VALUE io, VALUE val)
|
1369
|
+
{
|
1370
|
+
return console_scroll(io, +NUM2INT(val));
|
1371
|
+
}
|
1372
|
+
|
1373
|
+
static VALUE
|
1374
|
+
console_scroll_backward(VALUE io, VALUE val)
|
1375
|
+
{
|
1376
|
+
return console_scroll(io, -NUM2INT(val));
|
1377
|
+
}
|
1378
|
+
|
1379
|
+
static VALUE
|
1380
|
+
console_clear_screen(VALUE io)
|
1381
|
+
{
|
1382
|
+
console_erase_screen(io, INT2FIX(2));
|
1383
|
+
console_goto(io, INT2FIX(0), INT2FIX(0));
|
1384
|
+
return io;
|
1385
|
+
}
|
1386
|
+
|
766
1387
|
/*
|
767
1388
|
* call-seq:
|
768
1389
|
* IO.console -> #<File:/dev/tty>
|
@@ -882,7 +1503,7 @@ puts_call(VALUE io)
|
|
882
1503
|
static VALUE
|
883
1504
|
getpass_call(VALUE io)
|
884
1505
|
{
|
885
|
-
return ttymode(io, rb_io_gets, set_noecho, NULL);
|
1506
|
+
return ttymode(io, rb_io_gets, io, set_noecho, NULL);
|
886
1507
|
}
|
887
1508
|
|
888
1509
|
static void
|
@@ -891,7 +1512,6 @@ prompt(int argc, VALUE *argv, VALUE io)
|
|
891
1512
|
if (argc > 0 && !NIL_P(argv[0])) {
|
892
1513
|
VALUE str = argv[0];
|
893
1514
|
StringValueCStr(str);
|
894
|
-
rb_check_safe_obj(str);
|
895
1515
|
rb_io_write(io, str);
|
896
1516
|
}
|
897
1517
|
}
|
@@ -961,6 +1581,7 @@ Init_console(void)
|
|
961
1581
|
id_close = rb_intern("close");
|
962
1582
|
id_min = rb_intern("min");
|
963
1583
|
id_time = rb_intern("time");
|
1584
|
+
id_intr = rb_intern("intr");
|
964
1585
|
#ifndef HAVE_RB_F_SEND
|
965
1586
|
id___send__ = rb_intern("__send__");
|
966
1587
|
#endif
|
@@ -977,6 +1598,8 @@ InitVM_console(void)
|
|
977
1598
|
rb_define_method(rb_cIO, "getch", console_getch, -1);
|
978
1599
|
rb_define_method(rb_cIO, "echo=", console_set_echo, 1);
|
979
1600
|
rb_define_method(rb_cIO, "echo?", console_echo_p, 0);
|
1601
|
+
rb_define_method(rb_cIO, "console_mode", console_conmode_get, 0);
|
1602
|
+
rb_define_method(rb_cIO, "console_mode=", console_conmode_set, 1);
|
980
1603
|
rb_define_method(rb_cIO, "noecho", console_noecho, 0);
|
981
1604
|
rb_define_method(rb_cIO, "winsize", console_winsize, 0);
|
982
1605
|
rb_define_method(rb_cIO, "winsize=", console_set_winsize, 1);
|
@@ -987,7 +1610,18 @@ InitVM_console(void)
|
|
987
1610
|
rb_define_method(rb_cIO, "goto", console_goto, 2);
|
988
1611
|
rb_define_method(rb_cIO, "cursor", console_cursor_pos, 0);
|
989
1612
|
rb_define_method(rb_cIO, "cursor=", console_cursor_set, 1);
|
1613
|
+
rb_define_method(rb_cIO, "cursor_up", console_cursor_up, 1);
|
1614
|
+
rb_define_method(rb_cIO, "cursor_down", console_cursor_down, 1);
|
1615
|
+
rb_define_method(rb_cIO, "cursor_left", console_cursor_left, 1);
|
1616
|
+
rb_define_method(rb_cIO, "cursor_right", console_cursor_right, 1);
|
1617
|
+
rb_define_method(rb_cIO, "goto_column", console_goto_column, 1);
|
1618
|
+
rb_define_method(rb_cIO, "erase_line", console_erase_line, 1);
|
1619
|
+
rb_define_method(rb_cIO, "erase_screen", console_erase_screen, 1);
|
1620
|
+
rb_define_method(rb_cIO, "scroll_forward", console_scroll_forward, 1);
|
1621
|
+
rb_define_method(rb_cIO, "scroll_backward", console_scroll_backward, 1);
|
1622
|
+
rb_define_method(rb_cIO, "clear_screen", console_clear_screen, 0);
|
990
1623
|
rb_define_method(rb_cIO, "pressed?", console_key_pressed_p, 1);
|
1624
|
+
rb_define_method(rb_cIO, "check_winsize_changed", console_check_winsize_changed, 0);
|
991
1625
|
#if ENABLE_IO_GETPASS
|
992
1626
|
rb_define_method(rb_cIO, "getpass", console_getpass, -1);
|
993
1627
|
#endif
|
@@ -999,4 +1633,15 @@ InitVM_console(void)
|
|
999
1633
|
rb_define_method(mReadable, "getpass", io_getpass, -1);
|
1000
1634
|
#endif
|
1001
1635
|
}
|
1636
|
+
{
|
1637
|
+
/* :stopdoc: */
|
1638
|
+
cConmode = rb_define_class_under(rb_cIO, "ConsoleMode", rb_cObject);
|
1639
|
+
rb_define_alloc_func(cConmode, conmode_alloc);
|
1640
|
+
rb_undef_method(cConmode, "initialize");
|
1641
|
+
rb_define_method(cConmode, "initialize_copy", conmode_init_copy, 1);
|
1642
|
+
rb_define_method(cConmode, "echo=", conmode_set_echo, 1);
|
1643
|
+
rb_define_method(cConmode, "raw!", conmode_set_raw, -1);
|
1644
|
+
rb_define_method(cConmode, "raw", conmode_raw_new, -1);
|
1645
|
+
/* :startdoc: */
|
1646
|
+
}
|
1002
1647
|
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: io-console
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nobu Nakada
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-06-05 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: add console capabilities to IO instances.
|
14
14
|
email: nobu@ruby-lang.org
|
@@ -43,7 +43,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
43
43
|
- !ruby/object:Gem::Version
|
44
44
|
version: '0'
|
45
45
|
requirements: []
|
46
|
-
rubygems_version: 3.1.0.
|
46
|
+
rubygems_version: 3.1.0.pre3
|
47
47
|
signing_key:
|
48
48
|
specification_version: 4
|
49
49
|
summary: Console interface
|