|
|
@ -8,6 +8,7 @@ |
|
|
|
#include "jstring.h" |
|
|
|
#include "jstring.h" |
|
|
|
#include "character_sets.h" |
|
|
|
#include "character_sets.h" |
|
|
|
#include "utf8.h" |
|
|
|
#include "utf8.h" |
|
|
|
|
|
|
|
#include "uart_buffer.h" |
|
|
|
|
|
|
|
|
|
|
|
TerminalConfigBundle * const termconf = &persist.current.termconf; |
|
|
|
TerminalConfigBundle * const termconf = &persist.current.termconf; |
|
|
|
TerminalConfigBundle termconf_live; |
|
|
|
TerminalConfigBundle termconf_live; |
|
|
@ -20,11 +21,6 @@ static void utf8_remap(char* out, char g, char charset); |
|
|
|
#define W termconf_live.width |
|
|
|
#define W termconf_live.width |
|
|
|
#define H termconf_live.height |
|
|
|
#define H termconf_live.height |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Highest permissible value of the color attribute |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
#define COLOR_MAX 15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Screen cell data type (16 bits) |
|
|
|
* Screen cell data type (16 bits) |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -32,7 +28,7 @@ typedef struct __attribute__((packed)) { |
|
|
|
UnicodeCacheRef symbol : 8; |
|
|
|
UnicodeCacheRef symbol : 8; |
|
|
|
Color fg; |
|
|
|
Color fg; |
|
|
|
Color bg; |
|
|
|
Color bg; |
|
|
|
u8 attrs; |
|
|
|
CellAttrs attrs; |
|
|
|
} Cell; |
|
|
|
} Cell; |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -64,8 +60,8 @@ static struct { |
|
|
|
char last_char[4]; |
|
|
|
char last_char[4]; |
|
|
|
} scr; |
|
|
|
} scr; |
|
|
|
|
|
|
|
|
|
|
|
#define R0 scr.vm0 |
|
|
|
#define TOP scr.vm0 |
|
|
|
#define R1 scr.vm1 |
|
|
|
#define BTM scr.vm1 |
|
|
|
#define RH (scr.vm1 - scr.vm0 + 1) |
|
|
|
#define RH (scr.vm1 - scr.vm0 + 1) |
|
|
|
// horizontal edges - will be useful if horizontal margin is implemented
|
|
|
|
// horizontal edges - will be useful if horizontal margin is implemented
|
|
|
|
//#define C0 0
|
|
|
|
//#define C0 0
|
|
|
@ -78,9 +74,9 @@ typedef struct { |
|
|
|
bool hanging; //!< xenl state - cursor half-wrapped
|
|
|
|
bool hanging; //!< xenl state - cursor half-wrapped
|
|
|
|
|
|
|
|
|
|
|
|
/* SGR */ |
|
|
|
/* SGR */ |
|
|
|
bool inverse; //!< not in attrs bc it's applied server-side (not sent to browser)
|
|
|
|
bool inverse; //!< not in attrs bc it's applied immediately when writing the cell
|
|
|
|
bool conceal; //!< similar to inverse, causes all to be replaced by SP
|
|
|
|
bool conceal; //!< similar to inverse, causes all to be replaced by SP
|
|
|
|
u8 attrs; |
|
|
|
u16 attrs; |
|
|
|
Color fg; //!< Foreground color for writing
|
|
|
|
Color fg; //!< Foreground color for writing
|
|
|
|
Color bg; //!< Background color for writing
|
|
|
|
Color bg; //!< Background color for writing
|
|
|
|
|
|
|
|
|
|
|
@ -158,7 +154,7 @@ static volatile int notifyLock = 0; |
|
|
|
if (cursor.hanging && cursor.x != W-1) cursor.hanging = false; \
|
|
|
|
if (cursor.hanging && cursor.x != W-1) cursor.hanging = false; \
|
|
|
|
} while(false) |
|
|
|
} while(false) |
|
|
|
|
|
|
|
|
|
|
|
#define cursor_inside_region() (cursor.y >= R0 && cursor.y <= R1) |
|
|
|
#define cursor_inside_region() (cursor.y >= TOP && cursor.y <= BTM) |
|
|
|
|
|
|
|
|
|
|
|
//region --- Settings ---
|
|
|
|
//region --- Settings ---
|
|
|
|
|
|
|
|
|
|
|
@ -207,45 +203,12 @@ terminal_apply_settings_noclear(void) |
|
|
|
{ |
|
|
|
{ |
|
|
|
bool changed = false; |
|
|
|
bool changed = false; |
|
|
|
|
|
|
|
|
|
|
|
// Migrate to v1
|
|
|
|
// // Migrate to v1
|
|
|
|
if (termconf->config_version < 1) { |
|
|
|
// if (termconf->config_version < 1) {
|
|
|
|
persist_dbg("termconf: Updating to version 1"); |
|
|
|
// persist_dbg("termconf: Updating to version %d", 1);
|
|
|
|
termconf->display_cooldown_ms = SCR_DEF_DISPLAY_COOLDOWN_MS; |
|
|
|
// termconf->display_cooldown_ms = SCR_DEF_DISPLAY_COOLDOWN_MS;
|
|
|
|
changed = 1; |
|
|
|
// changed = 1;
|
|
|
|
} |
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// Migrate to v2
|
|
|
|
|
|
|
|
if (termconf->config_version < 2) { |
|
|
|
|
|
|
|
persist_dbg("termconf: Updating to version 2"); |
|
|
|
|
|
|
|
termconf->loopback = 0; |
|
|
|
|
|
|
|
termconf->show_config_links = 1; |
|
|
|
|
|
|
|
termconf->show_buttons = 1; |
|
|
|
|
|
|
|
changed = 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Migrate to v3
|
|
|
|
|
|
|
|
if (termconf->config_version < 3) { |
|
|
|
|
|
|
|
persist_dbg("termconf: Updating to version 3"); |
|
|
|
|
|
|
|
for(int i=1; i <= TERM_BTN_COUNT; i++) { |
|
|
|
|
|
|
|
sprintf(termconf->btn_msg[i-1], "%c", i); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
changed = 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Migrate to v4
|
|
|
|
|
|
|
|
if (termconf->config_version < 4) { |
|
|
|
|
|
|
|
persist_dbg("termconf: Updating to version 4"); |
|
|
|
|
|
|
|
termconf->cursor_shape = CURSOR_BLOCK_BL; |
|
|
|
|
|
|
|
termconf->crlf_mode = false; |
|
|
|
|
|
|
|
changed = 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Migrate to v5
|
|
|
|
|
|
|
|
if (termconf->config_version < 4) { |
|
|
|
|
|
|
|
persist_dbg("termconf: Updating to version 5"); |
|
|
|
|
|
|
|
termconf->want_all_fn = 0; |
|
|
|
|
|
|
|
changed = 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
termconf->config_version = TERMCONF_VERSION; |
|
|
|
termconf->config_version = TERMCONF_VERSION; |
|
|
|
|
|
|
|
|
|
|
@ -285,18 +248,7 @@ screen_init(void) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if(DEBUG_HEAP) dbg("Screen buffer size = %d bytes", sizeof(screen)); |
|
|
|
if(DEBUG_HEAP) dbg("Screen buffer size = %d bytes", sizeof(screen)); |
|
|
|
|
|
|
|
|
|
|
|
NOTIFY_LOCK(); |
|
|
|
|
|
|
|
Cell sample; |
|
|
|
|
|
|
|
sample.symbol = ' '; |
|
|
|
|
|
|
|
sample.fg = termconf->default_fg; |
|
|
|
|
|
|
|
sample.bg = termconf->default_bg; |
|
|
|
|
|
|
|
sample.attrs = 0; |
|
|
|
|
|
|
|
for (unsigned int i = 0; i < MAX_SCREEN_SIZE; i++) { |
|
|
|
|
|
|
|
memcpy(&screen[i], &sample, sizeof(Cell)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
screen_reset(); |
|
|
|
screen_reset(); |
|
|
|
NOTIFY_DONE(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -325,16 +277,13 @@ screen_reset_on_resize(void) |
|
|
|
ansi_dbg("Screen partial reset due to resize"); |
|
|
|
ansi_dbg("Screen partial reset due to resize"); |
|
|
|
NOTIFY_LOCK(); |
|
|
|
NOTIFY_LOCK(); |
|
|
|
|
|
|
|
|
|
|
|
cursor.x = 0; |
|
|
|
cursor_reset(); |
|
|
|
cursor.y = 0; |
|
|
|
|
|
|
|
cursor.hanging = false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scr.vm0 = 0; |
|
|
|
scr.vm0 = 0; |
|
|
|
scr.vm1 = H-1; |
|
|
|
scr.vm1 = H-1; |
|
|
|
|
|
|
|
|
|
|
|
// size is left unchanged
|
|
|
|
// size is left unchanged
|
|
|
|
screen_clear(CLEAR_ALL); |
|
|
|
screen_clear(CLEAR_ALL); // also clears utf cache
|
|
|
|
unicode_cache_clear(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NOTIFY_DONE(); |
|
|
|
NOTIFY_DONE(); |
|
|
|
} |
|
|
|
} |
|
|
@ -345,25 +294,17 @@ screen_reset_on_resize(void) |
|
|
|
void ICACHE_FLASH_ATTR |
|
|
|
void ICACHE_FLASH_ATTR |
|
|
|
screen_reset_sgr(void) |
|
|
|
screen_reset_sgr(void) |
|
|
|
{ |
|
|
|
{ |
|
|
|
cursor.fg = termconf->default_fg; |
|
|
|
cursor.fg = 0; |
|
|
|
cursor.bg = termconf->default_bg; |
|
|
|
cursor.bg = 0; |
|
|
|
cursor.attrs = 0; |
|
|
|
cursor.attrs = 0; |
|
|
|
cursor.inverse = false; |
|
|
|
|
|
|
|
cursor.conceal = false; |
|
|
|
cursor.conceal = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
static void ICACHE_FLASH_ATTR |
|
|
|
* Reset the screen - called by ESC c |
|
|
|
screen_reset_do(bool size, bool labels) |
|
|
|
*/ |
|
|
|
|
|
|
|
void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
screen_reset(void) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
ansi_dbg("Screen reset."); |
|
|
|
|
|
|
|
NOTIFY_LOCK(); |
|
|
|
NOTIFY_LOCK(); |
|
|
|
|
|
|
|
|
|
|
|
cursor_reset(); |
|
|
|
|
|
|
|
unicode_cache_clear(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// DECopts
|
|
|
|
// DECopts
|
|
|
|
scr.cursor_visible = true; |
|
|
|
scr.cursor_visible = true; |
|
|
|
scr.insert_mode = false; |
|
|
|
scr.insert_mode = false; |
|
|
@ -377,17 +318,21 @@ screen_reset(void) |
|
|
|
termconf_live.crlf_mode = termconf->crlf_mode; |
|
|
|
termconf_live.crlf_mode = termconf->crlf_mode; |
|
|
|
scr.reverse_video = false; |
|
|
|
scr.reverse_video = false; |
|
|
|
|
|
|
|
|
|
|
|
scr.vm0 = 0; |
|
|
|
|
|
|
|
scr.vm1 = H-1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
state_backup.alternate_active = false; |
|
|
|
state_backup.alternate_active = false; |
|
|
|
|
|
|
|
|
|
|
|
mouse_tracking.encoding = MTE_SIMPLE; |
|
|
|
mouse_tracking.encoding = MTE_SIMPLE; |
|
|
|
mouse_tracking.focus_tracking = false; |
|
|
|
mouse_tracking.focus_tracking = false; |
|
|
|
mouse_tracking.mode = MTM_NONE; |
|
|
|
mouse_tracking.mode = MTM_NONE; |
|
|
|
|
|
|
|
|
|
|
|
// size is left unchanged
|
|
|
|
if (size) { |
|
|
|
screen_clear(CLEAR_ALL); |
|
|
|
W = termconf->width; |
|
|
|
|
|
|
|
H = termconf->height; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scr.vm0 = 0; |
|
|
|
|
|
|
|
scr.vm1 = H - 1; |
|
|
|
|
|
|
|
cursor_reset(); |
|
|
|
|
|
|
|
screen_clear(CLEAR_ALL); // also clears utf cache
|
|
|
|
|
|
|
|
|
|
|
|
// Set initial tabstops
|
|
|
|
// Set initial tabstops
|
|
|
|
for (int i = 0; i < TABSTOP_WORDS; i++) { |
|
|
|
for (int i = 0; i < TABSTOP_WORDS; i++) { |
|
|
@ -410,8 +355,30 @@ screen_reset(void) |
|
|
|
opt_backup.show_config_links = termconf_live.show_config_links; |
|
|
|
opt_backup.show_config_links = termconf_live.show_config_links; |
|
|
|
|
|
|
|
|
|
|
|
NOTIFY_DONE(); |
|
|
|
NOTIFY_DONE(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (labels) { |
|
|
|
|
|
|
|
strcpy(termconf_live.title, termconf->title); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 1; i <= TERM_BTN_COUNT; i++) { |
|
|
|
|
|
|
|
strcpy(termconf_live.btn[i], termconf->btn[i]); |
|
|
|
|
|
|
|
strcpy(termconf_live.btn_msg[i], termconf->btn_msg[i]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
screen_notifyChange(CHANGE_LABELS); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Reset the screen - called by ESC c |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
screen_reset(void) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ansi_dbg("Screen reset."); |
|
|
|
|
|
|
|
screen_reset_do(true, true); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Swap screen buffer / state |
|
|
|
* Swap screen buffer / state |
|
|
|
* this is CSI ? 47/1047/1049 h/l |
|
|
|
* this is CSI ? 47/1047/1049 h/l |
|
|
@ -583,27 +550,163 @@ screen_tab_reverse(int count) |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Clear range, inclusive |
|
|
|
* Clear range, inclusive |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param from - starting absolute position |
|
|
|
|
|
|
|
* @param to - ending absolute position |
|
|
|
|
|
|
|
* @param clear_utf - release any encountered utf8 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static void ICACHE_FLASH_ATTR |
|
|
|
static void ICACHE_FLASH_ATTR |
|
|
|
clear_range(unsigned int from, unsigned int to) |
|
|
|
clear_range_do(unsigned int from, unsigned int to, bool clear_utf) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (to >= W*H) to = W*H-1; |
|
|
|
if (to >= W*H) to = W*H-1; |
|
|
|
Color fg = (cursor.inverse) ? cursor.bg : cursor.fg; |
|
|
|
|
|
|
|
Color bg = (cursor.inverse) ? cursor.fg : cursor.bg; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Cell sample; |
|
|
|
Cell sample; |
|
|
|
sample.symbol = ' '; |
|
|
|
sample.symbol = ' '; |
|
|
|
sample.fg = fg; |
|
|
|
sample.fg = cursor.fg; |
|
|
|
sample.bg = bg; |
|
|
|
sample.bg = cursor.bg; |
|
|
|
sample.attrs = 0; |
|
|
|
// we discard all attributes except color-set flags
|
|
|
|
|
|
|
|
sample.attrs = (CellAttrs) (cursor.attrs & (ATTR_FG | ATTR_BG)); |
|
|
|
|
|
|
|
|
|
|
|
for (unsigned int i = from; i <= to; i++) { |
|
|
|
for (unsigned int i = from; i <= to; i++) { |
|
|
|
|
|
|
|
if (clear_utf) { |
|
|
|
UnicodeCacheRef symbol = screen[i].symbol; |
|
|
|
UnicodeCacheRef symbol = screen[i].symbol; |
|
|
|
if (IS_UNICODE_CACHE_REF(symbol)) unicode_cache_remove(symbol); |
|
|
|
if (IS_UNICODE_CACHE_REF(symbol)) unicode_cache_remove(symbol); |
|
|
|
|
|
|
|
} |
|
|
|
memcpy(&screen[i], &sample, sizeof(Cell)); |
|
|
|
memcpy(&screen[i], &sample, sizeof(Cell)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Clear range, inclusive, freeing any encountered UTF8 from the cache |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param from - starting absolute position |
|
|
|
|
|
|
|
* @param to - ending absolute position |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
static inline void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
clear_range_utf(unsigned int from, unsigned int to) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
clear_range_do(from, to, true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Clear range, inclusive. Do not release utf characters |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param from - starting absolute position |
|
|
|
|
|
|
|
* @param to - ending absolute position |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
static inline void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
clear_range_noutf(unsigned int from, unsigned int to) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
clear_range_do(from, to, false); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Free a utf8 reference character in a cell |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param row |
|
|
|
|
|
|
|
* @param col |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
static inline void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
utf_free_cell(int row, int col) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
//dbg("free cell (row %d) %d", row, col);
|
|
|
|
|
|
|
|
UnicodeCacheRef symbol = screen[row * W + col].symbol; |
|
|
|
|
|
|
|
if (IS_UNICODE_CACHE_REF(symbol)) |
|
|
|
|
|
|
|
unicode_cache_remove(symbol); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Back-up utf8 reference in a cell (i.e. increment the counter, |
|
|
|
|
|
|
|
* so 1 subsequent free has no effect) |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param row |
|
|
|
|
|
|
|
* @param col |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
static inline void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
utf_backup_cell(int row, int col) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
//dbg("backup cell (row %d) %d", row, col);
|
|
|
|
|
|
|
|
UnicodeCacheRef symbol = screen[row * W + col].symbol; |
|
|
|
|
|
|
|
if (IS_UNICODE_CACHE_REF(symbol)) |
|
|
|
|
|
|
|
unicode_cache_inc(symbol); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Duplicate a cell within a row |
|
|
|
|
|
|
|
* @param row - row to work on |
|
|
|
|
|
|
|
* @param dest_col - destination column |
|
|
|
|
|
|
|
* @param src_col - source column |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
static inline void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
copy_cell(int row, int dest_col, int src_col) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
//dbg("copy cell (row %d) %d -> %d", row, src_col, dest_col);
|
|
|
|
|
|
|
|
memcpy(screen+row*W+dest_col, screen+row*W+src_col, sizeof(Cell)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Free all utf8 on a row |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param row |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
static inline void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
utf_free_row(int row) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
//dbg("free row %d", row);
|
|
|
|
|
|
|
|
for (int col = 0; col < W; col++) { |
|
|
|
|
|
|
|
utf_free_cell(row, col); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Back-up all utf8 refs on a row |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param row |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
static inline void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
utf_backup_row(int row) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
//dbg("backup row %d", row);
|
|
|
|
|
|
|
|
for (int col = 0; col < W; col++) { |
|
|
|
|
|
|
|
utf_backup_cell(row, col); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Duplicate a row |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param dest - destination row number (0-based) |
|
|
|
|
|
|
|
* @param src - source row number (0-based) |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
static inline void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
copy_row(int dest, int src) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
//dbg("copy row %d -> %d", src, dest);
|
|
|
|
|
|
|
|
memcpy(screen + dest * W, screen + src * W, sizeof(Cell) * W); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Clear a row, do nothing with the utf8 cache |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param row |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
static inline void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
clear_row_noutf(int row) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
clear_range_noutf(row * W, (row + 1) * W - 1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Clear a row, freeing any utf8 refs |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param row |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
static inline void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
clear_row_utf(int row) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
clear_range_utf(row * W, (row + 1) * W - 1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Clear screen area |
|
|
|
* Clear screen area |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -614,15 +717,17 @@ screen_clear(ClearMode mode) |
|
|
|
NOTIFY_LOCK(); |
|
|
|
NOTIFY_LOCK(); |
|
|
|
switch (mode) { |
|
|
|
switch (mode) { |
|
|
|
case CLEAR_ALL: |
|
|
|
case CLEAR_ALL: |
|
|
|
clear_range(0, W * H - 1); |
|
|
|
unicode_cache_clear(); |
|
|
|
|
|
|
|
clear_range_noutf(0, W * H - 1); |
|
|
|
|
|
|
|
scr.last_char[0] = 0; |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case CLEAR_FROM_CURSOR: |
|
|
|
case CLEAR_FROM_CURSOR: |
|
|
|
clear_range((cursor.y * W) + cursor.x, W * H - 1); |
|
|
|
clear_range_utf((cursor.y * W) + cursor.x, W * H - 1); |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case CLEAR_TO_CURSOR: |
|
|
|
case CLEAR_TO_CURSOR: |
|
|
|
clear_range(0, (cursor.y * W) + cursor.x); |
|
|
|
clear_range_utf(0, (cursor.y * W) + cursor.x); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
NOTIFY_DONE(); |
|
|
|
NOTIFY_DONE(); |
|
|
@ -637,15 +742,15 @@ screen_clear_line(ClearMode mode) |
|
|
|
NOTIFY_LOCK(); |
|
|
|
NOTIFY_LOCK(); |
|
|
|
switch (mode) { |
|
|
|
switch (mode) { |
|
|
|
case CLEAR_ALL: |
|
|
|
case CLEAR_ALL: |
|
|
|
clear_range(cursor.y * W, (cursor.y + 1) * W - 1); |
|
|
|
clear_row_utf(cursor.y); |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case CLEAR_FROM_CURSOR: |
|
|
|
case CLEAR_FROM_CURSOR: |
|
|
|
clear_range(cursor.y * W + cursor.x, (cursor.y + 1) * W - 1); |
|
|
|
clear_range_utf(cursor.y * W + cursor.x, (cursor.y + 1) * W - 1); |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case CLEAR_TO_CURSOR: |
|
|
|
case CLEAR_TO_CURSOR: |
|
|
|
clear_range(cursor.y * W, cursor.y * W + cursor.x); |
|
|
|
clear_range_utf(cursor.y * W, cursor.y * W + cursor.x); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
NOTIFY_DONE(); |
|
|
|
NOTIFY_DONE(); |
|
|
@ -654,14 +759,13 @@ screen_clear_line(ClearMode mode) |
|
|
|
void ICACHE_FLASH_ATTR |
|
|
|
void ICACHE_FLASH_ATTR |
|
|
|
screen_clear_in_line(unsigned int count) |
|
|
|
screen_clear_in_line(unsigned int count) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
NOTIFY_LOCK(); |
|
|
|
if (cursor.x + count >= W) { |
|
|
|
if (cursor.x + count >= W) { |
|
|
|
screen_clear_line(CLEAR_FROM_CURSOR); |
|
|
|
screen_clear_line(CLEAR_FROM_CURSOR); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
clear_range_utf(cursor.y * W + cursor.x, cursor.y * W + cursor.x + count - 1); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
|
|
|
|
NOTIFY_LOCK(); |
|
|
|
|
|
|
|
clear_range(cursor.y * W + cursor.x, cursor.y * W + cursor.x + count - 1); |
|
|
|
|
|
|
|
NOTIFY_DONE(); |
|
|
|
NOTIFY_DONE(); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void ICACHE_FLASH_ATTR |
|
|
|
void ICACHE_FLASH_ATTR |
|
|
@ -670,24 +774,24 @@ screen_insert_lines(unsigned int lines) |
|
|
|
if (!cursor_inside_region()) return; // can't insert if not inside region
|
|
|
|
if (!cursor_inside_region()) return; // can't insert if not inside region
|
|
|
|
NOTIFY_LOCK(); |
|
|
|
NOTIFY_LOCK(); |
|
|
|
|
|
|
|
|
|
|
|
// FIXME remove cleared & overwritten cells from unicode cache!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// shift the following lines
|
|
|
|
// shift the following lines
|
|
|
|
int targetStart = cursor.y + lines; |
|
|
|
int targetStart = cursor.y + lines; |
|
|
|
if (targetStart > R1) { |
|
|
|
if (targetStart > BTM) { |
|
|
|
targetStart = R1-1; |
|
|
|
clear_range_utf(cursor.y*W, (BTM+1)*W-1); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// do the moving
|
|
|
|
// do the moving
|
|
|
|
for (int i = R1; i >= targetStart; i--) { |
|
|
|
for (int i = BTM; i >= targetStart; i--) { |
|
|
|
memcpy(screen+i*W, screen+(i-lines)*W, sizeof(Cell)*W); |
|
|
|
utf_free_row(i); // release old characters
|
|
|
|
} |
|
|
|
copy_row(i, i - lines); |
|
|
|
|
|
|
|
if (i != targetStart) utf_backup_row(i); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// clear the first line
|
|
|
|
// clear the first line
|
|
|
|
screen_clear_line(CLEAR_ALL); |
|
|
|
clear_row_noutf(cursor.y); |
|
|
|
// copy it to the rest of the cleared region
|
|
|
|
// copy it to the rest of the cleared region
|
|
|
|
for (int i = cursor.y+1; i < targetStart; i++) { |
|
|
|
for (int i = cursor.y+1; i < targetStart; i++) { |
|
|
|
memcpy(screen+i*W, screen+cursor.y*W, sizeof(Cell)*W); |
|
|
|
copy_row(i, cursor.y); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
NOTIFY_DONE(); |
|
|
|
NOTIFY_DONE(); |
|
|
|
} |
|
|
|
} |
|
|
@ -698,21 +802,22 @@ screen_delete_lines(unsigned int lines) |
|
|
|
if (!cursor_inside_region()) return; // can't delete if not inside region
|
|
|
|
if (!cursor_inside_region()) return; // can't delete if not inside region
|
|
|
|
NOTIFY_LOCK(); |
|
|
|
NOTIFY_LOCK(); |
|
|
|
|
|
|
|
|
|
|
|
// FIXME remove cleared & overwritten cells from unicode cache!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// shift lines up
|
|
|
|
// shift lines up
|
|
|
|
int targetEnd = R1 - lines - 1; |
|
|
|
int movedBlockEnd = BTM - lines ; |
|
|
|
if (targetEnd <= cursor.y) { |
|
|
|
if (movedBlockEnd <= cursor.y) { |
|
|
|
targetEnd = cursor.y; |
|
|
|
// clear the entire rest of the screen
|
|
|
|
|
|
|
|
movedBlockEnd = cursor.y; |
|
|
|
|
|
|
|
clear_range_utf(movedBlockEnd*W, (BTM+1)*W-1); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// do the moving
|
|
|
|
// move some lines up, clear the rest
|
|
|
|
for (int i = cursor.y; i <= targetEnd; i++) { |
|
|
|
for (int i = cursor.y; i <= movedBlockEnd; i++) { |
|
|
|
memcpy(screen+i*W, screen+(i+lines)*W, sizeof(Cell)*W); |
|
|
|
utf_free_row(i); |
|
|
|
|
|
|
|
copy_row(i, i+lines); |
|
|
|
|
|
|
|
if (i != movedBlockEnd) utf_backup_row(i); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
clear_range_noutf((movedBlockEnd+1)*W, (BTM+1)*W-1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// clear the rest
|
|
|
|
|
|
|
|
clear_range(targetEnd*W, W*R1); |
|
|
|
|
|
|
|
NOTIFY_DONE(); |
|
|
|
NOTIFY_DONE(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -721,19 +826,21 @@ screen_insert_characters(unsigned int count) |
|
|
|
{ |
|
|
|
{ |
|
|
|
NOTIFY_LOCK(); |
|
|
|
NOTIFY_LOCK(); |
|
|
|
|
|
|
|
|
|
|
|
// FIXME remove cleared & overwritten cells from unicode cache!
|
|
|
|
// shove rest of the line to the right
|
|
|
|
|
|
|
|
|
|
|
|
int targetStart = cursor.x + count; |
|
|
|
int targetStart = cursor.x + count; |
|
|
|
if (targetStart >= W) { |
|
|
|
if (targetStart >= W) { |
|
|
|
targetStart = W-1; |
|
|
|
// all rest of line was cleared
|
|
|
|
|
|
|
|
clear_range_utf(cursor.y * W + cursor.x, (cursor.y + 1) * W - 1); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// do the moving
|
|
|
|
// do the moving
|
|
|
|
for (int i = W-1; i >= targetStart; i--) { |
|
|
|
for (int i = W-1; i >= targetStart; i--) { |
|
|
|
memcpy(screen+cursor.y*W+i, screen+cursor.y*W+(i-count), sizeof(Cell)); |
|
|
|
utf_free_cell(cursor.y, i); |
|
|
|
|
|
|
|
copy_cell(cursor.y, i, i - count); |
|
|
|
|
|
|
|
utf_backup_cell(cursor.y, i); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
clear_range_utf(cursor.y * W + cursor.x, cursor.y * W + targetStart - 1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
clear_range(cursor.y*W+cursor.x, cursor.y*W+targetStart-1); |
|
|
|
|
|
|
|
NOTIFY_DONE(); |
|
|
|
NOTIFY_DONE(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -742,21 +849,24 @@ screen_delete_characters(unsigned int count) |
|
|
|
{ |
|
|
|
{ |
|
|
|
NOTIFY_LOCK(); |
|
|
|
NOTIFY_LOCK(); |
|
|
|
|
|
|
|
|
|
|
|
// FIXME remove cleared & overwritten cells from unicode cache!
|
|
|
|
// pull rest of the line to the left
|
|
|
|
int targetEnd = W - count; |
|
|
|
|
|
|
|
if (targetEnd > cursor.x) { |
|
|
|
|
|
|
|
// do the moving
|
|
|
|
|
|
|
|
for (int i = cursor.x; i <= targetEnd; i++) { |
|
|
|
|
|
|
|
memcpy(screen+cursor.y*W+i, screen+cursor.y*W+(i+count), sizeof(Cell)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (targetEnd <= cursor.x) { |
|
|
|
int movedBlockEnd = W - count; |
|
|
|
screen_clear_line(CLEAR_FROM_CURSOR); |
|
|
|
if (movedBlockEnd > cursor.x) { |
|
|
|
|
|
|
|
// partial line delete / move
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = cursor.x; i <= movedBlockEnd; i++) { |
|
|
|
|
|
|
|
utf_free_cell(cursor.y, i); |
|
|
|
|
|
|
|
copy_cell(cursor.y, i, i + count); |
|
|
|
|
|
|
|
utf_backup_cell(cursor.y, i); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
// clear original positions of the moved characters
|
|
|
|
clear_range(cursor.y * W + (W - count), (cursor.y + 1) * W - 1); |
|
|
|
clear_range_noutf(cursor.y * W + (W - count), (cursor.y + 1) * W - 1); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// all rest was cleared
|
|
|
|
|
|
|
|
screen_clear_line(CLEAR_FROM_CURSOR); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
NOTIFY_DONE(); |
|
|
|
NOTIFY_DONE(); |
|
|
|
} |
|
|
|
} |
|
|
|
//endregion
|
|
|
|
//endregion
|
|
|
@ -767,12 +877,12 @@ void ICACHE_FLASH_ATTR |
|
|
|
screen_fill_with_E(void) |
|
|
|
screen_fill_with_E(void) |
|
|
|
{ |
|
|
|
{ |
|
|
|
NOTIFY_LOCK(); |
|
|
|
NOTIFY_LOCK(); |
|
|
|
screen_reset(); // based on observation from xterm
|
|
|
|
screen_reset_do(false, false); // based on observation from xterm
|
|
|
|
|
|
|
|
|
|
|
|
Cell sample; |
|
|
|
Cell sample; |
|
|
|
sample.symbol = 'E'; |
|
|
|
sample.symbol = 'E'; |
|
|
|
sample.fg = termconf->default_fg; |
|
|
|
sample.fg = 0; |
|
|
|
sample.bg = termconf->default_bg; |
|
|
|
sample.bg = 0; |
|
|
|
sample.attrs = 0; |
|
|
|
sample.attrs = 0; |
|
|
|
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i <= W*H-1; i++) { |
|
|
|
for (unsigned int i = 0; i <= W*H-1; i++) { |
|
|
@ -837,7 +947,8 @@ screen_scroll_up(unsigned int lines) |
|
|
|
{ |
|
|
|
{ |
|
|
|
NOTIFY_LOCK(); |
|
|
|
NOTIFY_LOCK(); |
|
|
|
if (lines >= RH) { |
|
|
|
if (lines >= RH) { |
|
|
|
clear_range(R0*W, (R1+1)*W-1); |
|
|
|
// clear entire region
|
|
|
|
|
|
|
|
clear_range_utf(TOP * W, (BTM + 1) * W - 1); |
|
|
|
goto done; |
|
|
|
goto done; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -846,16 +957,16 @@ screen_scroll_up(unsigned int lines) |
|
|
|
goto done; |
|
|
|
goto done; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// FIXME remove cleared & overwritten cells from unicode cache!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int y; |
|
|
|
int y; |
|
|
|
for (y = R0; y <= R1 - lines; y++) { |
|
|
|
for (y = TOP; y <= BTM - lines; y++) { |
|
|
|
memcpy(screen + y * W, screen + (y + lines) * W, W * sizeof(Cell)); |
|
|
|
utf_free_row(y); |
|
|
|
|
|
|
|
copy_row(y, y+lines); |
|
|
|
|
|
|
|
if (y < BTM - lines) utf_backup_row(y); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
clear_range(y * W, (R1+1)*W-1); |
|
|
|
clear_range_noutf(y * W, (BTM + 1) * W - 1); |
|
|
|
|
|
|
|
|
|
|
|
done: |
|
|
|
done: |
|
|
|
NOTIFY_DONE(); |
|
|
|
NOTIFY_DONE(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -867,24 +978,25 @@ screen_scroll_down(unsigned int lines) |
|
|
|
{ |
|
|
|
{ |
|
|
|
NOTIFY_LOCK(); |
|
|
|
NOTIFY_LOCK(); |
|
|
|
if (lines >= RH) { |
|
|
|
if (lines >= RH) { |
|
|
|
clear_range(R0*W, (R1+1)*W-1); |
|
|
|
// clear entire region
|
|
|
|
|
|
|
|
clear_range_utf(TOP * W, (BTM + 1) * W - 1); |
|
|
|
goto done; |
|
|
|
goto done; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// FIXME remove cleared & overwritten cells from unicode cache!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// bad cmd
|
|
|
|
// bad cmd
|
|
|
|
if (lines == 0) { |
|
|
|
if (lines == 0) { |
|
|
|
goto done; |
|
|
|
goto done; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int y; |
|
|
|
int y; |
|
|
|
for (y = R1; y >= R0+lines; y--) { |
|
|
|
for (y = BTM; y >= TOP+lines; y--) { |
|
|
|
memcpy(screen + y * W, screen + (y - lines) * W, W * sizeof(Cell)); |
|
|
|
utf_free_row(y); |
|
|
|
|
|
|
|
copy_row(y, y-lines); |
|
|
|
|
|
|
|
if (y > TOP + lines) utf_backup_row(y); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
clear_range(R0*W, R0*W+ lines * W-1); |
|
|
|
clear_range_noutf(TOP * W, TOP * W + lines * W - 1); |
|
|
|
done: |
|
|
|
done: |
|
|
|
NOTIFY_DONE(); |
|
|
|
NOTIFY_DONE(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -960,7 +1072,7 @@ screen_cursor_get(int *y, int *x) |
|
|
|
*y = cursor.y; |
|
|
|
*y = cursor.y; |
|
|
|
|
|
|
|
|
|
|
|
if (cursor.origin_mode) { |
|
|
|
if (cursor.origin_mode) { |
|
|
|
*y -= R0; |
|
|
|
*y -= TOP; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -989,9 +1101,9 @@ screen_cursor_set_y(int y) |
|
|
|
{ |
|
|
|
{ |
|
|
|
NOTIFY_LOCK(); |
|
|
|
NOTIFY_LOCK(); |
|
|
|
if (cursor.origin_mode) { |
|
|
|
if (cursor.origin_mode) { |
|
|
|
y += R0; |
|
|
|
y += TOP; |
|
|
|
if (y > R1) y = R1; |
|
|
|
if (y > BTM) y = BTM; |
|
|
|
if (y < R0) y = R0; |
|
|
|
if (y < TOP) y = TOP; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
if (y > H-1) y = H-1; |
|
|
|
if (y > H-1) y = H-1; |
|
|
|
if (y < 0) y = 0; |
|
|
|
if (y < 0) y = 0; |
|
|
@ -1012,7 +1124,7 @@ screen_cursor_move(int dy, int dx, bool scroll) |
|
|
|
clear_invalid_hanging(); |
|
|
|
clear_invalid_hanging(); |
|
|
|
|
|
|
|
|
|
|
|
if (cursor.hanging && dx < 0) { |
|
|
|
if (cursor.hanging && dx < 0) { |
|
|
|
dx += 1; // consume one step on the removal of "xenl"
|
|
|
|
//dx += 1; // consume one step on the removal of "xenl"
|
|
|
|
cursor.hanging = false; |
|
|
|
cursor.hanging = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1040,7 +1152,7 @@ screen_cursor_move(int dy, int dx, bool scroll) |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
// end of screen, end of line (wrap around)
|
|
|
|
// end of screen, end of line (wrap around)
|
|
|
|
cursor.y = R1; |
|
|
|
cursor.y = BTM; |
|
|
|
cursor.x = W - 1; |
|
|
|
cursor.x = W - 1; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -1050,10 +1162,10 @@ screen_cursor_move(int dy, int dx, bool scroll) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (cursor.y < R0) { |
|
|
|
if (cursor.y < TOP) { |
|
|
|
if (was_inside) { |
|
|
|
if (was_inside) { |
|
|
|
move = -(cursor.y - R0); |
|
|
|
move = -(cursor.y - TOP); |
|
|
|
cursor.y = R0; |
|
|
|
cursor.y = TOP; |
|
|
|
if (scroll) screen_scroll_down((unsigned int) move); |
|
|
|
if (scroll) screen_scroll_down((unsigned int) move); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
@ -1065,10 +1177,10 @@ screen_cursor_move(int dy, int dx, bool scroll) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (cursor.y > R1) { |
|
|
|
if (cursor.y > BTM) { |
|
|
|
if (was_inside) { |
|
|
|
if (was_inside) { |
|
|
|
move = cursor.y - R1; |
|
|
|
move = cursor.y - BTM; |
|
|
|
cursor.y = R1; |
|
|
|
cursor.y = BTM; |
|
|
|
if (scroll) screen_scroll_up((unsigned int) move); |
|
|
|
if (scroll) screen_scroll_up((unsigned int) move); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
@ -1174,6 +1286,7 @@ void ICACHE_FLASH_ATTR |
|
|
|
screen_set_fg(Color color) |
|
|
|
screen_set_fg(Color color) |
|
|
|
{ |
|
|
|
{ |
|
|
|
cursor.fg = color; |
|
|
|
cursor.fg = color; |
|
|
|
|
|
|
|
cursor.attrs |= ATTR_FG; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -1183,10 +1296,31 @@ void ICACHE_FLASH_ATTR |
|
|
|
screen_set_bg(Color color) |
|
|
|
screen_set_bg(Color color) |
|
|
|
{ |
|
|
|
{ |
|
|
|
cursor.bg = color; |
|
|
|
cursor.bg = color; |
|
|
|
|
|
|
|
cursor.attrs |= ATTR_BG; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Set cursor foreground color to default |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
screen_set_default_fg(void) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
cursor.fg = 0; |
|
|
|
|
|
|
|
cursor.attrs &= ~ATTR_FG; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Set cursor background color to default |
|
|
|
|
|
|
|
*/ |
|
|
|
void ICACHE_FLASH_ATTR |
|
|
|
void ICACHE_FLASH_ATTR |
|
|
|
screen_set_sgr(u8 attrs, bool ena) |
|
|
|
screen_set_default_bg(void) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
cursor.bg = 0; |
|
|
|
|
|
|
|
cursor.attrs &= ~ATTR_BG; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
screen_set_sgr(CellAttrs attrs, bool ena) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (ena) { |
|
|
|
if (ena) { |
|
|
|
cursor.attrs |= attrs; |
|
|
|
cursor.attrs |= attrs; |
|
|
@ -1196,12 +1330,6 @@ screen_set_sgr(u8 attrs, bool ena) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void ICACHE_FLASH_ATTR |
|
|
|
|
|
|
|
screen_set_sgr_inverse(bool ena) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
cursor.inverse = ena; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ICACHE_FLASH_ATTR |
|
|
|
void ICACHE_FLASH_ATTR |
|
|
|
screen_set_sgr_conceal(bool ena) |
|
|
|
screen_set_sgr_conceal(bool ena) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -1359,9 +1487,11 @@ screen_report_sgr(char *buffer) |
|
|
|
if (cursor.attrs & ATTR_BLINK) buffer += sprintf(buffer, ";%d", SGR_BLINK); |
|
|
|
if (cursor.attrs & ATTR_BLINK) buffer += sprintf(buffer, ";%d", SGR_BLINK); |
|
|
|
if (cursor.attrs & ATTR_FRAKTUR) buffer += sprintf(buffer, ";%d", SGR_FRAKTUR); |
|
|
|
if (cursor.attrs & ATTR_FRAKTUR) buffer += sprintf(buffer, ";%d", SGR_FRAKTUR); |
|
|
|
if (cursor.attrs & ATTR_STRIKE) buffer += sprintf(buffer, ";%d", SGR_STRIKE); |
|
|
|
if (cursor.attrs & ATTR_STRIKE) buffer += sprintf(buffer, ";%d", SGR_STRIKE); |
|
|
|
if (cursor.inverse) buffer += sprintf(buffer, ";%d", SGR_INVERSE); |
|
|
|
if (cursor.attrs & ATTR_INVERSE) buffer += sprintf(buffer, ";%d", SGR_INVERSE); |
|
|
|
if (cursor.fg != termconf->default_fg) buffer += sprintf(buffer, ";%d", ((cursor.fg > 7) ? SGR_FG_BRT_START : SGR_FG_START) + (cursor.fg&7)); |
|
|
|
if (cursor.attrs & ATTR_FG) |
|
|
|
if (cursor.bg != termconf->default_bg) buffer += sprintf(buffer, ";%d", ((cursor.bg > 7) ? SGR_BG_BRT_START : SGR_BG_START) + (cursor.bg&7)); |
|
|
|
buffer += sprintf(buffer, ";%d", ((cursor.fg > 7) ? SGR_FG_BRT_START : SGR_FG_START) + (cursor.fg&7)); |
|
|
|
|
|
|
|
if (cursor.attrs & ATTR_BG) |
|
|
|
|
|
|
|
buffer += sprintf(buffer, ";%d", ((cursor.bg > 7) ? SGR_BG_BRT_START : SGR_BG_START) + (cursor.bg&7)); |
|
|
|
(void)buffer; |
|
|
|
(void)buffer; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1381,10 +1511,10 @@ putchar_graphic(const char *ch) |
|
|
|
cursor.x = 0; |
|
|
|
cursor.x = 0; |
|
|
|
cursor.y++; |
|
|
|
cursor.y++; |
|
|
|
// Y wrap
|
|
|
|
// Y wrap
|
|
|
|
if (cursor.y > R1) { |
|
|
|
if (cursor.y > BTM) { |
|
|
|
// Scroll up, so we have space for writing
|
|
|
|
// Scroll up, so we have space for writing
|
|
|
|
screen_scroll_up(1); |
|
|
|
screen_scroll_up(1); |
|
|
|
cursor.y = R1; |
|
|
|
cursor.y = BTM; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
cursor.hanging = false; |
|
|
|
cursor.hanging = false; |
|
|
@ -1403,14 +1533,8 @@ putchar_graphic(const char *ch) |
|
|
|
} |
|
|
|
} |
|
|
|
unicode_cache_remove(c->symbol); |
|
|
|
unicode_cache_remove(c->symbol); |
|
|
|
c->symbol = unicode_cache_add((const u8 *)ch); |
|
|
|
c->symbol = unicode_cache_add((const u8 *)ch); |
|
|
|
|
|
|
|
|
|
|
|
if (cursor.inverse) { |
|
|
|
|
|
|
|
c->fg = cursor.bg; |
|
|
|
|
|
|
|
c->bg = cursor.fg; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
c->fg = cursor.fg; |
|
|
|
c->fg = cursor.fg; |
|
|
|
c->bg = cursor.bg; |
|
|
|
c->bg = cursor.bg; |
|
|
|
} |
|
|
|
|
|
|
|
c->attrs = cursor.attrs; |
|
|
|
c->attrs = cursor.attrs; |
|
|
|
|
|
|
|
|
|
|
|
cursor.x++; |
|
|
|
cursor.x++; |
|
|
@ -1543,7 +1667,7 @@ utf8_remap(char *out, char g, char charset) |
|
|
|
struct ScreenSerializeState { |
|
|
|
struct ScreenSerializeState { |
|
|
|
Color lastFg; |
|
|
|
Color lastFg; |
|
|
|
Color lastBg; |
|
|
|
Color lastBg; |
|
|
|
bool lastAttrs; |
|
|
|
CellAttrs lastAttrs; |
|
|
|
UnicodeCacheRef lastSymbol; |
|
|
|
UnicodeCacheRef lastSymbol; |
|
|
|
char lastChar[4]; |
|
|
|
char lastChar[4]; |
|
|
|
u8 lastCharLen; |
|
|
|
u8 lastCharLen; |
|
|
@ -1593,58 +1717,46 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Cell *cell, *cell0; |
|
|
|
Cell *cell, *cell0; |
|
|
|
WordB2 w1; |
|
|
|
|
|
|
|
WordB3 lw1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
u8 nbytes; |
|
|
|
size_t remain = buf_len; |
|
|
|
size_t remain = buf_len; |
|
|
|
char *bb = buffer; |
|
|
|
char *bb = buffer; |
|
|
|
|
|
|
|
|
|
|
|
#define bufput_c(c) do { \ |
|
|
|
#define bufput_c(c) do { \ |
|
|
|
*bb = (char)c; bb++; \
|
|
|
|
*bb = (char)(c); \
|
|
|
|
|
|
|
|
bb++; \
|
|
|
|
remain--; \
|
|
|
|
remain--; \
|
|
|
|
} while(0) |
|
|
|
} while(0) |
|
|
|
|
|
|
|
|
|
|
|
#define bufput_2B(n) do { \ |
|
|
|
#define bufput_utf8(num) do { \ |
|
|
|
encode2B((u16) n, &w1); \
|
|
|
|
nbytes = utf8_encode(bb, (num)+1); \
|
|
|
|
bufput_c(w1.lsb); \
|
|
|
|
bb += nbytes; \
|
|
|
|
bufput_c(w1.msb); \
|
|
|
|
remain -= nbytes; \
|
|
|
|
} while(0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define bufput_3B(n) do { \ |
|
|
|
|
|
|
|
encode3B((u32) n, &lw1); \
|
|
|
|
|
|
|
|
bufput_c(lw1.lsb); \
|
|
|
|
|
|
|
|
bufput_c(lw1.msb); \
|
|
|
|
|
|
|
|
bufput_c(lw1.xsb); \
|
|
|
|
|
|
|
|
} while(0) |
|
|
|
} while(0) |
|
|
|
|
|
|
|
|
|
|
|
#define bufput_t2B(t, n) do { \ |
|
|
|
#define bufput_t_utf8(t, num) do { \ |
|
|
|
bufput_c(t); \
|
|
|
|
bufput_c((t)); \
|
|
|
|
bufput_2B(n); \
|
|
|
|
bufput_utf8((num)); \
|
|
|
|
} while(0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define bufput_t3B(t, n) do { \ |
|
|
|
|
|
|
|
bufput_c(t); \
|
|
|
|
|
|
|
|
bufput_3B(n); \
|
|
|
|
|
|
|
|
} while(0) |
|
|
|
} while(0) |
|
|
|
|
|
|
|
|
|
|
|
if (ss == NULL) { |
|
|
|
if (ss == NULL) { |
|
|
|
*data = ss = malloc(sizeof(struct ScreenSerializeState)); |
|
|
|
*data = ss = malloc(sizeof(struct ScreenSerializeState)); |
|
|
|
ss->index = 0; |
|
|
|
ss->index = 0; |
|
|
|
ss->lastBg = 0; |
|
|
|
ss->lastBg = 0xFF; |
|
|
|
ss->lastFg = 0; |
|
|
|
ss->lastFg = 0xFF; |
|
|
|
ss->lastAttrs = 0; |
|
|
|
ss->lastAttrs = 0xFFFF; |
|
|
|
ss->lastCharLen = 0; |
|
|
|
ss->lastCharLen = 0; |
|
|
|
ss->lastSymbol = 32; |
|
|
|
ss->lastSymbol = 0; |
|
|
|
strncpy(ss->lastChar, " ", 4); |
|
|
|
strncpy(ss->lastChar, " ", 4); |
|
|
|
|
|
|
|
|
|
|
|
bufput_c('S'); |
|
|
|
bufput_c('S'); |
|
|
|
// H W X Y Attribs
|
|
|
|
// H W X Y Attribs
|
|
|
|
bufput_2B(H); |
|
|
|
bufput_utf8(H); |
|
|
|
bufput_2B(W); |
|
|
|
bufput_utf8(W); |
|
|
|
bufput_2B(cursor.y); |
|
|
|
bufput_utf8(cursor.y); |
|
|
|
bufput_2B(cursor.x); |
|
|
|
bufput_utf8(cursor.x); |
|
|
|
// 3B has 18 free bits
|
|
|
|
// 3B has 18 free bits
|
|
|
|
bufput_3B( |
|
|
|
bufput_utf8( |
|
|
|
(scr.cursor_visible << 0) | |
|
|
|
(scr.cursor_visible << 0) | |
|
|
|
(cursor.hanging << 1) | |
|
|
|
(cursor.hanging << 1) | |
|
|
|
(scr.cursors_alt_mode << 2) | |
|
|
|
(scr.cursors_alt_mode << 2) | |
|
|
@ -1656,7 +1768,8 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data) |
|
|
|
(termconf_live.show_config_links << 8) | |
|
|
|
(termconf_live.show_config_links << 8) | |
|
|
|
((termconf_live.cursor_shape&0x07) << 9) | // 9,10,11 - cursor shape based on DECSCUSR
|
|
|
|
((termconf_live.cursor_shape&0x07) << 9) | // 9,10,11 - cursor shape based on DECSCUSR
|
|
|
|
(termconf_live.crlf_mode << 12) | |
|
|
|
(termconf_live.crlf_mode << 12) | |
|
|
|
(scr.bracketed_paste << 13) |
|
|
|
(scr.bracketed_paste << 13) | |
|
|
|
|
|
|
|
(scr.reverse_video << 14) |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1683,35 +1796,29 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (repCnt == 0) { |
|
|
|
if (repCnt == 0) { |
|
|
|
// No repeat
|
|
|
|
// No repeat - first occurrence
|
|
|
|
bool changeAttrs = cell0->attrs != ss->lastAttrs || i==0; |
|
|
|
bool changeAttrs = cell0->attrs != ss->lastAttrs; |
|
|
|
bool changeFg = cell0->fg != ss->lastFg; |
|
|
|
bool changeFg = cell0->fg != ss->lastFg; |
|
|
|
bool changeBg = cell0->bg != ss->lastBg; |
|
|
|
bool changeBg = cell0->bg != ss->lastBg; |
|
|
|
bool changeColors = (changeFg && changeBg) || i==0; |
|
|
|
bool changeColors = changeFg && changeBg; |
|
|
|
Color fg, bg; |
|
|
|
Color fg, bg; |
|
|
|
|
|
|
|
|
|
|
|
// Reverse fg and bg if we're in global reverse mode
|
|
|
|
// Reverse fg and bg if we're in global reverse mode
|
|
|
|
if (! scr.reverse_video) { |
|
|
|
|
|
|
|
fg = cell0->fg; |
|
|
|
fg = cell0->fg; |
|
|
|
bg = cell0->bg; |
|
|
|
bg = cell0->bg; |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
fg = cell0->bg; |
|
|
|
|
|
|
|
bg = cell0->fg; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (changeColors) { |
|
|
|
if (changeColors) { |
|
|
|
bufput_t3B(SEQ_TAG_COLORS, bg<<8 | fg); |
|
|
|
bufput_t_utf8(SEQ_TAG_COLORS, bg<<8 | fg); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (changeFg) { |
|
|
|
else if (changeFg) { |
|
|
|
bufput_t2B(SEQ_TAG_FG, fg); |
|
|
|
bufput_t_utf8(SEQ_TAG_FG, fg); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (changeBg) { |
|
|
|
else if (changeBg) { |
|
|
|
bufput_t2B(SEQ_TAG_BG, bg); |
|
|
|
bufput_t_utf8(SEQ_TAG_BG, bg); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (changeAttrs) { |
|
|
|
if (changeAttrs) { |
|
|
|
bufput_t2B(SEQ_TAG_ATTRS, cell0->attrs); |
|
|
|
bufput_t_utf8(SEQ_TAG_ATTRS, cell0->attrs); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// copy the symbol, until first 0 or reached 4 bytes
|
|
|
|
// copy the symbol, until first 0 or reached 4 bytes
|
|
|
@ -1733,24 +1840,21 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data) |
|
|
|
i++; |
|
|
|
i++; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// last character was repeated repCnt times
|
|
|
|
// last character was repeated repCnt times
|
|
|
|
int savings = ss->lastCharLen*repCnt; |
|
|
|
bufput_t_utf8(SEQ_TAG_REPEAT, repCnt); |
|
|
|
if (savings > 3) { |
|
|
|
|
|
|
|
// Repeat count
|
|
|
|
|
|
|
|
bufput_t2B(SEQ_TAG_REPEAT, repCnt); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// repeat it manually
|
|
|
|
|
|
|
|
for(int k = 0; k < repCnt; k++) { |
|
|
|
|
|
|
|
for (int j = 0; j < ss->lastCharLen; j++) { |
|
|
|
|
|
|
|
bufput_c(ss->lastChar[j]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ss->index = i; |
|
|
|
ss->index = i; |
|
|
|
bufput_c('\0'); // terminate the string
|
|
|
|
bufput_c('\0'); // terminate the string
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0 |
|
|
|
|
|
|
|
printf("MSG: "); |
|
|
|
|
|
|
|
for (int j=0;j<bb-buffer;j++) { |
|
|
|
|
|
|
|
printf("%02X ", buffer[j]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
printf("\n"); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
if (i < W*H-1) { |
|
|
|
if (i < W*H-1) { |
|
|
|
return HTTPD_CGI_MORE; |
|
|
|
return HTTPD_CGI_MORE; |
|
|
|
} |
|
|
|
} |
|
|
|