diff --git a/ports/atmel-samd/mpconfigport.mk b/ports/atmel-samd/mpconfigport.mk index 3dde2885d1f68..c2961e4165f23 100644 --- a/ports/atmel-samd/mpconfigport.mk +++ b/ports/atmel-samd/mpconfigport.mk @@ -59,6 +59,8 @@ CIRCUITPY_ZLIB = 0 # Turn off a few more things that don't fit in 192kB +CIRCUITPY_TERMINALIO_VT100 = 0 + ifeq ($(INTERNAL_FLASH_FILESYSTEM),1) CIRCUITPY_ONEWIREIO ?= 0 CIRCUITPY_SAFEMODE_PY ?= 0 diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 3a240ba1e1db7..69ebd03e8b295 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -552,6 +552,9 @@ CFLAGS += -DCIRCUITPY_SYS=$(CIRCUITPY_SYS) CIRCUITPY_TERMINALIO ?= $(CIRCUITPY_DISPLAYIO) CFLAGS += -DCIRCUITPY_TERMINALIO=$(CIRCUITPY_TERMINALIO) +CIRCUITPY_TERMINALIO_VT100 ?= $(CIRCUITPY_TERMINALIO) +CFLAGS += -DCIRCUITPY_TERMINALIO_VT100=$(CIRCUITPY_TERMINALIO_VT100) + CIRCUITPY_FONTIO ?= $(call enable-if-all,$(CIRCUITPY_DISPLAYIO) $(CIRCUITPY_TERMINALIO)) CFLAGS += -DCIRCUITPY_FONTIO=$(CIRCUITPY_FONTIO) diff --git a/shared-bindings/terminalio/Terminal.c b/shared-bindings/terminalio/Terminal.c index d2e5485dcf347..5d79c88c60839 100644 --- a/shared-bindings/terminalio/Terminal.c +++ b/shared-bindings/terminalio/Terminal.c @@ -30,11 +30,18 @@ //| //| VT100 control sequences: //| * ``ESC [ K`` - Clear the remainder of the line +//| * ``ESC [ 0 K`` - Clear the remainder of the line +//| * ``ESC [ 1 K`` - Clear start of the line to cursor +//| * ``ESC [ 2 K`` - Clear the entire line //| * ``ESC [ #### D`` - Move the cursor to the left by #### //| * ``ESC [ 2 J`` - Erase the entire display //| * ``ESC [ nnnn ; mmmm H`` - Move the cursor to mmmm, nnnn. -//| * ``ESC [ nn m`` - Set the terminal display attributes. -//| * ``ESC [ nn ; nn m`` - Set the terminal display attributes. +//| * ``ESC [ H`` - Move the cursor to 0,0. +//| * ``ESC M`` - Move the cursor up one line, scrolling if necessary. +//| * ``ESC D`` - Move the cursor down one line, scrolling if necessary. +//| * ``ESC [ ## m`` - Set the terminal display attributes. +//| * ``ESC [ ## ; ## m`` - Set the terminal display attributes. +//| * ``ESC [ ## ; ## ; ## m`` - Set the terminal display attributes. //| //| Supported Display attributes: //| 0 - Reset all attributes diff --git a/shared-module/terminalio/Terminal.c b/shared-module/terminalio/Terminal.c index 6b6fb5402178b..d2cedf0661874 100644 --- a/shared-module/terminalio/Terminal.c +++ b/shared-module/terminalio/Terminal.c @@ -47,6 +47,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con return len; } + #if CIRCUITPY_TERMINALIO_VT100 uint32_t _select_color(uint16_t ascii_color) { uint32_t color_value = 0; if ((ascii_color & 1) > 0) { @@ -63,6 +64,8 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con } displayio_palette_t *terminal_palette = self->scroll_area->pixel_shader; + #endif + const byte *i = data; uint16_t start_y = self->cursor_y; while (i < data + len) { @@ -111,99 +114,149 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con } } else if (c == 0x1b) { // Handle commands of the form [ESC]. where . is not yet known. - uint16_t n = 0; + uint8_t vt_args[3] = {0, -1, -1}; uint8_t j = 1; + #if CIRCUITPY_TERMINALIO_VT100 + uint8_t n_args = 1; + #endif for (; j < 6; j++) { if ('0' <= i[j] && i[j] <= '9') { - n = n * 10 + (i[j] - '0'); + vt_args[0] = vt_args[0] * 10 + (i[j] - '0'); } else { c = i[j]; break; } } if (i[0] == '[') { - if (i[1] == 'K') { - // Clear the rest of the line. - for (uint16_t k = self->cursor_x; k < self->scroll_area->width_in_tiles; k++) { - common_hal_displayio_tilegrid_set_tile(self->scroll_area, k, self->cursor_y, 0); + for (uint8_t i_args = 1; i_args < 3 && c == ';'; i_args++) { + vt_args[i_args] = 0; + for (++j; j < 12; j++) { + if ('0' <= i[j] && i[j] <= '9') { + vt_args[i_args] = vt_args[i_args] * 10 + (i[j] - '0'); + #if CIRCUITPY_TERMINALIO_VT100 + n_args = i_args + 1; + #endif + } else { + c = i[j]; + break; + } + } + } + if (c == '?') { + #if CIRCUITPY_TERMINALIO_VT100 + if (i[2] == '2' && i[3] == '5') { + // cursor visibility commands + if (i[4] == 'h') { + // make cursor visible + // not implemented yet + } else if (i[4] == 'l') { + // make cursor invisible + // not implemented yet + } } - i += 2; + i += 5; + #endif } else { - if (c == 'D') { - if (n > self->cursor_x) { + if (c == 'K') { + uint8_t clr_start = self->cursor_x; + uint8_t clr_end = self->scroll_area->width_in_tiles; + #if CIRCUITPY_TERMINALIO_VT100 + if (vt_args[0] == 1) { + clr_start = 0; + clr_end = self->cursor_x; + } else if (vt_args[0] == 2) { + clr_start = 0; + } + #endif + // Clear the (start/rest/all) of the line. + for (uint16_t k = clr_start; k < clr_end; k++) { + common_hal_displayio_tilegrid_set_tile(self->scroll_area, k, self->cursor_y, 0); + } + } else if (c == 'D') { + if (vt_args[0] > self->cursor_x) { self->cursor_x = 0; } else { - self->cursor_x -= n; + self->cursor_x -= vt_args[0]; } - } - if (c == 'J') { - if (n == 2) { + } else if (c == 'J') { + if (vt_args[0] == 2) { common_hal_displayio_tilegrid_set_top_left(self->scroll_area, 0, 0); self->cursor_x = self->cursor_y = start_y = 0; - n = 0; common_hal_displayio_tilegrid_set_all_tiles(self->scroll_area, 0); } - } - if (c == 'm') { - if ((n >= 40 && n <= 47) || (n >= 30 && n <= 37)) { - common_hal_displayio_palette_set_color(terminal_palette, 1 - (n / 40), _select_color(n % 10)); + } else if (c == 'H') { + if (vt_args[0] > 0) { + vt_args[0]--; } - if (n == 0) { - common_hal_displayio_palette_set_color(terminal_palette, 0, 0x000000); - common_hal_displayio_palette_set_color(terminal_palette, 1, 0xffffff); + if (vt_args[1] == -1) { + vt_args[1] = 0; } - } - if (c == ';') { - uint16_t m = 0; - for (++j; j < 9; j++) { - if ('0' <= i[j] && i[j] <= '9') { - m = m * 10 + (i[j] - '0'); - } else { - c = i[j]; - break; - } + if (vt_args[1] > 0) { + vt_args[1]--; } - if (c == 'H') { - if (n > 0) { - n--; - } - if (m > 0) { - m--; - } - if (n >= self->scroll_area->height_in_tiles) { - n = self->scroll_area->height_in_tiles - 1; - } - if (m >= self->scroll_area->width_in_tiles) { - m = self->scroll_area->width_in_tiles - 1; - } - n = (n + self->scroll_area->top_left_y) % self->scroll_area->height_in_tiles; - self->cursor_x = m; - self->cursor_y = n; - start_y = self->cursor_y; + if (vt_args[0] >= self->scroll_area->height_in_tiles) { + vt_args[0] = self->scroll_area->height_in_tiles - 1; } - if (c == 'm') { - if ((n >= 40 && n <= 47) || (n >= 30 && n <= 37)) { - common_hal_displayio_palette_set_color(terminal_palette, 1 - (n / 40), _select_color(n % 10)); - } - if (n == 0) { - common_hal_displayio_palette_set_color(terminal_palette, 0, 0x000000); - common_hal_displayio_palette_set_color(terminal_palette, 1, 0xffffff); - } - if ((m >= 40 && m <= 47) || (m >= 30 && m <= 37)) { - common_hal_displayio_palette_set_color(terminal_palette, 1 - (m / 40), _select_color(m % 10)); + if (vt_args[1] >= self->scroll_area->width_in_tiles) { + vt_args[1] = self->scroll_area->width_in_tiles - 1; + } + vt_args[0] = (vt_args[0] + self->scroll_area->top_left_y) % self->scroll_area->height_in_tiles; + self->cursor_x = vt_args[1]; + self->cursor_y = vt_args[0]; + start_y = self->cursor_y; + #if CIRCUITPY_TERMINALIO_VT100 + } else if (c == 'm') { + for (uint8_t i_args = 0; i_args < n_args; i_args++) { + if ((vt_args[i_args] >= 40 && vt_args[i_args] <= 47) || (vt_args[i_args] >= 30 && vt_args[i_args] <= 37)) { + common_hal_displayio_palette_set_color(terminal_palette, 1 - (vt_args[i_args] / 40), _select_color(vt_args[i_args] % 10)); } - if (m == 0) { + if (vt_args[i_args] == 0) { common_hal_displayio_palette_set_color(terminal_palette, 0, 0x000000); common_hal_displayio_palette_set_color(terminal_palette, 1, 0xffffff); } } + #endif } i += j + 1; - continue; } + #if CIRCUITPY_TERMINALIO_VT100 + } else if (i[0] == 'M') { + if (self->cursor_y != self->scroll_area->top_left_y) { + if (self->cursor_y > 0) { + self->cursor_y = self->cursor_y - 1; + } else { + self->cursor_y = self->scroll_area->height_in_tiles - 1; + } + } else { + if (self->cursor_y > 0) { + common_hal_displayio_tilegrid_set_top_left(self->scroll_area, 0, self->cursor_y - 1); + } else { + common_hal_displayio_tilegrid_set_top_left(self->scroll_area, 0, self->scroll_area->height_in_tiles - 1); + } + for (uint8_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { + common_hal_displayio_tilegrid_set_tile(self->scroll_area, icol, self->scroll_area->top_left_y, 0); + } + + self->cursor_x = 0; + self->cursor_y = self->scroll_area->top_left_y; + } + start_y = self->cursor_y; + i++; + } else if (i[0] == 'D') { + self->cursor_y = (self->cursor_y + 1) % self->scroll_area->height_in_tiles; + if (self->cursor_y == self->scroll_area->top_left_y) { + common_hal_displayio_tilegrid_set_top_left(self->scroll_area, 0, (self->cursor_y + 1) % self->scroll_area->height_in_tiles); + for (uint8_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { + common_hal_displayio_tilegrid_set_tile(self->scroll_area, icol, self->cursor_y, 0); + } + self->cursor_x = 0; + } + start_y = self->cursor_y; + i++; + #endif } else if (i[0] == ']' && c == ';') { self->in_osc_command = true; - self->osc_command = n; + self->osc_command = vt_args[0]; i += j + 1; } }