FIXED STUPID JSON BUG YOOOO

pull/30/head
Ondřej Hruška 8 years ago
parent 0f7fb9430c
commit f8d848f383
  1. 33
      html/css/app.css
  2. 4
      html/js/app.js
  3. 33
      html_orig/css/app.css
  4. 4
      html_orig/jssrc/term.js
  5. 24
      html_orig/sass/_layout.scss
  6. 204
      user/ansi_parser.c
  7. 51
      user/ansi_parser.rl
  8. 46
      user/screen.c
  9. 2
      user/screen.h
  10. 17
      user/user_main.c

@ -438,40 +438,51 @@ body {
body > * {
margin-left: auto;
margin-right: auto; }
body h1 {
h1, h2 {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; }
h1 {
text-align: center;
font-size: 2.02729em;
margin-top: 0;
margin-bottom: 1rem; }
@media screen and (max-width: 544px) {
body h1 {
h1 {
font-size: 1.42383em;
margin-bottom: 0.61805rem; } }
@media screen and (min-width: 545px) and (max-width: 1000px) {
body h1 {
h1 {
font-size: 1.80203em; } }
body h2 {
h2 {
font-size: 1.26563em;
margin-bottom: 0.61805rem; }
body h2:first-child {
h2:first-child {
margin-top: 0; }
body td, body th {
td, th {
padding: 0.38198rem;
white-space: nowrap; }
@media screen and (max-width: 544px) {
body td, body th {
td, th {
padding: 0.23608rem; } }
body tbody th {
tbody th {
text-align: right;
width: 130px;
color: white; }
@media screen and (max-width: 544px) {
body tbody th {
tbody th {
width: auto; } }
body tbody td input[type="text"], body tbody td input[type="number"] {
tbody td input[type="text"], tbody td input[type="number"] {
width: 10em; }
@media screen and (max-width: 544px) {
body tbody td input[type="text"], body tbody td input[type="number"] {
tbody td input[type="text"], tbody td input[type="number"] {
width: 8em; } }
#loader {

@ -894,6 +894,7 @@ $._loader = function(vis) {
var W, H;
var cursor = {a: false, x: 0, y: 0, suppress: false, hidden: false};
var screen = [];
var blinkIval;
/** Colors table */
var CLR = [// dark gray #2E3436
@ -1071,7 +1072,8 @@ $._loader = function(vis) {
}
/* Cursor blinking */
setInterval(function() {
clearInterval(blinkIval);
blinkIval = setInterval(function() {
cursor.a = !cursor.a;
if (cursor.hidden) {
cursor.a = false;

@ -438,40 +438,51 @@ body {
body > * {
margin-left: auto;
margin-right: auto; }
body h1 {
h1, h2 {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; }
h1 {
text-align: center;
font-size: 2.02729em;
margin-top: 0;
margin-bottom: 1rem; }
@media screen and (max-width: 544px) {
body h1 {
h1 {
font-size: 1.42383em;
margin-bottom: 0.61805rem; } }
@media screen and (min-width: 545px) and (max-width: 1000px) {
body h1 {
h1 {
font-size: 1.80203em; } }
body h2 {
h2 {
font-size: 1.26563em;
margin-bottom: 0.61805rem; }
body h2:first-child {
h2:first-child {
margin-top: 0; }
body td, body th {
td, th {
padding: 0.38198rem;
white-space: nowrap; }
@media screen and (max-width: 544px) {
body td, body th {
td, th {
padding: 0.23608rem; } }
body tbody th {
tbody th {
text-align: right;
width: 130px;
color: white; }
@media screen and (max-width: 544px) {
body tbody th {
tbody th {
width: auto; } }
body tbody td input[type="text"], body tbody td input[type="number"] {
tbody td input[type="text"], tbody td input[type="number"] {
width: 10em; }
@media screen and (max-width: 544px) {
body tbody td input[type="text"], body tbody td input[type="number"] {
tbody td input[type="text"], tbody td input[type="number"] {
width: 8em; } }
#loader {

@ -6,6 +6,7 @@
var W, H;
var cursor = {a: false, x: 0, y: 0, suppress: false, hidden: false};
var screen = [];
var blinkIval;
/** Colors table */
var CLR = [// dark gray #2E3436
@ -183,7 +184,8 @@
}
/* Cursor blinking */
setInterval(function() {
clearInterval(blinkIval);
blinkIval = setInterval(function() {
cursor.a = !cursor.a;
if (cursor.hidden) {
cursor.a = false;

@ -78,8 +78,13 @@ body {
margin-left: auto;
margin-right: auto;
}
}
h1,h2 {
@include noselect();
}
h1 {
h1 {
text-align: center;
font-size: fsize(6);
margin-top: 0;
@ -93,24 +98,24 @@ body {
@include media($tablet) {
font-size: fsize(5);
}
}
}
h2 {
h2 {
font-size: fsize(2);
margin-bottom: dist(-1);
&:first-child{margin-top:0}
}
}
td, th {
td, th {
padding: dist(-2);
white-space: nowrap;
@include media($phone) {
padding: dist(-3);
}
}
}
tbody th {
tbody th {
text-align: right;
width: $form-label-w;
color: $c-form-label-fg;
@ -118,9 +123,9 @@ body {
@include media($phone) {
width: auto;
}
}
}
tbody td {
tbody td {
input[type="text"], input[type="number"] {
width: 10em;
@ -128,7 +133,6 @@ body {
width: 8em;
}
}
}
}
// Loader wheel in top right corner

@ -182,28 +182,49 @@ handle_plainchar(char c)
screen_putchar(c);
}
void ICACHE_FLASH_ATTR
handle_OSC_FactoryReset(void)
{
info("OSC: Factory reset");
warn("NOT IMPLEMENTED");
// TODO
}
void ICACHE_FLASH_ATTR
handle_OSC_SetScreenSize(int rows, int cols)
{
info("OSC: Set screen size to %d x %d", rows, cols);
screen_resize(rows, cols);
}
/* Ragel constants block */
/* #line 188 "user/ansi_parser.c" */
/* #line 206 "user/ansi_parser.c" */
static const char _ansi_actions[] = {
0, 1, 0, 1, 1, 1, 2, 1,
3, 1, 4, 1, 5, 1, 6, 1,
7, 1, 8, 1, 9
7, 1, 8, 1, 9, 1, 10
};
static const char _ansi_eof_actions[] = {
0, 15, 15, 13, 13, 0, 0
0, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 0, 0,
0
};
static const int ansi_start = 1;
static const int ansi_first_final = 5;
static const int ansi_first_final = 14;
static const int ansi_error = 0;
static const int ansi_en_CSI_body = 3;
static const int ansi_en_OSC_body = 5;
static const int ansi_en_main = 1;
/* #line 187 "user/ansi_parser.rl" */
/* #line 205 "user/ansi_parser.rl" */
/**
@ -240,17 +261,17 @@ ansi_parser(const char *newdata, size_t len)
// Init Ragel on the first run
if (cs == -1) {
/* #line 244 "user/ansi_parser.c" */
/* #line 265 "user/ansi_parser.c" */
{
cs = ansi_start;
}
/* #line 223 "user/ansi_parser.rl" */
/* #line 241 "user/ansi_parser.rl" */
}
// The parser
/* #line 254 "user/ansi_parser.c" */
/* #line 275 "user/ansi_parser.c" */
{
const char *_acts;
unsigned int _nacts;
@ -274,79 +295,137 @@ case 2:
goto tr2;
case 0:
goto _out;
case 5:
case 14:
if ( (*p) == 27 )
goto tr1;
goto tr0;
case 3:
if ( (*p) == 59 )
goto tr9;
goto tr8;
if ( (*p) < 60 ) {
if ( (*p) > 47 ) {
if ( 48 <= (*p) && (*p) <= 57 )
goto tr8;
} else if ( (*p) >= 32 )
goto tr7;
} else if ( (*p) >= 32 )
goto tr6;
} else if ( (*p) > 64 ) {
if ( (*p) > 90 ) {
if ( 97 <= (*p) && (*p) <= 122 )
goto tr10;
goto tr9;
} else if ( (*p) >= 65 )
goto tr10;
goto tr9;
} else
goto tr7;
goto tr6;
goto tr2;
case 4:
if ( (*p) == 59 )
goto tr9;
goto tr8;
if ( (*p) < 65 ) {
if ( 48 <= (*p) && (*p) <= 57 )
goto tr8;
goto tr7;
} else if ( (*p) > 90 ) {
if ( 97 <= (*p) && (*p) <= 122 )
goto tr10;
goto tr9;
} else
goto tr10;
goto tr6;
goto tr9;
goto tr2;
case 15:
goto tr2;
case 5:
switch( (*p) ) {
case 70: goto tr10;
case 87: goto tr11;
}
goto tr2;
case 6:
goto tr6;
if ( (*p) == 82 )
goto tr12;
goto tr2;
case 7:
switch( (*p) ) {
case 7: goto tr13;
case 27: goto tr14;
}
goto tr2;
case 16:
goto tr2;
case 8:
if ( (*p) == 92 )
goto tr13;
goto tr2;
case 9:
if ( 48 <= (*p) && (*p) <= 57 )
goto tr15;
goto tr2;
case 10:
if ( (*p) == 59 )
goto tr16;
if ( 48 <= (*p) && (*p) <= 57 )
goto tr15;
goto tr2;
case 11:
if ( 48 <= (*p) && (*p) <= 57 )
goto tr17;
goto tr2;
case 12:
switch( (*p) ) {
case 7: goto tr18;
case 27: goto tr19;
}
if ( 48 <= (*p) && (*p) <= 57 )
goto tr17;
goto tr2;
case 13:
if ( (*p) == 92 )
goto tr18;
goto tr2;
}
tr2: cs = 0; goto f0;
tr6: cs = 0; goto f5;
tr0: cs = 1; goto f1;
tr1: cs = 2; goto _again;
tr6: cs = 4; goto f5;
tr7: cs = 4; goto f6;
tr8: cs = 4; goto f7;
tr9: cs = 4; goto f8;
tr3: cs = 5; goto f2;
tr4: cs = 5; goto f3;
tr5: cs = 5; goto f4;
tr10: cs = 6; goto f9;
tr10: cs = 6; goto _again;
tr12: cs = 7; goto _again;
tr14: cs = 8; goto _again;
tr11: cs = 9; goto _again;
tr15: cs = 10; goto f6;
tr16: cs = 11; goto f7;
tr17: cs = 12; goto f6;
tr19: cs = 13; goto _again;
tr3: cs = 14; goto f2;
tr4: cs = 14; goto f3;
tr5: cs = 14; goto f4;
tr9: cs = 15; goto f8;
tr13: cs = 16; goto f9;
tr18: cs = 16; goto f10;
f1: _acts = _ansi_actions + 1; goto execFuncs;
f2: _acts = _ansi_actions + 3; goto execFuncs;
f6: _acts = _ansi_actions + 5; goto execFuncs;
f7: _acts = _ansi_actions + 7; goto execFuncs;
f8: _acts = _ansi_actions + 9; goto execFuncs;
f9: _acts = _ansi_actions + 11; goto execFuncs;
f5: _acts = _ansi_actions + 13; goto execFuncs;
f0: _acts = _ansi_actions + 15; goto execFuncs;
f3: _acts = _ansi_actions + 17; goto execFuncs;
f4: _acts = _ansi_actions + 19; goto execFuncs;
f5: _acts = _ansi_actions + 5; goto execFuncs;
f6: _acts = _ansi_actions + 7; goto execFuncs;
f7: _acts = _ansi_actions + 9; goto execFuncs;
f8: _acts = _ansi_actions + 11; goto execFuncs;
f0: _acts = _ansi_actions + 13; goto execFuncs;
f3: _acts = _ansi_actions + 15; goto execFuncs;
f9: _acts = _ansi_actions + 17; goto execFuncs;
f10: _acts = _ansi_actions + 19; goto execFuncs;
f4: _acts = _ansi_actions + 21; goto execFuncs;
execFuncs:
_nacts = *_acts++;
while ( _nacts-- > 0 ) {
switch ( *_acts++ ) {
case 0:
/* #line 233 "user/ansi_parser.rl" */
/* #line 251 "user/ansi_parser.rl" */
{
handle_plainchar((*p));
}
break;
case 1:
/* #line 240 "user/ansi_parser.rl" */
/* #line 258 "user/ansi_parser.rl" */
{
/* Reset the CSI builder */
csi_leading = csi_char = 0;
@ -361,13 +440,13 @@ execFuncs:
}
break;
case 2:
/* #line 253 "user/ansi_parser.rl" */
/* #line 271 "user/ansi_parser.rl" */
{
csi_leading = (*p);
}
break;
case 3:
/* #line 257 "user/ansi_parser.rl" */
/* #line 275 "user/ansi_parser.rl" */
{
/* x10 + digit */
if (csi_ni < CSI_N_MAX) {
@ -376,13 +455,13 @@ execFuncs:
}
break;
case 4:
/* #line 264 "user/ansi_parser.rl" */
/* #line 282 "user/ansi_parser.rl" */
{
csi_ni++;
}
break;
case 5:
/* #line 268 "user/ansi_parser.rl" */
/* #line 286 "user/ansi_parser.rl" */
{
csi_char = (*p);
@ -392,33 +471,49 @@ execFuncs:
}
break;
case 6:
/* #line 276 "user/ansi_parser.rl" */
/* #line 294 "user/ansi_parser.rl" */
{
warn("Invalid escape sequence discarded.");
{cs = 1; goto _again;}
}
break;
case 7:
/* #line 280 "user/ansi_parser.rl" */
/* #line 311 "user/ansi_parser.rl" */
{
{cs = 1; goto _again;}
csi_ni = 0;
// we reuse the CSI numeric buffer
for(int i = 0; i < CSI_N_MAX; i++) {
csi_n[i] = 0;
}
{cs = 5; goto _again;}
}
break;
case 8:
/* #line 292 "user/ansi_parser.rl" */
/* #line 322 "user/ansi_parser.rl" */
{
// TODO implement OS control code parsing
handle_OSC_FactoryReset();
{cs = 1; goto _again;}
}
break;
case 9:
/* #line 297 "user/ansi_parser.rl" */
/* #line 327 "user/ansi_parser.rl" */
{
handle_OSC_SetScreenSize(csi_n[0], csi_n[1]);
{cs = 1; goto _again;}
}
break;
case 10:
/* #line 338 "user/ansi_parser.rl" */
{
// Reset screen
handle_RESET_cmd();
{cs = 1; goto _again;}
}
break;
/* #line 422 "user/ansi_parser.c" */
/* #line 517 "user/ansi_parser.c" */
}
}
goto _again;
@ -436,18 +531,13 @@ _again:
while ( __nacts-- > 0 ) {
switch ( *__acts++ ) {
case 6:
/* #line 276 "user/ansi_parser.rl" */
{
{cs = 1; goto _again;}
}
break;
case 7:
/* #line 280 "user/ansi_parser.rl" */
/* #line 294 "user/ansi_parser.rl" */
{
warn("Invalid escape sequence discarded.");
{cs = 1; goto _again;}
}
break;
/* #line 451 "user/ansi_parser.c" */
/* #line 541 "user/ansi_parser.c" */
}
}
}
@ -455,6 +545,6 @@ _again:
_out: {}
}
/* #line 315 "user/ansi_parser.rl" */
/* #line 356 "user/ansi_parser.rl" */
}

@ -180,6 +180,24 @@ handle_plainchar(char c)
screen_putchar(c);
}
void ICACHE_FLASH_ATTR
handle_OSC_FactoryReset(void)
{
info("OSC: Factory reset");
warn("NOT IMPLEMENTED");
// TODO
}
void ICACHE_FLASH_ATTR
handle_OSC_SetScreenSize(int rows, int cols)
{
info("OSC: Set screen size to %d x %d", rows, cols);
screen_resize(rows, cols);
}
/* Ragel constants block */
%%{
machine ansi;
@ -273,27 +291,50 @@ ansi_parser(const char *newdata, size_t len)
fgoto main;
}
action CSI_fail {
action errBadSeq {
warn("Invalid escape sequence discarded.");
fgoto main;
}
action main_fail {
action back2main {
fgoto main;
}
CSI_body := ((32..47|60..64) @CSI_leading)?
((digit @CSI_digit)* ';' @CSI_semi)*
(digit @CSI_digit)* alpha @CSI_end $!CSI_fail;
(digit @CSI_digit)* alpha @CSI_end $!errBadSeq;
# --- OSC commands (Operating System Commands) ---
# Module parametrisation
action OSC_start {
// TODO implement OS control code parsing
csi_ni = 0;
// we reuse the CSI numeric buffer
for(int i = 0; i < CSI_N_MAX; i++) {
csi_n[i] = 0;
}
fgoto OSC_body;
}
action OSC_fr {
handle_OSC_FactoryReset();
fgoto main;
}
action OSC_resize {
handle_OSC_SetScreenSize(csi_n[0], csi_n[1]);
fgoto main;
}
OSC_body := (
("FR" ('\a' | ESC '\\') @OSC_fr) |
('W' (digit @CSI_digit)+ ';' @CSI_semi (digit @CSI_digit)+ ('\a' | ESC '\\') @OSC_resize)
) $!errBadSeq;
action RESET_cmd {
// Reset screen
handle_RESET_cmd();
@ -309,7 +350,7 @@ ansi_parser(const char *newdata, size_t len)
']' @OSC_start |
'c' @RESET_cmd
)
)+ $!main_fail;
)+ $!errBadSeq;
write exec;
}%%

@ -189,20 +189,28 @@ screen_clear_line(ClearMode mode)
/**
* Change the screen size
*
* @param w - new width
* @param h - new height
* @param cols - new width
* @param rows - new height
*/
void ICACHE_FLASH_ATTR
screen_resize(Coordinate w, Coordinate h)
screen_resize(Coordinate rows, Coordinate cols)
{
NOTIFY_LOCK();
// sanitize
if (w < 1) w = 1;
if (h < 1) h = 1;
if (cols < 1 || rows < 1) {
error("Screen size must be positive");
goto done;
}
if (cols * rows > MAX_SCREEN_SIZE) {
error("Max screen size exceeded");
goto done;
}
W = w;
H = h;
W = cols;
H = rows;
screen_reset();
done:
NOTIFY_DONE();
}
@ -579,11 +587,11 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data)
ss->lastFg = 0;
ss->lastChar = '\0';
bufprint("{\"w\":%d,\"h\":%d,\"x\":%d,\"y\":%d,\"cv\":%d,\"screen\":\"", W, H, cursor.x, cursor.y, cursor.visible);
bufprint("{\n \"w\": %d, \"h\": %d,\n \"x\": %d, \"y\": %d,\n \"cv\": %d,\n \"screen\": \"", W, H, cursor.x, cursor.y, cursor.visible);
}
int i = ss->index;
while(i < W*H && remain > 6) {
while(i < W*H && remain > 12) {
cell = cell0 = &screen[i];
// Count how many times same as previous
@ -598,11 +606,25 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data)
}
if (repCnt == 0) {
// All this crap is needed because it's JSON and also
// embedded in HTML (hence the angle brackets)
if (cell0->fg == ss->lastFg && cell0->bg == ss->lastBg) {
// same colors as previous
bufprint(",%c", cell0->c);
bufprint(",");
} else {
bufprint("%X%X%c", cell0->fg, cell0->bg, cell0->c);
bufprint("%X%X", cell0->fg, cell0->bg);
}
char c = cell0->c;
if (c == '"' || c == '\\') {
bufprint("\\%c", c);
}
else if (c == '<' || c == '>' || c == '\'' || c == '/' || c == '&') {
bufprint("\\u00%02X", (int)c);
}
else {
bufprint("%c", c);
}
ss->lastFg = cell0->fg;
@ -633,7 +655,7 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data)
}
if (remain >= 3) {
bufprint("\"}");
bufprint("\"\n}");
return HTTPD_CGI_DONE;
} else {
return HTTPD_CGI_MORE;

@ -62,7 +62,7 @@ screenSerializeToBuffer(char *buffer, size_t buf_len, void **data);
void screen_init(void);
/** Change the screen size */
void screen_resize(Coordinate w, Coordinate h);
void screen_resize(Coordinate rows, Coordinate cols);
// --- Clearing ---

@ -50,17 +50,20 @@ static ETSTimer prHeapTimer;
/** Periodically show heap usage */
static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg)
{
static uint32_t cnt = 0;
static uint32_t last = 0;
if (cnt == 5) {
uint32_t heap = system_get_free_heap_size();
dbg("Free heap: %d bytes (~ %d)", heap, (heap-last));
cnt = 0;
last = heap;
int32_t diff = (heap-last);
const char *cc = "+";
if (diff<0) cc = "";
if (diff == 0) {
dbg("Free heap: %d bytes", heap);
} else {
dbg("Free heap: %d bytes (%s%d)", heap, cc, diff);
}
cnt++;
last = heap;
}
//Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done.
@ -97,7 +100,7 @@ void ICACHE_FLASH_ATTR user_init(void)
// Heap use timer & blink
os_timer_disarm(&prHeapTimer);
os_timer_setfn(&prHeapTimer, prHeapTimerCb, NULL);
os_timer_arm(&prHeapTimer, 1000, 1);
os_timer_arm(&prHeapTimer, 5000, 1);
// The terminal screen
screen_init();

Loading…
Cancel
Save