mirror of
https://github.com/ascii-boxes/boxes.git
synced 2025-01-19 04:18:12 +01:00
Do not count ANSI sequences towards line length
This allows the usage of boxes with basic ANSI SGR colors and formating. The change was made as a quick hack for myself, so it ended up not super-clean. The problem here is that before, boxes only had a concept of line->len that would store both the width of the line and the number of bytes contained since they were assumed to be the same. Now, there are visible and invisble characters - sometimes the code needs to work with the visible line length and sometimes with the byte count. Because of that, at this point the code could use some refactoring to make it a little more obvious which line length (visible or bytes) is being used at a given time. So, if anybody feels like cleaning up the mess I introduced - that would be appreciated. Works with `lolcat -f` Tested on: + debian: xterm, gnome-terminal, terminator, locally and via ssh + win64/cygwin: compiled and tested locally and via ssh + win64/putty: connected to debian server Fixes ascii-boxes/boxes#65
This commit is contained in:
parent
7ef0b3517f
commit
2356251a27
55
src/boxes.c
55
src/boxes.c
@ -1278,9 +1278,13 @@ static int apply_substitutions (const int mode)
|
|||||||
perror (PROJECT);
|
perror (PROJECT);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input.lines[k].vischar += buf_len - input.lines[k].len;
|
||||||
input.lines[k].len = buf_len;
|
input.lines[k].len = buf_len;
|
||||||
if (input.lines[k].len > input.maxline)
|
|
||||||
input.maxline = input.lines[k].len;
|
if (input.lines[k].vischar > input.maxline)
|
||||||
|
input.maxline = input.lines[k].vischar;
|
||||||
|
|
||||||
#ifdef REGEXP_DEBUG
|
#ifdef REGEXP_DEBUG
|
||||||
fprintf (stderr, "input.lines[%d] == {%d, \"%s\"}\n", k,
|
fprintf (stderr, "input.lines[%d] == {%d, \"%s\"}\n", k,
|
||||||
input.lines[k].len, input.lines[k].text);
|
input.lines[k].len, input.lines[k].text);
|
||||||
@ -1350,6 +1354,9 @@ static int read_all_input (const int use_stdin)
|
|||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
char buf[LINE_MAX+2]; /* input buffer */
|
char buf[LINE_MAX+2]; /* input buffer */
|
||||||
|
char c;
|
||||||
|
size_t invis; /* counts invisible characters */
|
||||||
|
int ansipos; /* progression of ansi sequence */
|
||||||
size_t input_size = 0; /* number of elements allocated */
|
size_t input_size = 0; /* number of elements allocated */
|
||||||
line_t *tmp = NULL;
|
line_t *tmp = NULL;
|
||||||
char *temp = NULL; /* string resulting from tab exp. */
|
char *temp = NULL; /* string resulting from tab exp. */
|
||||||
@ -1410,11 +1417,51 @@ static int read_all_input (const int use_stdin)
|
|||||||
input.lines[input.anz_lines].text = (char *) strdup (buf);
|
input.lines[input.anz_lines].text = (char *) strdup (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find ANSI CSI/ESC sequences
|
||||||
|
*/
|
||||||
|
invis = 0;
|
||||||
|
ansipos = 0;
|
||||||
|
for (i=0; i<input.lines[input.anz_lines].len; ++i) {
|
||||||
|
c = input.lines[input.anz_lines].text[i];
|
||||||
|
if (ansipos == 0 && c == 0x1b){
|
||||||
|
/* Found an ESC char, count it as invisible and move 1 forward in the
|
||||||
|
* detection of CSI sequences */
|
||||||
|
ansipos++;
|
||||||
|
invis++;
|
||||||
|
} else if (ansipos == 1 && c == '[') {
|
||||||
|
/* Found '[' char after ESC. A CSI sequence has started. */
|
||||||
|
ansipos++;
|
||||||
|
invis++;
|
||||||
|
} else if (ansipos == 1 && c >= 0x40 && c <= 0x5f) {
|
||||||
|
/* Found a byte designating the end of a two-byte
|
||||||
|
* escape sequence */
|
||||||
|
invis++;
|
||||||
|
ansipos = 0;
|
||||||
|
} else if (ansipos == 2) {
|
||||||
|
/* Inside CSI sequence - Keep counting bytes as invisible */
|
||||||
|
invis++;
|
||||||
|
|
||||||
|
/* A char between 0x40 and 0x7e signals the end of an CSI or escape sequence */
|
||||||
|
if (c >= 0x40 && c <= 0x7e)
|
||||||
|
ansipos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the count of invisible chars and visible chars.
|
||||||
|
* I'm happy about suggestions for a more elegant handling
|
||||||
|
* of this and the use of .invis and .vischar (and .len)
|
||||||
|
* in the other functions.
|
||||||
|
*/
|
||||||
|
input.lines[input.anz_lines].invis = invis;
|
||||||
|
input.lines[input.anz_lines].vischar = input.lines[input.anz_lines].len - invis;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update length of longest line
|
* Update length of longest line
|
||||||
*/
|
*/
|
||||||
if (input.lines[input.anz_lines].len > input.maxline)
|
if (input.lines[input.anz_lines].vischar > input.maxline) {
|
||||||
input.maxline = input.lines[input.anz_lines].len;
|
input.maxline = input.lines[input.anz_lines].vischar;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* next please
|
* next please
|
||||||
|
@ -147,6 +147,8 @@ extern opt_t opt;
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
size_t len; /* length of text in characters */
|
size_t len; /* length of text in characters */
|
||||||
char *text; /* line content, tabs expanded */
|
char *text; /* line content, tabs expanded */
|
||||||
|
size_t invis; /* number of characters part of an ansi sequence */
|
||||||
|
size_t vischar; /* number of normal printable characters */
|
||||||
size_t *tabpos; /* tab positions in expanded work strings */
|
size_t *tabpos; /* tab positions in expanded work strings */
|
||||||
size_t tabpos_len; /* number of tabs in a line */
|
size_t tabpos_len; /* number of tabs in a line */
|
||||||
size_t num_leading_blanks; /* number of spaces at the start of the line after justification */
|
size_t num_leading_blanks; /* number of spaces at the start of the line after justification */
|
||||||
|
@ -709,30 +709,32 @@ static int justify_line (line_t *line, int skew)
|
|||||||
case 'l':
|
case 'l':
|
||||||
if (opt.design->indentmode == 't') {
|
if (opt.design->indentmode == 't') {
|
||||||
memmove (line->text+input.indent, p, newlen+1);
|
memmove (line->text+input.indent, p, newlen+1);
|
||||||
line->len = newlen + input.indent;
|
line->vischar = newlen + input.indent - line->invis;
|
||||||
|
line->len = line->vischar;
|
||||||
line->num_leading_blanks = input.indent;
|
line->num_leading_blanks = input.indent;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
memmove (line->text, p, newlen+1);
|
memmove (line->text, p, newlen+1);
|
||||||
line->len = newlen;
|
line->vischar = newlen - line->invis;
|
||||||
|
line->len = line->vischar;
|
||||||
line->num_leading_blanks = 0;
|
line->num_leading_blanks = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
if (opt.design->indentmode == 't') {
|
if (opt.design->indentmode == 't') {
|
||||||
shift = (input.maxline-input.indent-newlen) / 2 + input.indent;
|
shift = (input.maxline - input.indent - newlen + line->invis) / 2 + input.indent;
|
||||||
skew -= input.indent;
|
skew -= input.indent;
|
||||||
if ((input.maxline-input.indent-newlen) % 2 && skew == 1)
|
if ((input.maxline-input.indent - newlen) % 2 && skew == 1)
|
||||||
++shift;
|
++shift;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
shift = (input.maxline - newlen) / 2;
|
shift = (input.maxline - newlen + line->invis) / 2;
|
||||||
if ((input.maxline - newlen) % 2 && skew == 1)
|
if ((input.maxline - newlen +line->invis) % 2 && skew == 1)
|
||||||
++shift;
|
++shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
newtext = (char *) calloc (shift + newlen + 1, sizeof(char));
|
newtext = (char *) calloc (shift + newlen + line->invis + 1, sizeof(char));
|
||||||
if (newtext == NULL) {
|
if (newtext == NULL) {
|
||||||
perror (PROJECT);
|
perror (PROJECT);
|
||||||
return 2;
|
return 2;
|
||||||
@ -750,18 +752,19 @@ static int justify_line (line_t *line, int skew)
|
|||||||
newlen, shift, spaces);
|
newlen, shift, spaces);
|
||||||
#endif
|
#endif
|
||||||
strncpy (newtext, spaces, shift);
|
strncpy (newtext, spaces, shift);
|
||||||
strncat (newtext, p, newlen);
|
strncat (newtext, p, newlen+line->invis);
|
||||||
newtext[shift+newlen] = '\0';
|
newtext[shift+newlen+line->invis] = '\0';
|
||||||
BFREE (spaces);
|
BFREE (spaces);
|
||||||
BFREE (line->text);
|
BFREE (line->text);
|
||||||
line->text = newtext;
|
line->text = newtext;
|
||||||
line->len = shift + newlen;
|
line->len = shift + newlen - line->invis;
|
||||||
|
line->vischar = line->len;
|
||||||
line->num_leading_blanks = shift;
|
line->num_leading_blanks = shift;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r':
|
case 'r':
|
||||||
shift = input.maxline - newlen;
|
shift = input.maxline - (newlen - line->invis);
|
||||||
newtext = (char *) calloc (input.maxline+1, sizeof(char));
|
newtext = (char *) calloc (input.maxline+1000, sizeof(char));
|
||||||
if (newtext == NULL) {
|
if (newtext == NULL) {
|
||||||
perror (PROJECT);
|
perror (PROJECT);
|
||||||
return 2;
|
return 2;
|
||||||
@ -776,10 +779,11 @@ static int justify_line (line_t *line, int skew)
|
|||||||
spaces[shift] = '\0';
|
spaces[shift] = '\0';
|
||||||
strncpy (newtext, spaces, shift);
|
strncpy (newtext, spaces, shift);
|
||||||
strncat (newtext, p, newlen);
|
strncat (newtext, p, newlen);
|
||||||
newtext[input.maxline] = '\0';
|
newtext[input.maxline+line->invis] = '\0';
|
||||||
BFREE (spaces);
|
BFREE (spaces);
|
||||||
BFREE (line->text);
|
BFREE (line->text);
|
||||||
line->text = newtext;
|
line->text = newtext;
|
||||||
|
line->vischar = input.maxline;
|
||||||
line->len = input.maxline;
|
line->len = input.maxline;
|
||||||
line->num_leading_blanks = shift;
|
line->num_leading_blanks = shift;
|
||||||
break;
|
break;
|
||||||
@ -796,8 +800,9 @@ static int justify_line (line_t *line, int skew)
|
|||||||
size_t k;
|
size_t k;
|
||||||
input.maxline = 0;
|
input.maxline = 0;
|
||||||
for (k=0; k<input.anz_lines; ++k) {
|
for (k=0; k<input.anz_lines; ++k) {
|
||||||
if (input.lines[k].len > input.maxline)
|
if (input.lines[k].len > input.maxline) {
|
||||||
input.maxline = input.lines[k].len;
|
input.maxline = input.lines[k].len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1016,7 +1021,7 @@ int output_box (const sentry_t *thebox)
|
|||||||
rc = justify_line (input.lines+ti, hpr-hpl);
|
rc = justify_line (input.lines+ti, hpr-hpl);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
r = input.maxline - input.lines[ti].len;
|
r = input.maxline - input.lines[ti].vischar;
|
||||||
trailspc[r] = '\0';
|
trailspc[r] = '\0';
|
||||||
restored_indent = tabbify_indent (ti, indentspc, indentspclen);
|
restored_indent = tabbify_indent (ti, indentspc, indentspclen);
|
||||||
if (input.lines[ti].num_leading_blanks == SIZE_MAX) {
|
if (input.lines[ti].num_leading_blanks == SIZE_MAX) {
|
||||||
|
@ -805,13 +805,13 @@ int remove_box()
|
|||||||
input.maxline += opt.design->shape[NE].width;
|
input.maxline += opt.design->shape[NE].width;
|
||||||
for (j=0; j<input.anz_lines; ++j) {
|
for (j=0; j<input.anz_lines; ++j) {
|
||||||
input.lines[j].text = (char *)
|
input.lines[j].text = (char *)
|
||||||
realloc (input.lines[j].text, input.maxline+1);
|
realloc (input.lines[j].text, input.maxline+input.lines[j].invis+1);
|
||||||
if (input.lines[j].text == NULL) {
|
if (input.lines[j].text == NULL) {
|
||||||
perror (PROJECT);
|
perror (PROJECT);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
memset (input.lines[j].text + input.lines[j].len, ' ',
|
memset (input.lines[j].text + input.lines[j].len, ' ',
|
||||||
input.maxline - input.lines[j].len);
|
input.maxline - input.lines[j].len + input.lines[j].invis);
|
||||||
input.lines[j].text[input.maxline] = '\0';
|
input.lines[j].text[input.maxline] = '\0';
|
||||||
input.lines[j].len = input.maxline;
|
input.lines[j].len = input.maxline;
|
||||||
}
|
}
|
||||||
@ -983,8 +983,9 @@ int remove_box()
|
|||||||
}
|
}
|
||||||
input.maxline = 0;
|
input.maxline = 0;
|
||||||
for (j=0; j<input.anz_lines; ++j) {
|
for (j=0; j<input.anz_lines; ++j) {
|
||||||
if (input.lines[j].len > input.maxline)
|
if (input.lines[j].len - input.lines[j].invis > input.maxline) {
|
||||||
input.maxline = input.lines[j].len;
|
input.maxline = input.lines[j].len - input.lines[j].invis;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
memset (input.lines + input.anz_lines, 0,
|
memset (input.lines + input.anz_lines, 0,
|
||||||
(BMAX (textstart - boxstart, 0) + BMAX (boxend - textend, 0)) *
|
(BMAX (textstart - boxstart, 0) + BMAX (boxend - textend, 0)) *
|
||||||
|
Loading…
Reference in New Issue
Block a user