Skip to content

Commit e634410

Browse files
committed
Added line/screen erase methods
1 parent 143a9d5 commit e634410

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed

ext/io/console/console.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,21 @@ console_beep(VALUE io)
766766
return io;
767767
}
768768

769+
static int
770+
mode_in_range(VALUE val, int high, const char *modename)
771+
{
772+
int mode;
773+
if (NIL_P(val)) return 0;
774+
if (!RB_INTEGER_TYPE_P(val)) {
775+
wrong_value:
776+
rb_raise(rb_eArgError, "wrong %s mode: %"PRIsVALUE, modename, val);
777+
}
778+
if ((mode = NUM2INT(val)) < 0 || mode > high) {
779+
goto wrong_value;
780+
}
781+
return mode;
782+
}
783+
769784
#if defined _WIN32
770785
static VALUE
771786
console_goto(VALUE io, VALUE x, VALUE y)
@@ -839,6 +854,87 @@ console_goto_column(VALUE io, VALUE val)
839854
}
840855
return io;
841856
}
857+
858+
static void
859+
constat_clear(HANDLE handle, WORD attr, DWORD len, COORD pos)
860+
{
861+
DWORD written;
862+
863+
FillConsoleOutputAttribute(handle, attr, len, pos, &written);
864+
FillConsoleOutputCharacterW(handle, L' ', len, pos, &written);
865+
}
866+
867+
static VALUE
868+
console_erase_line(VALUE io, VALUE val)
869+
{
870+
rb_io_t *fptr;
871+
HANDLE h;
872+
rb_console_size_t ws;
873+
COORD *pos = &ws.dwCursorPosition;
874+
DWORD written, w;
875+
int mode = mode_in_range(val, 2, "line erase");
876+
877+
GetOpenFile(io, fptr);
878+
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
879+
if (!GetConsoleScreenBufferInfo(h, &ws)) {
880+
rb_syserr_fail(LAST_ERROR, 0);
881+
}
882+
w = winsize_col(&ws);
883+
switch (mode) {
884+
case 0: /* after cursor */
885+
w -= pos->X;
886+
break;
887+
case 1: /* before *and* cursor */
888+
w = pos->X + 1;
889+
pos->X = 0;
890+
break;
891+
case 2: /* entire line */
892+
pos->X = 0;
893+
break;
894+
}
895+
constat_clear(h, ws.wAttributes, w, *pos);
896+
return io;
897+
}
898+
899+
static VALUE
900+
console_erase_screen(VALUE io, VALUE val)
901+
{
902+
rb_io_t *fptr;
903+
HANDLE h;
904+
rb_console_size_t ws;
905+
COORD *pos = &ws.dwCursorPosition;
906+
DWORD written, w;
907+
int mode = mode_in_range(val, 3, "screen erase");
908+
909+
GetOpenFile(io, fptr);
910+
h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
911+
if (!GetConsoleScreenBufferInfo(h, &ws)) {
912+
rb_syserr_fail(LAST_ERROR, 0);
913+
}
914+
w = winsize_col(&ws);
915+
switch (mode) {
916+
case 0: /* erase after cursor */
917+
w = (w * (ws.srWindow.Bottom - pos->Y + 1) - pos->X);
918+
break;
919+
case 1: /* erase before *and* cursor */
920+
w = (w * (pos->Y - ws.srWindow.Top) + pos->X + 1);
921+
pos->X = 0;
922+
pos->Y = ws.srWindow.Top;
923+
break;
924+
case 2: /* erase entire screen */
925+
w = (w * winsize_row(&ws));
926+
pos->X = 0;
927+
pos->Y = ws.srWindow.Top;
928+
break;
929+
case 3: /* erase entire screen */
930+
w = (w * ws.dwSize.Y);
931+
pos->X = 0;
932+
pos->Y = 0;
933+
break;
934+
}
935+
constat_clear(h, ws.wAttributes, w, *pos);
936+
return io;
937+
}
842938
#include "win32_vk.inc"
843939

844940
static VALUE
@@ -949,6 +1045,22 @@ console_goto_column(VALUE io, VALUE val)
9491045
rb_io_write(io, rb_sprintf("\x1b[%dG", NUM2UINT(val)+1));
9501046
return io;
9511047
}
1048+
1049+
static VALUE
1050+
console_erase_line(VALUE io, VALUE val)
1051+
{
1052+
int mode = mode_in_range(val, 2, "line erase");
1053+
rb_io_write(io, rb_sprintf("\x1b[%dK", mode));
1054+
return io;
1055+
}
1056+
1057+
static VALUE
1058+
console_erase_screen(VALUE io, VALUE val)
1059+
{
1060+
int mode = mode_in_range(val, 3, "screen erase");
1061+
rb_io_write(io, rb_sprintf("\x1b[%dJ", mode));
1062+
return io;
1063+
}
9521064
# define console_key_pressed_p rb_f_notimplement
9531065
#endif
9541066

@@ -1221,6 +1333,9 @@ InitVM_console(void)
12211333
rb_define_method(rb_cIO, "cursor_left", console_cursor_left, 1);
12221334
rb_define_method(rb_cIO, "cursor_right", console_cursor_right, 1);
12231335
rb_define_method(rb_cIO, "goto_column", console_goto_column, 1);
1336+
rb_define_method(rb_cIO, "erase_line", console_erase_line, 1);
1337+
rb_define_method(rb_cIO, "erase_screen", console_erase_screen, 1);
1338+
rb_define_method(rb_cIO, "clear_screen", console_clear_screen, 0);
12241339
rb_define_method(rb_cIO, "pressed?", console_key_pressed_p, 1);
12251340
#if ENABLE_IO_GETPASS
12261341
rb_define_method(rb_cIO, "getpass", console_getpass, -1);

0 commit comments

Comments
 (0)