The next little game in the series where I make a fancy rogue game.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
roguish/ansi_parser.rl

100 lines
2.3 KiB

#include <fmt/core.h>
#include <string_view>
#include <charconv>
#include "dbc.hpp"
#include <SFML/Graphics.hpp>
#include "ansi_parser.hpp"
using namespace fmt;
%%{
machine foo;
alphtype int;
action tstart {
start = fpc;
}
action number {
value = 0;
size_t len = fpc - start;
dbc::check(start[0] != '-', "negative numbers not supported");
switch(len) {
case 10: value += (start[len-10] - '0') * 1000000000;
case 9: value += (start[len- 9] - '0') * 100000000;
case 8: value += (start[len- 8] - '0') * 10000000;
case 7: value += (start[len- 7] - '0') * 1000000;
case 6: value += (start[len- 6] - '0') * 100000;
case 5: value += (start[len- 5] - '0') * 10000;
case 4: value += (start[len- 4] - '0') * 1000;
case 3: value += (start[len- 3] - '0') * 100;
case 2: value += (start[len- 2] - '0') * 10;
case 1: value += (start[len- 1] - '0');
break;
default:
dbc::sentinel("can't process > 10 digits");
}
}
action color24b { }
action is_fg {
target = color;
}
action is_bg {
target = bgcolor;
}
action out {
write(bgcolor, color, fc);
}
action reset_fg { color = default_fg; }
action reset_bg { bgcolor = default_bg; }
action red { target.r = value; }
action blue { target.g = value; }
action green { target.b = value; }
action start { value = 0; }
action end { }
ESC = 0x1B;
start = ESC "[";
fg = "38;" %is_fg;
bg = "48;" %is_bg;
reset = ("39" %reset_fg | "49" %reset_bg);
num = digit+ >tstart %number;
color256 = "5;";
color24b = "2;";
ansi = (
start %start
(
reset |
(fg|bg) color24b num %red ";" num %blue ";" num %green %color24b
) "m" %end
);
other = (any+ @out -- ESC)*;
main := (other :> ansi)**;
}%%
%% write data;
bool parse_ansi(std::wstring_view codes, sf::Color default_fg, sf::Color default_bg, WriteCB write) {
const wchar_t *start = NULL;
int cs = 0;
unsigned int value = 0;
const wchar_t *p = codes.data();
const wchar_t *pe = p + codes.size();
const wchar_t *eof = pe;
sf::Color bgcolor(default_bg);
sf::Color color(default_fg);
sf::Color &target = color;
%% write init;
%% write exec;
return p - pe == 0;
}