Tab Stops™
This commit is contained in:
+27
-24
@@ -150,11 +150,14 @@ ansi_parser(char newchar)
|
||||
newchar = LF; // translate to LF, like VT100 / xterm do
|
||||
case CR:
|
||||
case LF:
|
||||
case TAB:
|
||||
case BS:
|
||||
apars_handle_plainchar(newchar);
|
||||
return;
|
||||
|
||||
case TAB:
|
||||
screen_tab_forward();
|
||||
return;
|
||||
|
||||
// Select G0 or G1
|
||||
case SI:
|
||||
screen_set_charset_n(1);
|
||||
@@ -202,7 +205,7 @@ ansi_parser(char newchar)
|
||||
|
||||
// The parser
|
||||
|
||||
/* #line 206 "user/ansi_parser.c" */
|
||||
/* #line 209 "user/ansi_parser.c" */
|
||||
{
|
||||
const char *_acts;
|
||||
unsigned int _nacts;
|
||||
@@ -488,7 +491,7 @@ execFuncs:
|
||||
while ( _nacts-- > 0 ) {
|
||||
switch ( *_acts++ ) {
|
||||
case 0:
|
||||
/* #line 177 "user/ansi_parser.rl" */
|
||||
/* #line 180 "user/ansi_parser.rl" */
|
||||
{
|
||||
if ((*p) != 0) {
|
||||
apars_handle_plainchar((*p));
|
||||
@@ -496,7 +499,7 @@ execFuncs:
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
/* #line 186 "user/ansi_parser.rl" */
|
||||
/* #line 189 "user/ansi_parser.rl" */
|
||||
{
|
||||
// Reset the CSI builder
|
||||
csi_leading = csi_char = 0;
|
||||
@@ -512,13 +515,13 @@ execFuncs:
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/* #line 200 "user/ansi_parser.rl" */
|
||||
/* #line 203 "user/ansi_parser.rl" */
|
||||
{
|
||||
csi_leading = (*p);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
/* #line 204 "user/ansi_parser.rl" */
|
||||
/* #line 207 "user/ansi_parser.rl" */
|
||||
{
|
||||
if (csi_cnt == 0) csi_cnt = 1;
|
||||
// x10 + digit
|
||||
@@ -528,7 +531,7 @@ execFuncs:
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
/* #line 212 "user/ansi_parser.rl" */
|
||||
/* #line 215 "user/ansi_parser.rl" */
|
||||
{
|
||||
if (csi_cnt == 0) csi_cnt = 1; // handle case when first arg is empty
|
||||
csi_cnt++;
|
||||
@@ -536,7 +539,7 @@ execFuncs:
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
/* #line 218 "user/ansi_parser.rl" */
|
||||
/* #line 221 "user/ansi_parser.rl" */
|
||||
{
|
||||
csi_char = (*p);
|
||||
apars_handle_CSI(csi_leading, csi_n, csi_cnt, csi_char);
|
||||
@@ -544,7 +547,7 @@ execFuncs:
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
/* #line 224 "user/ansi_parser.rl" */
|
||||
/* #line 227 "user/ansi_parser.rl" */
|
||||
{
|
||||
ansi_warn("Parser error.");
|
||||
apars_handle_badseq();
|
||||
@@ -552,7 +555,7 @@ execFuncs:
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
/* #line 242 "user/ansi_parser.rl" */
|
||||
/* #line 245 "user/ansi_parser.rl" */
|
||||
{
|
||||
csi_ni = 0;
|
||||
|
||||
@@ -570,7 +573,7 @@ execFuncs:
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
/* #line 259 "user/ansi_parser.rl" */
|
||||
/* #line 262 "user/ansi_parser.rl" */
|
||||
{
|
||||
osc_bi = 0;
|
||||
osc_buffer[0] = '\0';
|
||||
@@ -579,7 +582,7 @@ execFuncs:
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
/* #line 266 "user/ansi_parser.rl" */
|
||||
/* #line 269 "user/ansi_parser.rl" */
|
||||
{
|
||||
apars_handle_OSC_SetScreenSize(csi_n[0], csi_n[1]);
|
||||
inside_osc = false;
|
||||
@@ -587,13 +590,13 @@ execFuncs:
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
/* #line 272 "user/ansi_parser.rl" */
|
||||
/* #line 275 "user/ansi_parser.rl" */
|
||||
{
|
||||
osc_buffer[osc_bi++] = (*p);
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
/* #line 276 "user/ansi_parser.rl" */
|
||||
/* #line 279 "user/ansi_parser.rl" */
|
||||
{
|
||||
osc_buffer[osc_bi++] = '\0';
|
||||
apars_handle_OSC_SetTitle(osc_buffer);
|
||||
@@ -602,7 +605,7 @@ execFuncs:
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
/* #line 283 "user/ansi_parser.rl" */
|
||||
/* #line 286 "user/ansi_parser.rl" */
|
||||
{
|
||||
osc_buffer[osc_bi++] = '\0';
|
||||
apars_handle_OSC_SetButton(csi_n[0], osc_buffer);
|
||||
@@ -611,28 +614,28 @@ execFuncs:
|
||||
}
|
||||
break;
|
||||
case 13:
|
||||
/* #line 316 "user/ansi_parser.rl" */
|
||||
/* #line 319 "user/ansi_parser.rl" */
|
||||
{
|
||||
apars_handle_hashCode((*p));
|
||||
{cs = 1;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 14:
|
||||
/* #line 321 "user/ansi_parser.rl" */
|
||||
/* #line 324 "user/ansi_parser.rl" */
|
||||
{
|
||||
apars_handle_shortCode((*p));
|
||||
{cs = 1;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 15:
|
||||
/* #line 326 "user/ansi_parser.rl" */
|
||||
/* #line 329 "user/ansi_parser.rl" */
|
||||
{
|
||||
apars_handle_setXCtrls((*p)); // weird control settings like 7 bit / 8 bit mode
|
||||
{cs = 1;goto _again;}
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
/* #line 331 "user/ansi_parser.rl" */
|
||||
/* #line 334 "user/ansi_parser.rl" */
|
||||
{
|
||||
// abuse the buffer for storing the leading char
|
||||
osc_buffer[0] = (*p);
|
||||
@@ -640,13 +643,13 @@ execFuncs:
|
||||
}
|
||||
break;
|
||||
case 17:
|
||||
/* #line 337 "user/ansi_parser.rl" */
|
||||
/* #line 340 "user/ansi_parser.rl" */
|
||||
{
|
||||
apars_handle_characterSet(osc_buffer[0], (*p));
|
||||
{cs = 1;goto _again;}
|
||||
}
|
||||
break;
|
||||
/* #line 650 "user/ansi_parser.c" */
|
||||
/* #line 653 "user/ansi_parser.c" */
|
||||
}
|
||||
}
|
||||
goto _again;
|
||||
@@ -664,7 +667,7 @@ _again:
|
||||
while ( __nacts-- > 0 ) {
|
||||
switch ( *__acts++ ) {
|
||||
case 6:
|
||||
/* #line 224 "user/ansi_parser.rl" */
|
||||
/* #line 227 "user/ansi_parser.rl" */
|
||||
{
|
||||
ansi_warn("Parser error.");
|
||||
apars_handle_badseq();
|
||||
@@ -673,7 +676,7 @@ _again:
|
||||
goto _again;}
|
||||
}
|
||||
break;
|
||||
/* #line 677 "user/ansi_parser.c" */
|
||||
/* #line 680 "user/ansi_parser.c" */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -681,7 +684,7 @@ goto _again;}
|
||||
_out: {}
|
||||
}
|
||||
|
||||
/* #line 361 "user/ansi_parser.rl" */
|
||||
/* #line 364 "user/ansi_parser.rl" */
|
||||
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -114,11 +114,14 @@ ansi_parser(char newchar)
|
||||
newchar = LF; // translate to LF, like VT100 / xterm do
|
||||
case CR:
|
||||
case LF:
|
||||
case TAB:
|
||||
case BS:
|
||||
apars_handle_plainchar(newchar);
|
||||
return;
|
||||
|
||||
case TAB:
|
||||
screen_tab_forward();
|
||||
return;
|
||||
|
||||
// Select G0 or G1
|
||||
case SI:
|
||||
screen_set_charset_n(1);
|
||||
|
||||
@@ -136,6 +136,8 @@ apars_handle_CSI(char leadchar, int *params, int count, char keychar)
|
||||
case 'M':
|
||||
case '@':
|
||||
case 'P':
|
||||
case 'I':
|
||||
case 'Z':
|
||||
if (n1 == 0) n1 = 1;
|
||||
break;
|
||||
|
||||
@@ -257,14 +259,26 @@ apars_handle_CSI(char leadchar, int *params, int count, char keychar)
|
||||
for (int i = 0; i < count; i++) {
|
||||
int n = params[i];
|
||||
if (leadchar == '?') {
|
||||
if (n == 25) {
|
||||
screen_cursor_visible(yn);
|
||||
if (n == 1) {
|
||||
screen_set_cursors_alt_mode(yn);
|
||||
}
|
||||
else if (n == 6) {
|
||||
// TODO origin mode (scrolling region)
|
||||
}
|
||||
else if (n == 7) {
|
||||
screen_wrap_enable(yn);
|
||||
}
|
||||
else if (n == 1) {
|
||||
screen_set_cursors_alt_mode(yn);
|
||||
else if (n == 8) {
|
||||
// TODO autorepeat mode
|
||||
}
|
||||
else if (n == 9) {
|
||||
// TODO X10 mouse
|
||||
}
|
||||
else if (n == 1000) {
|
||||
// TODo X11 mouse
|
||||
}
|
||||
else if (n == 25) {
|
||||
screen_cursor_visible(yn);
|
||||
}
|
||||
else {
|
||||
// ansi_warn("NOIMPL DEC opt %d", n);
|
||||
@@ -371,13 +385,23 @@ apars_handle_CSI(char leadchar, int *params, int count, char keychar)
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
// TODO clear tab
|
||||
// ansi_warn("NOIMPL clear tab");
|
||||
if (n1 == 3) {
|
||||
screen_clear_all_tabs();
|
||||
} else {
|
||||
screen_clear_tab();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
// TODO back tab
|
||||
// ansi_warn("NOIMPL cursor back tab");
|
||||
for(; n1 > 0; n1--) {
|
||||
screen_tab_reverse();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
for(; n1 > 0; n1--) {
|
||||
screen_tab_forward();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c': // CSI-c
|
||||
@@ -438,8 +462,7 @@ void ICACHE_FLASH_ATTR apars_handle_shortCode(char c)
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
// TODO set tab
|
||||
// ansi_warn("NOIMPL set tab");
|
||||
screen_set_tab();
|
||||
break;
|
||||
|
||||
case '>':
|
||||
|
||||
+125
-15
@@ -32,6 +32,13 @@ typedef struct __attribute__((packed)){
|
||||
*/
|
||||
static Cell screen[MAX_SCREEN_SIZE];
|
||||
|
||||
|
||||
#define TABSTOP_WORDS 5
|
||||
/**
|
||||
* Tab stops bitmap
|
||||
*/
|
||||
static u32 tab_stops[TABSTOP_WORDS];
|
||||
|
||||
/**
|
||||
* Screen state structure
|
||||
*/
|
||||
@@ -204,10 +211,126 @@ screen_reset(void)
|
||||
// size is left unchanged
|
||||
screen_clear(CLEAR_ALL);
|
||||
|
||||
screen_clear_all_tabs();
|
||||
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region --- Tab stops ---
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_clear_all_tabs(void)
|
||||
{
|
||||
memset(tab_stops, 0, sizeof(tab_stops));
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_set_tab(void)
|
||||
{
|
||||
tab_stops[cursor.x/32] |= (1<<(cursor.x%32));
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_clear_tab(void)
|
||||
{
|
||||
tab_stops[cursor.x/32] &= ~(1<<(cursor.x%32));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find tab stop closest to cursor to the right
|
||||
* @return X pos or -1
|
||||
*/
|
||||
static int ICACHE_FLASH_ATTR
|
||||
next_tab_stop(void)
|
||||
{
|
||||
// cursor must never go past EOL
|
||||
if (cursor.x >= W-1) return -1;
|
||||
|
||||
// find first word to inspect
|
||||
int idx = (cursor.x+1)/32;
|
||||
int offs = (cursor.x+1)%32;
|
||||
int cp = cursor.x;
|
||||
while (idx < TABSTOP_WORDS) {
|
||||
u32 w = tab_stops[idx];
|
||||
w >>= offs;
|
||||
for(;offs<32;offs++) {
|
||||
cp++;
|
||||
if (cp >= W) return -1;
|
||||
if (w & 1) return cp;
|
||||
w >>= 1;
|
||||
}
|
||||
offs = 0;
|
||||
idx++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find tab stop closest to cursor to the left
|
||||
* @return X pos or -1
|
||||
*/
|
||||
static int ICACHE_FLASH_ATTR
|
||||
prev_tab_stop(void)
|
||||
{
|
||||
// nowhere to go
|
||||
if (cursor.x == 0) return -1;
|
||||
|
||||
// find first word to inspect
|
||||
int idx = (cursor.x-1)/32;
|
||||
int offs = (cursor.x-1)%32;
|
||||
int cp = cursor.x;
|
||||
while (idx >= 0) {
|
||||
u32 w = tab_stops[idx];
|
||||
w <<= 31-offs;
|
||||
if (w == 0) {
|
||||
cp -= cp%32;
|
||||
if (cp < 0) return -1;
|
||||
goto next;
|
||||
}
|
||||
for(;offs>=0;offs--) {
|
||||
cp--;
|
||||
if (cp < 0) return -1;
|
||||
if (w & (1<<31)) return cp;
|
||||
w <<= 1;
|
||||
}
|
||||
next:
|
||||
offs = 31;
|
||||
idx--;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_tab_forward(void)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
int tab = next_tab_stop();
|
||||
if (tab != -1) {
|
||||
cursor.x = tab;
|
||||
} else {
|
||||
cursor.x = W-1;
|
||||
}
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
screen_tab_reverse(void)
|
||||
{
|
||||
NOTIFY_LOCK();
|
||||
int tab = prev_tab_stop();
|
||||
if (tab != -1) {
|
||||
cursor.x = tab;
|
||||
} else {
|
||||
cursor.x = 0;
|
||||
}
|
||||
NOTIFY_DONE();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region --- Clearing & inserting ---
|
||||
|
||||
/**
|
||||
@@ -742,29 +865,16 @@ screen_putchar(const char *ch)
|
||||
|
||||
case 8: // BS
|
||||
if (cursor.x > 0) {
|
||||
// according to vttest, backspace should go to col 79 if "hanging" after 80
|
||||
if (cursor.hanging) {
|
||||
cursor.hanging = false;
|
||||
} else {
|
||||
cursor.x--;
|
||||
}
|
||||
cursor.x--;
|
||||
}
|
||||
// we should not wrap around
|
||||
// and apparently backspace should not even clear the cell
|
||||
goto done;
|
||||
|
||||
case 9: // TAB
|
||||
// // TODO change to "go to next tab stop"
|
||||
// if (cursor.x<((W-1)-(W-1)%4)) {
|
||||
// c->c[0] = ' ';
|
||||
// c->c[1] = 0;
|
||||
// c->c[2] = 0;
|
||||
// c->c[3] = 0;
|
||||
// do {
|
||||
// screen_putchar(" ");
|
||||
// } while(cursor.x%4!=0);
|
||||
// }
|
||||
goto done;
|
||||
|
||||
default:
|
||||
if (ch[0] < ' ') {
|
||||
// Discard
|
||||
|
||||
@@ -193,6 +193,14 @@ void screen_set_cursors_alt_mode(bool app_mode);
|
||||
void screen_set_charset_n(int Gx);
|
||||
void screen_set_charset(int Gx, char charset);
|
||||
|
||||
// tabs
|
||||
|
||||
void screen_clear_all_tabs(void);
|
||||
void screen_set_tab(void);
|
||||
void screen_clear_tab(void);
|
||||
void screen_tab_forward(void);
|
||||
void screen_tab_reverse(void);
|
||||
|
||||
/**
|
||||
* Set a character in the cursor color, move to right with wrap.
|
||||
* The character may be ASCII (then only one char is used), or
|
||||
|
||||
Reference in New Issue
Block a user