Skip to content

Commit 4745b2b

Browse files
committed
fix(gfx): honour newlines that land at column 0
basic-gfx swallowed a CR/LF reaching col 0 (guard if(gfx_x!=0)), so leading \n, \n\n, and bare-PRINT spacing produced no blank line, unlike the terminal interpreter and the transpiler C runtime which honour every newline. Same .bas spaced differently under gfx vs PET/native-C. Add gfx_just_wrapped: set only when an eager 40-col wrap left the cursor at col 0 with no glyph since; cleared by glyph/newline/HOME/CLS. CR/LF now advances unless that flag is set, so a full-line wrap still absorbs its trailing newline while every other col-0 newline advances. gfx now matches terminal + compiled targets. 40-col eager wrap unchanged.
1 parent d7ed006 commit 4745b2b

2 files changed

Lines changed: 44 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
11
## Changelog
22

3+
### gfx PRINT: stop swallowing newlines that land at column 0 (2026-06-22)
4+
5+
`basic-gfx` (and the raylib/canvas WASM builds, which share
6+
`gfx_apply_control_code`) treated a `CR`/`LF` reaching column 0 as a no-op. The
7+
guard was `if (gfx_x != 0) gfx_newline();`, meant to absorb the duplicate
8+
newline a full 40-column line produces (the eager wrap already moved the cursor
9+
down, so a trailing `\n` would double-space). But `gfx_x == 0` can't tell that
10+
wrap case from a `\n` that legitimately starts a blank line — a leading `\n` in
11+
a literal, an embedded `\n\n`, or a `\n` right after a prior explicit newline.
12+
All of those were eaten, so `print "A\n\nB"` rendered `A` / `B` with no gap.
13+
14+
The terminal interpreter (`OUTC('\n')`) and the transpiler C runtime
15+
(`rgc_pstr` → unconditional `rgc_nl`) both honour every `\n`, so the same source
16+
gained blank lines on PET / native-C / terminal targets but lost them under
17+
gfx — e.g. Space Battles' short+long range scan packed tight in `basic-gfx`
18+
while the compiled builds spaced it out.
19+
20+
Fix: a `gfx_just_wrapped` flag, set only when an eager auto-wrap left the cursor
21+
at column 0 with no glyph placed since, cleared by any glyph, explicit newline,
22+
HOME, or CLS. The CR/LF handler now advances unless that flag is set, so a
23+
full-line wrap still absorbs its trailing newline while every other column-0
24+
`\n`/`\r` advances — matching the terminal and transpiler runtimes. gfx output
25+
now lines up with PET / native-C for the same `.bas`. The 40-column eager-wrap
26+
behaviour (vs terminal's 80 / `-nowrap`) is unchanged; keep portable PRINT lines
27+
≤ 40 chars.
28+
329
### Transpiler backends extracted to a private repo (2026-06-17)
430

531
The two source-to-source transpiler backends left this repo. The **C** backend

basic.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2772,6 +2772,12 @@ static inline int gfx_cols(void) {
27722772
}
27732773
static int gfx_x = 0;
27742774
static int gfx_y = 0;
2775+
/* Set only when an eager auto-wrap (a glyph filling the last column) left the
2776+
* cursor at col 0 with no glyph placed since. Lets a CR/LF that immediately
2777+
* follows a full line absorb into the wrap instead of double-spacing, while a
2778+
* \n/\r arriving at col 0 by any other means (leading \n, \n\n, a prior
2779+
* explicit newline) still advances — matching terminal + transpiler runtimes. */
2780+
static int gfx_just_wrapped = 0;
27752781
static uint8_t gfx_fg = 14; /* default light blue */
27762782
static uint8_t gfx_bg = 6; /* default blue background */
27772783
static int gfx_reverse = 0;
@@ -2851,6 +2857,7 @@ static void gfx_scroll_up(void)
28512857

28522858
static void gfx_newline(void)
28532859
{
2860+
gfx_just_wrapped = 0;
28542861
gfx_x = 0;
28552862
gfx_y++;
28562863
if (gfx_y >= GFX_ROWS) {
@@ -2905,6 +2912,7 @@ static void gfx_clear_screen(void)
29052912
gfx_x = 0;
29062913
gfx_y = 0;
29072914
print_col = 0;
2915+
gfx_just_wrapped = 0;
29082916
}
29092917

29102918
static int gfx_apply_control_code(unsigned char code)
@@ -2928,14 +2936,18 @@ static int gfx_apply_control_code(unsigned char code)
29282936
return 1;
29292937
case 13: /* CR */
29302938
case 10: /* LF */
2931-
/* Avoid double newline: gfx_put_byte already wraps at col 40, so when
2932-
* the viewer sends CR after wrapping, we're already at col 0. */
2933-
if (gfx_x != 0) gfx_newline();
2939+
/* Absorb a CR/LF that lands right after an eager wrap of a full line
2940+
* (gfx_put_byte already advanced past col 40) so it doesn't double-
2941+
* space. A \n/\r reaching col 0 any other way still advances, matching
2942+
* the terminal and transpiler-C runtimes (leading \n, \n\n, etc.). */
2943+
if (gfx_x != 0 || !gfx_just_wrapped) gfx_newline();
2944+
gfx_just_wrapped = 0;
29342945
return 1;
29352946
case 19: /* HOME */
29362947
gfx_x = 0;
29372948
gfx_y = 0;
29382949
print_col = 0;
2950+
gfx_just_wrapped = 0;
29392951
return 1;
29402952
case 147: /* CLR */
29412953
gfx_clear_screen();
@@ -3183,9 +3195,11 @@ static void gfx_put_byte(unsigned char b)
31833195

31843196
gfx_x++;
31853197
if (gfx_x >= gfx_cols()) {
3186-
gfx_newline();
3198+
gfx_newline(); /* clears gfx_just_wrapped */
3199+
gfx_just_wrapped = 1; /* this newline came from a full line */
31873200
} else {
31883201
print_col = gfx_x;
3202+
gfx_just_wrapped = 0;
31893203
}
31903204
}
31913205

0 commit comments

Comments
 (0)