:: commit af013833dd841cf457a93d573d3ea8d6f7fa954f

mintsuki <mintsuki@protonmail.com> — 2022-01-18 22:46

parents: 105de293ce

term: Support for reverse scroll, save/restore, and bug fixes

diff --git a/stage23/drivers/vga_textmode.h b/stage23/drivers/vga_textmode.h
index 8800e9df..1c76c357 100644
--- a/stage23/drivers/vga_textmode.h
+++ b/stage23/drivers/vga_textmode.h
@@ -23,7 +23,10 @@ bool text_scroll_disable(void);
 void text_scroll_enable(void);
 void text_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y);
 void text_scroll(void);
+void text_revscroll(void);
 void text_swap_palette(void);
+void text_save_state(void);
+void text_restore_state(void);
 
 void text_double_buffer(bool state);
 void text_double_buffer_flush(void);
diff --git a/stage23/drivers/vga_textmode.s2.c b/stage23/drivers/vga_textmode.s2.c
index f3a97cfb..1982f11b 100644
--- a/stage23/drivers/vga_textmode.s2.c
+++ b/stage23/drivers/vga_textmode.s2.c
@@ -29,6 +29,11 @@ static struct context {
 #define text_palette context.text_palette
     bool scroll_enabled;
 #define scroll_enabled context.scroll_enabled
+
+    uint8_t saved_state_text_palette;
+#define saved_state_text_palette context.saved_state_text_palette
+    size_t saved_state_cursor_offset;
+#define saved_state_cursor_offset context.saved_state_cursor_offset
 } context;
 
 static size_t old_cursor_offset = 0;
@@ -38,6 +43,16 @@ static void draw_cursor(void) {
     video_mem[cursor_offset + 1] = ((pal & 0xf0) >> 4) | ((pal & 0x0f) << 4);
 }
 
+void text_save_state(void) {
+    saved_state_text_palette = text_palette;
+    saved_state_cursor_offset = cursor_offset;
+}
+
+void text_restore_state(void) {
+    text_palette = saved_state_text_palette;
+    cursor_offset = saved_state_cursor_offset;
+}
+
 void text_swap_palette(void) {
     text_palette = (text_palette << 4) | (text_palette >> 4);
 }
@@ -66,6 +81,22 @@ void text_scroll(void) {
     }
 }
 
