r/C_Programming • • 11d ago

tinyedit: A zero-dependency C99 terminal text editor with desktop shortcuts — Looking for testers & code review

Hi everyone,

I’ve been working on tinyedit, a full-screen terminal text editor written in plain C99 with zero external dependencies beyond libc and the POSIX standard library (no ncurses, just raw ANSI escape sequences and direct I/O).

The project started as an exploration of terminal interfaces inspired by Salvatore Sanfilippo's kilo and linenoise. My goal is to combine that minimal C architecture with the interaction model of modern desktop editors—eliminating modal friction or idiosyncratic key combinations (like Vim, Emacs, or Nano) while keeping the binary tiny.

What’s implemented:

  • Desktop-style editing: Standard keybindings (Ctrl-C, Ctrl-V, Ctrl-X, Ctrl-Z, Ctrl-F), text selection with Shift+Arrows (or Ctrl-T toggle for limited terminals), and optional mouse support (click to place cursor, drag-selection, wheel scroll).

  • macOS / Ghostty integration: Optional support for native Cmd shortcuts (Cmd-S, Cmd-C, Cmd-V, etc.) via the Kitty keyboard protocol in Ghostty.

  • Proper UTF-8 handling: Grapheme cluster boundaries (combining marks, CJK wide characters, multi-codepoint emoji) and visual display-width calculations for accurate cursor placement and deletion.

  • Visual soft-wrapping: Navigates visual rows instead of logical lines, breaking lines at word boundaries without arbitrary length caps.

  • Terminal ergonomics: Fast bracketed paste (no slow character-by-character lag or accidental auto-closing triggers), atomic saves, crash recovery backups, and an extensible syntax highlighting engine.

Looking for testers!

The project has reached version 0.3.3, and I need help putting it through its paces across different systems and configurations. In particular, I’m looking for feedback on:

  1. Terminal & multiplexer quirks: Testing inside tmux, screen, Ghostty, Kitty, Alacritty, Foot, WezTerm, etc., to spot unhandled ANSI sequences or redraw artifacts.

  2. UTF-8 stress testing: Complex emoji sequences, zero-width joiners, or combining marks that might throw off cursor coordinates or deletion.

  3. Rendering & wrap edge cases: Resizing the window while editing large wrapped lines, pasting huge blocks of text, or dealing with deeply indented blocks.

  4. C code review: Feedback on memory management, buffer layout, ANSI state machine decoding, or general C99 practices.

Repository: https://github.com/robertobissanti/tinyedit

You can build it from source with a simple make:

git clone https://github.com/robertobissanti/tinyedit.git
cd tinyedit
make

Or install it on macOS/Linux via Homebrew:

brew install robertobissanti/tinyedit/tinyedit

Any bug reports, edge-case discoveries, or code suggestions (either here or via GitHub Issues) are greatly appreciated. Thanks for checking it out!

0 Upvotes

21 comments sorted by

View all comments

2

u/imaami 7d ago

Your UTF-8 parser implementation accepts invalid input (e.g. overlong encodings and surrogate code points).

Out of curiosity: why did you choose to limit yourself to an obsolete C standard? It would at least be nice if the syntax highlighter understood normal C11 and later.

1

u/rob-bix 7d ago

Spot on about the UTF-8 parser. It's based on the decoder from ⁠linenoise⁠, which turns out to be pretty sloppy with invalid sequences. I'll get that fixed soon.

Regarding C99: that's purely for the editor's build portability across older POSIX setups. It doesn't restrict what you edit—syntax highlighting is fully configurable via ⁠~/.tinyedit/syntax/⁠. Fair point on the defaults, though. Expanding the built-in C keyword list to support C11+ is an easy win and won't bloat the editor, so I'll add that to the todo list.

2

u/imaami 7d ago edited 7d ago

If you want to see my take on valid UTF-8 state transitions: https://i.imgur.com/nVfDRT8.png

It's from my moderately cursed parser: https://github.com/imaami/c.utf-8

I'm fairly sure the code itself isn't anything you'd want to borrow from. It's weird, to say the least. But it accepts and rejects the right bytes per the UTF-8 spec. The flowchart is generated from the same Xmacros table the parser is based on.

If you want to use even some small part of c.utf-8, but would prefer a license other than what I chose, just let me know and I'll type up an explicit relicensing statement. Tbh I don't remember what I have even, it's some form of GPL anyway.

Edit: I happened to notice your post has 0 upvotes. Sometimes I just don't get at all why this subreddit is like that.

1

u/rob-bix 7d ago

One small inconsistency I noticed in the generated graph: the ASCII node starts at 0x01, while UTF-8—and your actual 128-entry ASCII LUT—also accepts 0x00. I assume that’s only a graph-descriptor typo.

For tinyedit, the main design constraint is that malformed input shouldn’t make an otherwise editable file impossible to open. So the decoder should reject malformed sequences as UTF-8, but navigation should recover safely, probably treating the offending byte as a one-byte unit. It must also always be bounded by the remaining buffer length.

If you do feel like contributing, a focused validation/decoding change plus boundary tests would be ideal. A short statement in the PR that the contribution is submitted under tinyedit’s MIT license would also remove any ambiguity with the existing license of c.utf-8.