I started building Icarus in 2024 as a simple text editor, and honestly I never thought it could become anything more than that... (Spoiler: it did, over the course of the last two years I implemented what I will go through in this small article).
The motivation behind Icarus has always been my obsession of control over (almost) everything I run on my machine (I think it started with Casey's "Thirty Million Lines Problem" talk). I wanted an editor I could entirely keep in my head.
The general architecture is very direct. The app runs an event loop that polls input, mutates the editor state, renders from state and repeats. Most long-lived state hangs off one central editor object that owns the active tab, viewports, text buffers, syntax highlighter, intellisense, project model, console, and debugger.
The text engine is intentionally plain. Each line is a dynamic char array, and inserts/deletes rely on memmove. It’s not the best approach ever, but (in my experience) it keeps the code understandable and integrates in a nice way with the other line based features I've written (diagnostics, syntax caching, and viewport math).
Rendering is the classic immediate mode style, with the little quirk being that there are dirty flags and dirty line ranges, and frame submission is skipped when nothing changed. That made a lot difference for responsiveness.
Syntax highlighting is token-based and incremental. C and C++ (up to the latest MSVC compliant standards) keywords, types, and common function identifiers go through hash lookups, then line-level cache entries track things like tokenization and multiline comment state.
Then there's this whole Project and "workspace persistence" system that turned out to matter a lot for my daily usage. The project file stores build/run config and tracked files, along with session-like state such as open tabs, split settings, debugger panel toggles, and watch expressions. Reopening a project in milliseconds and starting work just where I left it actually makes it feel like a full development environment instead of a text editor.
Intellisense is intentionally pragmatic. I’m not trying to replicate the full complexity of modern language servers YET. The system uses symbol tables and recursively scans files skipping sensible dirs. It’s heuristic heavy, but it’s fast and it’s mine (which, as stated, to me is what matters the most out of all of this =) ).
The integrated console is one of the first systems I built back in 2024 but I'm still expanding it. Commands are launched with CreateProcess and piped output goes into it. From the latest version build output gets classified into errors and warnings and those diagnostics are parsed and normalized with project paths so the editor can go to those issues when clicking on them.
The debugger is the subsystem I’m the proudest of. It runs a native debug event loop with DbgHelp symbols. For breakpoints source locations are resolved to memory addresses, INT3 interrupt is inserted, original bytes are restored on hit. Step into, over, and out all run through this system. When execution pauses, the debugger captures registers, stack frames, locals, memory windows, disassembly context, and watch expressions from live process state.
There’s also a built-in profiler panel tied to the debugger session. It samples process CPU, memory, IO, thread count, handle count, and keeps ring-buffer history for graphing. it is NOT intended to be a replacement for heavyweight and proprietary profilers, but it is kind of what I want in 99.9% of the cases when iterating quickly.
The project is out on itch.io: https://giovannicarlino04.itch.io/icarus
I also started a youtube channel going over the editor's updates and features: https://www.youtube.com/@GiovanniCarlino-z1j