Debugging an AI-generated editor
I've written one text editor (ke), and tried to C++ rewrites a couple of times, but always stalled out due to a lack of time. I pivoted at some point to writing a graphical editor (kge), which got so far as loading a file in an imgui window without any editing ability. I've been keeping notes and trying to work out what needs to be done for an improved editor in the meantime.
Well, two things converged:
- I got ke working in termios, but wanted to start over in C++ with ncurses.
- I got stuck in all-day customer support calls for the better part of a month.
I pay for a Jetbrains "all tools" license, and that includes their AI plan, so I figured why not feed the C sources and my notes to AI piecemeal to see if I can get it to write an editor?
TL;DR: I did. It's about 12k lines of C++, of which I have touched less than a hundred.
One thing I kept running into is the cursor not being set right when
clicking in the GUI. This had been working in master, but I was
working on a font registry and somewhere in the process, it broke. I
didn't really want to debug graphics code though, so I set about doing
it with the AI. Notably, I hand wrote the font registry. The registry
takes TTF files built into a header with imgui's binary to compressed
c tool and some custom python tooling, then use that to create and
register fonts.
Well, because I copy pasted the basic pattern for doing this to repeat it for all the fonts bundled, I missed setting the correct size information for one of the fonts. I spent about an hour trying to get the AI to figure it out, and after some initial going around in circles I decided to switch from GPT-5 (the default) to the much more expensive Claude 4.5 Opus.
After about a half hour (the better part of an episode of Silo, I figured it out. As soon as I fixed that size mismatch, everything went back to working.
I have next to no experience with writing GUIs, so this was a useful learning experience. I then asked Junie to write up its POV, mostly to look at how it approached the debugging.
The concluding parts are... spot on, actually.
I've been pretty negative about agentic coding and LLMs, but this has been fun.
Junie's write up
The Hunt for a Phantom Font Bug: A Debugging Journey in kte
December 2, 2025
What started as a mysterious GUI glitch in a text editor led me down a rabbit hole of display metrics, HiDPI scaling suspicions, and ultimately revealed a subtle one-line copy-paste error hiding in plain sight.
The Symptoms
The user reported three puzzling behaviors in kge (Kyle's Graphical Editor):
- Click misalignment: Clicking on row 30, column 29 would land the cursor at row 36, column 22
- Page down overshoot: From position 1,1 with 31 visible lines, page down jumped to row 38 instead of row 32
- Display not refreshing: Opening a file with
kge +41 Buffer.ccshowed the status bar at line 41, but the display stayed at line 1
The Initial Investigation
My first instinct was to examine the dimension calculation and click
handling code in GUIRenderer.cc. The debug values told an interesting
story:
[DEBUG DIMS] vis_rows=37 child_h=1049.0 row_h=28.0 setting Rows=38
[DEBUG CLICK] mp.y=1002.0 line0_screen_y=6.0 rel_y=996.0 row_h=28.0 dy_rows=35
The editor thought it had 37 visible rows, but the user could only see 31. This 6-row discrepancy explained everything: clicks were being mapped to the wrong row, and page down was jumping too far.
Following the Wrong Trail
I spent considerable effort investigating what seemed like obvious suspects:
HiDPI/Retina Scaling?
The user was on a Retina display with
FramebufferScale=(2.00,2.00). I checked if coordinates were being
double-counted somewhere. They weren't.
Title Bar Confusion?
On macOS, the window has a title bar. Perhaps SDL's reported window size included decorations that ImGui didn't account for? I added extensive logging:
[DEBUG VIEWPORT] vp->Size=(1800.0,1097.0)
[DEBUG PRE-CHILD] avail.y=1085.0 frame_h=36.0 child_visible_h=1049.0
The numbers were consistent—no hidden title bar issue.
Content Region vs Clip Rect?
I tried multiple ImGui APIs: GetWindowContentRegionMax(),
GetWindowHeight(), InnerClipRect. All returned the same 1049
pixels.
Manual Scroll Calculation?
I attempted to compute visible height from scroll extents: visible_h
= total_content_h - scroll_max_y. This produced negative numbers and
broke everything worse.
The Breakthrough
After many iterations, the user dropped a crucial hint:
"Also note this is working on master, and something with the new font handling appears to have broken it."
And then the revelation:
"The error appears now to be an issue with the expanded font I was using (iosevkaex). When I revert back to other fonts (brassmono, brassmonocode, iosevka, go), everything works fine."
A font-specific bug! This completely reframed the problem.
Finding the Root Cause
I examined FontRegistry.cc where fonts are registered:
FontRegistry::Instance().Register(std::make_unique<Font>(
"iosevkaex",
const_cast<unsigned int *>(IosevkaExtended::DefaultFontRegularCompressedData),
BrassMono::DefaultFontRegularCompressedSize // <-- BUG!
));
There it was. A classic copy-paste error: the iosevkaex font was
being registered with IosevkaExtended's data but BrassMono's
size. This caused ImGui to load the font with incorrect metrics,
resulting in a mismatch between:
- What ImGui thought the row height was (28 pixels based on corrupted metrics)
- What was actually rendered on screen (~33.7 pixels based on user's 31 visible rows in 1044 pixels)
The Fix
One line:
// Before (wrong):
BrassMono::DefaultFontRegularCompressedSize
// After (correct):
IosevkaExtended::DefaultFontRegularCompressedSize
Lessons Learned
-
Trust the user's observations: When the user said "it works with other fonts," that was the key clue. I should have pivoted to font investigation earlier.
-
Copy-paste errors are insidious: The code looked correct at a glance. The pattern of
Namespace::Data, Namespace::Sizewas followed everywhere else. Only iosevkaex had the wrong namespace for the size. -
Debug output can mislead: All my metrics were internally consistent—ImGui genuinely believed row_h was 28 pixels. The bug was upstream in how the font was loaded.
-
When stuck, diff against working code: The
difffile showing changes from master could have revealed the font registry changes earlier. -
Verify every registration: When adding fonts to a registry, each entry should be validated independently. A simple test rendering each font and checking basic metrics would have caught this.
The Irony
The most sophisticated debugging---HiDPI analysis, viewport calculations, clip rect investigations---all led nowhere. The bug was a typo in a registration call that I could have found by careful code review in the first place.
But that's debugging: sometimes you need to eliminate the complex possibilities before the simple answer reveals itself.
- Total debugging time: ~5 AI interaction credits (editor's note: I get 35/mo with Jetbrains; the Claude 4.5 Opus model is about 2-5x more expensive)
- Lines of debug code added then removed: ~50
- Lines changed in final fix: 1