+void text_revscroll(void) {
+    // move the text up by one row
+    for (size_t i = (term_context.scroll_bottom_margin - 1) * VD_COLS - 2; ; i--) {
+        back_buffer[i + VD_COLS] = back_buffer[i];
+        if (i == term_context.scroll_top_margin * VD_COLS) {
+            break;
+        }
+    }
+    // clear the first line of the screen
+    for (size_t i = term_context.scroll_top_margin * VD_COLS;
+         i < (term_context.scroll_top_margin + 1) * VD_COLS; i += 2) {
+        back_buffer[i] = ' ';
+        back_buffer[i + 1] = text_palette;
+    }
+}
+
 void text_clear(bool move) {
     for (size_t i = 0; i < VIDEO_BOTTOM; i += 2) {
         back_buffer[i] = ' ';
diff --git a/stage23/lib/gterm.c b/stage23/lib/gterm.c
index 94681c3d..ce685547 100644
--- a/stage23/lib/gterm.c
+++ b/stage23/lib/gterm.c
@@ -89,19 +89,40 @@ static struct context {
 #define cursor_x context.cursor_x
     size_t cursor_y;
 #define cursor_y context.cursor_y
+    bool scroll_enabled;
+#define scroll_enabled context.scroll_enabled
+
+    uint32_t saved_state_text_fg;
+#define saved_state_text_fg context.saved_state_text_fg
+    uint32_t saved_state_text_bg;
+#define saved_state_text_bg context.saved_state_text_bg
+    size_t saved_state_cursor_x;
+#define saved_state_cursor_x context.saved_state_cursor_x
+    size_t saved_state_cursor_y;
+#define saved_state_cursor_y context.saved_state_cursor_y
 } context;
 
 static size_t old_cursor_x = 0;
 static size_t old_cursor_y = 0;
 
+void gterm_save_state(void) {
+    saved_state_text_fg = text_fg;
+    saved_state_text_bg = text_bg;
+    saved_state_cursor_x = cursor_x;
+    saved_state_cursor_y = cursor_y;
+}
+
+void gterm_restore_state(void) {
+    text_fg = saved_state_text_fg;
+    text_bg = saved_state_text_bg;
+    cursor_x = saved_state_cursor_x;
+    cursor_y = saved_state_cursor_y;
+}
+
 void gterm_swap_palette(void) {
     uint32_t tmp = text_bg;
     text_bg = text_fg;
-    if (tmp == 0xffffffff) {
-        text_fg = default_bg;
-    } else {
-        text_fg = tmp;
-    }
+    text_fg = tmp;
 }
 
 #define A(rgb) (uint8_t)(rgb >> 24)
@@ -353,8 +374,6 @@ static void push_to_queue(struct gterm_char *c, size_t x, size_t y) {
     q->c = *c;
 }
 
-static bool scroll_enabled = true;
-
 bool gterm_scroll_disable(void) {
     bool ret = scroll_enabled;
     scroll_enabled = false;
@@ -365,6 +384,32 @@ void gterm_scroll_enable(void) {
     scroll_enabled = true;
 }
 
+void gterm_revscroll(void) {
+    for (size_t i = (term_context.scroll_bottom_margin - 1) * cols - 1; ; i--) {
+        struct gterm_char *c;
+        struct queue_item *q = map[i];
+        if (q != NULL) {
+            c = &q->c;
+        } else {
+            c = &grid[i];
+        }
+        push_to_queue(c, (i + cols) % cols, (i + cols) / cols);
+        if (i == term_context.scroll_top_margin * cols) {
+            break;
+        }
+    }
+
+    // Clear the first line of the screen.
+    struct gterm_char empty;
+    empty.c  = ' ';
+    empty.fg = text_fg;
+    empty.bg = text_bg;
+    for (size_t i = term_context.scroll_top_margin * cols;
+         i < (term_context.scroll_top_margin + 1) * cols; i++) {
+        push_to_queue(&empty, i % cols, i / cols);
+    }
+}
+
 void gterm_scroll(void) {
     for (size_t i = (term_context.scroll_top_margin + 1) * cols;
          i < term_context.scroll_bottom_margin * cols; i++) {
@@ -578,6 +623,7 @@ bool gterm_init(size_t *_rows, size_t *_cols, size_t width, size_t height) {
         return false;
 
     cursor_status = true;
+    scroll_enabled = true;
 
     // default scheme
     margin = 64;
diff --git a/stage23/lib/gterm.h b/stage23/lib/gterm.h
index 65a39282..d37aaa13 100644
--- a/stage23/lib/gterm.h
+++ b/stage23/lib/gterm.h
@@ -27,7 +27,10 @@ bool gterm_scroll_disable(void);
 void gterm_scroll_enable(void);
 void gterm_move_character(size_t new_x, size_t new_y, size_t old_x, size_t old_y);
 void gterm_scroll(void);
+void gterm_revscroll(void);
 void gterm_swap_palette(void);
+void gterm_save_state(void);
+void gterm_restore_state(void);
 
 void gterm_double_buffer_flush(void);
 
diff --git a/stage23/lib/term.c b/stage23/lib/term.c
index 21fa0dea..91e612ee 100644
--- a/stage23/lib/term.c
+++ b/stage23/lib/term.c
@@ -51,7 +51,10 @@ void term_vbe(size_t width, size_t height) {
     scroll_enable  = gterm_scroll_enable;
     term_move_character = gterm_move_character;
     term_scroll = gterm_scroll;
+    term_revscroll = gterm_revscroll;
     term_swap_palette = gterm_swap_palette;
+    term_save_state = gterm_save_state;
+    term_restore_state = gterm_restore_state;
 
     term_double_buffer_flush = gterm_double_buffer_flush;
 
diff --git a/stage23/lib/term.h b/stage23/lib/term.h
index 13a9a2d3..c113f669 100644
--- a/stage23/lib/term.h
+++ b/stage23/lib/term.h
@@ -30,6 +30,11 @@ extern struct term_context {
     size_t scroll_top_margin;
     size_t scroll_bottom_margin;
     uint32_t esc_values[MAX_ESC_VALUES];
+
+    bool saved_state_bold;
+    bool saved_state_reverse_video;
+    size_t saved_state_current_charset;
+    size_t saved_state_current_primary;
 } term_context;
 
 enum {
@@ -71,7 +76,10 @@ extern bool (*scroll_disable)(void);
 extern void (*scroll_enable)(void);
 extern void (*term_move_character)(size_t new_x, size_t new_y, size_t old_x, size_t old_y);
 extern void (*term_scroll)(void);
+extern void (*term_revscroll)(void);
 extern void (*term_swap_palette)(void);
+extern void (*term_save_state)(void);
+extern void (*term_restore_state)(void);
 
 extern void (*term_double_buffer_flush)(void);
 
diff --git a/stage23/lib/term.s2.c b/stage23/lib/term.s2.c
index c0543796..4622877c 100644
--- a/stage23/lib/term.s2.c
+++ b/stage23/lib/term.s2.c
@@ -66,7 +66,10 @@ void term_notready(void) {
     scroll_enable = notready_void;
     term_move_character = notready_move_character;
     term_scroll = notready_void;
+    term_revscroll = notready_void;
     term_swap_palette = notready_void;
+    term_save_state = notready_void;
+    term_restore_state = notready_void;
     term_double_buffer_flush = notready_void;
     term_context_size = notready_context_size;
     term_context_save = notready_uint64_t;
@@ -207,7 +210,10 @@ bool (*scroll_disable)(void);
 void (*scroll_enable)(void);
 void (*term_move_character)(size_t new_x, size_t new_y, size_t old_x, size_t old_y);
 void (*term_scroll)(void);
+void (*term_revscroll)(void);
 void (*term_swap_palette)(void);
+void (*term_save_state)(void);
+void (*term_restore_state)(void);
 
 void (*term_double_buffer_flush)(void);
 
@@ -241,6 +247,11 @@ struct term_context term_context;
 #define charsets term_context.charsets
 #define g_select term_context.g_select
 
+#define saved_state_bold term_context.saved_state_bold
+#define saved_state_reverse_video term_context.saved_state_reverse_video
+#define saved_state_current_charset term_context.saved_state_current_charset
+#define saved_state_current_primary term_context.saved_state_current_primary
+
 #define CHARSET_DEFAULT 0
 #define CHARSET_DEC_SPECIAL 1
 
@@ -296,7 +307,10 @@ void term_textmode(void) {
     scroll_enable  = text_scroll_enable;
     term_move_character = text_move_character;
     term_scroll = text_scroll;
+    term_revscroll = text_revscroll;
     term_swap_palette = text_swap_palette;
+    term_save_state = text_save_state;
+    term_restore_state = text_restore_state;
 
     term_double_buffer_flush = text_double_buffer_flush;
 
@@ -897,6 +911,24 @@ cleanup:
     escape = false;
 }
 
+static void restore_state(void) {
+    bold = saved_state_bold;
+    reverse_video = saved_state_reverse_video;
+    current_charset = saved_state_current_charset;
+    current_primary = saved_state_current_primary;
+
+    term_restore_state();
+}
+
+static void save_state(void) {
+    term_save_state();
+
+    saved_state_bold = bold;
+    saved_state_reverse_video = reverse_video;
+    saved_state_current_charset = current_charset;
+    saved_state_current_primary = current_primary;
+}
+
 static void escape_parse(uint8_t c) {
     escape_offset++;
 
@@ -922,6 +954,12 @@ is_csi:
             rrr = false;
             control_sequence = true;
             return;
+        case '7':
+            save_state();
+            break;
+        case '8':
+            restore_state();
+            break;
         case 'c':
             term_reinit();
             clear(true);
@@ -944,7 +982,12 @@ is_csi:
             break;
         case 'M':
             // "Reverse linefeed"
-            set_cursor_pos(x, y - 1);
+            if (y == scroll_top_margin) {
+                term_revscroll();
+                set_cursor_pos(0, y);
+            } else {
+                set_cursor_pos(0, y - 1);
+            }
             break;
         case 'Z':
             if (term_callback != NULL) {
tab: 248 wrap: offon