HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
josephg
librope
C2013–2026
josephg / librope

librope

UTF-8 rope library for C

4Distinct people
12Mentions
0Explicit recommenders
300GitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

UTF-8 rope library for C

GitHub

Where it is used

No documented product use has been verified yet.

What people are saying

No recommendation phrase was found in the indexed comments.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

Mentioned in the same Hacker News threads. That is not proof they are substitutes.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 3:56:07 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year12 dated mentions

Observed mentions: 2013-06-08 16:28:20 UTC to 2026-06-16 02:32:00 UTC.

01232013-01-01 00:00:00 UTC to 2014-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments20132014-01-01 00:00:00 UTC to 2015-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2015-01-01 00:00:00 UTC to 2016-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments20192020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 3 mentions; 0 submissions, 3 comments2022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments. Incomplete calendar period.2026*

* An incomplete calendar period is marked with an outlined bar. Its count is not directly comparable with a full period.

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20132013-01-01 00:00:00 UTC2014-01-01 00:00:00 UTC101
20142014-01-01 00:00:00 UTC2015-01-01 00:00:00 UTC000
20152015-01-01 00:00:00 UTC2016-01-01 00:00:00 UTC000
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC101
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC101
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC000
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC000
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC000
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC303
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC202
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC101
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC101
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC101
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC101

What Hacker News says

12 sources
> Until Rust has equal meta-programming support to C++ it's always going to be "slower". What metaprogramming does C++ have that rust is lacking? If you need more than traits + generics, rust also has proc macros. Proc macros are essentially portable compiler extensions. They take in a stream of symbols from the user's program at compile time and emit rust code that gets passed straight to the compiler. You lose out on syntax highlighting and they make compilation slower. But macros are essentially compile-time code gen. They work great. In rust, you can do things like JSX at compile-time without any special compiler support. (See: leptos.) > Realistically the difference doesn't matter much and if you're writing code that must be as fast as possible your writing unsafe Rust that looks a lot more like C/C++ then anything Rust. I agree that
Read the rest
the difference is small in practice. Good rust often does look a lot like C - with plain structs everywhere and lots of global-ish scoped functions. But I don't agree about unsafe. I've spent some time porting well optimised code from C to rust. I generally find I need far less unsafe code than I expected. I ported a ~500 line skip list implementation from C to rust a few years ago. I think my rust code ended up using just 2 unsafe functions. The rest of the code didn't need any unsafe at all. My skip list was a monster to debug in C because most logic bugs ended up corrupting memory. As a result, a bug in one function caused crashes in far away code. In rust, debugging was much easier. There wasn't any "spooky action at a distance". And that let me reason about the code much more easily. As a result, once I got it working I ended up adding a few more optimisations in rust that I was too overwhelmed to write in C. The rust code is now ~2-3x faster. If you're interested: https://github.com/josephg/jumprope-rs#benchmarks C code is here: https://github.com/josephg/librope
In How memory safety CVEs differ between Rust and C/C++
> When you program with totally unsafe languages, you develop more strategies than just relying on a type checker and borrow checker: RAII, "crash early", TDD, completion-compatible naming conventions, even syntax highlighting (coloring octal numbers differently)... Having written a fair bit of rust and C, I don't consider the tools for safety in C to be good enough. In C, its so easy for small mistakes to turn into CVEs. ASAN and friends help. But they're a long way from perfect. Testing helps. But in C, there's usually a fair bit of time that passes between when I make a mistake and when I discover the bug through testing. Its also so easy for bugs to hide in C in the cracks of UB. One of my clearest experiences with C and rust was a rope library I wrote several years ago. Ropes are "fancy strings". They're strings, but they support O(l
Read the rest
og n) insert & delete, at arbitrary positions. I wrote my library in pure C, implemented on top of a skip list. The code is very subtle - like, there's a lot of very careful logic. A single incorrect line of code will often cause silent data corruption or memory errors that don't show up until much later. It took about as long to properly test & debug the library as it took to write it in the first place. Debugging it was exhausting - there were a myriad of obscure edge cases that I needed fuzzing to track down. When the fuzzer found problems, going from a failing fuzzer trace to a code fix was a big job. Before I started, I had a bunch of optimisations in mind that I wanted to add to the library. But it was so exhausting getting it working at all that I never got around to most of them. Eg I wanted to make each node in the skip list into a gap buffer to reduce memcopies. But implementing that would have required significant code changes - which in turn would have meant a new round of memory bugs and debugging. I never brought myself to do it. At some point I rewrote the library in rust, with liberal use of raw pointers. I made just as many mistakes in the implementation - though the compiler caught a lot of them. The first time I ran it it segfaulted. And I thought "here we go again". But despite using raw pointers, there were only 2 unsafe functions in the whole program. A segfault in rust can only happen from unsafe code. So I took a read of that code - and lo and behold, there was my bug, plain as day. Time to fix: 2 minutes. The library never segfaulted again in all my testing. The first time I benchmarked it it was ~10% faster than the C version. I still have no idea why. It was so much easier to write that a little while later, I put the gap buffer optimisation in. Now the rust library is 2-3x faster than C. In this case, memory safety made my program easier to write. And that resulted in better performance. If anyone is curious, C / rust code is here: https://github.com/josephg/librope https://github.com/josephg/jumprope-rs > BUT. the cultural characteristics of the programmers are only one-quarter of the story. The bigger part is about company culture, and more specifically the availability of programmers. Yeah absolutely. I think this is the biggest downside of rust. Rust is really hard - and painful - to learn. It front loads all the pain. In C, you suffer while debugging. In rust, all that suffering happens while learning the language in the first place. I spent months fighting the borrow checker. And its very demotivating not being able to compile your program at all. Once you understand it, it makes sense. But I think there will always be a limited pool of programmers willing to struggle through. Even chatgpt is bad at rust. It makes all sorts of classic beginner mistakes with lifetimes, and the resulting code often won't compile. Even after pointing out the problem, chatgpt is often unable to correct lifetime bugs.
In Safe C++ proposal is not being continued
Apart from the learning experience, there is still value in a small-sized, fast TUI text editor for Linux. However, my two suggestions would be: - add Unicode support (it's the 21st century, so ∑, ®, etc. should finally work); this is not easy, but the earlier you do it the less dramatic the changes will be (check out https://github.com/unicode-org/icu/tree/main/icu4c); - don't allocate the lines individually (as you do now with malloc, having looked at the code); at least use an arena allocator, i.e. allocate larger chunks of memory and the provide your own alloc_line function that uses the larger chunks (called arenas) piecemeal. This will speed things up and reduce fragmentation. A more advanced approach would be not to use per-line buffers but to switch to rope data structures e.g. https://github.com/josephg/librope).
In Show HN: A retro terminal text editor for GNU/Linux coded in C (C-edit)
if you don't have reflinks (or some non-linux equivalent) you're going to have to load the entire file into an array when you open it anyway, even if that array isn't where you edit it the performance cost of a dumb array is being oversold here. it's true that insertion and deletion are slow in arrays, but let's put this in perspective. i'm displaying my editor on a 2-megapixel display, which is 8 megabytes of pixels because they're 32 bits per pixel. drawing a single frame of video involves the same amount of memory traffic as memmove()ing 4 megabytes of text. so until you have a few megabytes, even with a dumb array, ordinary text editing operations will easily support interactive responsivity. even things like refilling paragraphs and indenting or outdenting regions, which might involve hundreds of individual edits, is fine on eve
Read the rest
ryday-sized files. this laptop can do about 20 gigabytes a second to main memory, 10 gigabytes of memmove(), so in 16.7 milliseconds (a 60-hertz frame) it can memmove() 167 megabytes. it isn't until you get into things like search-and-replace jobs on big logfiles that you start to feel the pain the complexity of ropes is also being oversold here. as i pointed out in a comment in a subthread, you can make ropes quite complex, but https://github.com/ivanbgd/Rope-Data-Structure-C is 339 lines of code. it's probably not a real-world rope, though; it has far too much memory overhead probably the most widely used implementation of ropes is the one from the sgi stl, which is in gcc as libstdc++/ext/rope https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USER... and libstdc++/ext/ropeimpl.h https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USER..., which total 1485 lines of code, about five times larger. c++'s verbose syntax isn't doing brevity any favors here in a garbage-collected language, like the cedar language where ropes originated, most of that complexity goes away, and production-quality ropes can be only a few hundred lines of code http://www.bitsavers.org/pdf/xerox/parc/cedar/Cedar_7.0/09_C... another somewhat popular rope implementation is librope, in c https://github.com/josephg/librope which is 684 lines of code and looks to be production-quality there's an unrelated librope-ocaml in debian (and opam); it's 1029 lines of code but nothing in debian depends on it. it looks quite full-featured; the documentation says it 'has all non-deprecated operations of String' http://chris00.github.io/ocaml-rope/doc/rope/Rope/ in ur-scheme i used the simplest, dumbest kind of rope for building up output text (input was parsed into s-expressions character by character): an output text was either a string, a pair (representing the concatenation of its arguments), or nil (representing the empty string). this is very similar to erlang's io lists. the only operations supported were (constant-time) concatenation (implemented as cons) and (linear-time) flattening into a string; this took 27 lines of scheme because the subset of scheme i implemented it in was quite limited. http://canonical.org/~kragen/sw/urscheme/ finseth's book is worth reading https://www.finseth.com/craft/, tatham's notes on b-tree ropes https://www.chiark.greenend.org.uk/~sgtatham/tweak/btree.htm... are worth reading, and raph levien's notes on xi and ropes https://xi-editor.io/docs/rope_science_00.html are worth reading. chris wellons's post about gap buffers https://nullprogram.com/blog/2017/09/07/ is a little bit silly but has animations
In Text Editor: Data Structures
Yep. A few years ago I implemented a skip list based rope library in C[1], and after learning rust I eventually ported it over[2]. The rust implementation was much less code than the C version. It generated a bigger assembly but it ran 20% faster or so. (I don't know why it ran faster than the C version - this was before the noalias analysis was turned on in the compiler). Its now about 3x faster than C, thanks to some use of clever layered data structures. I could implement those optimizations in C, but I find rust easier to work with. C has advantages, but performance is a bad reason to choose C over rust. In my experience, the runtime bounds checks it adds are remarkably cheap from a performance perspective. And its more than offset by the extra optimizations the rust compiler can do thanks to the extra knowledge the compiler has about
Read the rest
your program. If my experience is anything to go by, naively porting C programs to rust would result in faster code a lot of the time. And I find it easier to optimize rust code compared to C code, thanks to generics and the (excellent) crates ecosystem. If I was optimizing for runtime speed, I'd pick rust over C every time. [1] https://github.com/josephg/librope [2] https://github.com/josephg/jumprope-rs
In The case against a C alternative
> it’s not clear if this will be a positive for native dev advocacy I've rewritten a few things in rust. Seems pretty positive to me, because you can mix some of the best optimizations and data structures you'd write in C, with much better developer ergonomics. A few years ago I wrote a rope library in C. This is a library for making very fast, arbitrary insert & delete operations in a large string. My C code was about as fast as I could make it at the time. But recently, I took a stab at porting it to Rust to see if I could improve things. Long story short, the rust version is another ~3x faster than the C version. https://crates.io/crates/jumprope (Vs C equivalent: https://github.com/josephg/librope ) The competition absolutely isn't fair. In rust, I managed to add another optimization that doesn't exist in the C code. I could add it in
Read the rest
C, but it would have been really awkward to weave in. Possible, but awkward in an already very complex bit of C. In rust it was much easier because of the language's ergonomics. In C I'm using lots of complex memory management and I don't want to add complexity in case I add memory corruption bugs. In rust, well, the optimization was entirely safe code. And as for other languages - I challenge anyone to even approach this level of performance in a non-native language. I'm processing ~30M text edit operations per second. A few years ago I tried something similar in JS and got about 100k edits per second. (300x slower) But these sort of performance results probably won't scale for a broader group of programmers. I've seen rust code run slower than equivalent javascript code because the programmers, used to having a GC, just Box<>'ed everything. And all the heap allocations killed performance. If you naively port python line-by-line to rust, you can't expect to magically get 100x the performance. Its like, if you give a top of the line Porsche to an expert driver, they can absolutely drive faster. But I'm not an expert driver, so I'll probably crash the darn thing. I'd take a simple toyota or something any day. I feel like rust is the porsche, and python is the toyota.
In Why Is C Faster Than Java (2009)
Trees seemed to work pretty well for me here! The problem with trees is usually that people don't pack enough data into each node in the tree. I implemented a skip list in C a few years ago[1]. For a lark I benchmarked its performance against the C++ SGI rope class which was shipped in the C++ header directory somewhere. My skip list was 20x faster - which was suspicious. I looked into what the SGI rope does and it turns out it was only putting one character into each leaf node in the tree it constructed. Benchmarking showed the optimal number was ~120 or so characters per leaf. Memcpy is much much faster in practice than main memory lookups. In diamond-types (benchmarked here), the internal nodes in my B-tree store 16 pointers and leaf nodes store 32 entries. With run-length encoding, all 180,000 inserted characters in this data set end
Read the rest
up in a tree with just 88 internal nodes and a depth of 3. It goes fast like this. But if you think an array based solution would work better, I'd love to see it! It would certainly need a lot less code. [1] https://github.com/josephg/librope
In Faster CRDTs: An Adventure in Optimization
> I have no idea whether that matters or even easy to measure... It is reasonably easy to measure, and the GP is about right. I've measured a crossover point of around a few hundred items too. (Though I'm sure it'll vary depending on use case and whatnot.) I made a rope data structure a few years ago in C. Its a fancy string data structure which supports inserts and deletes of characters at arbitrary offsets. (Designed for text editors). The implementation uses a skip list (which performs similarly to a b-tree). At every node we store an array of characters. To insert or delete, we traverse the structure to find the node at the requested offset, then (usually) memmove a bunch of characters at that node. Q: How large should that per-node array be? A small number would put more burden on the skip list structure and the allocator, and incur
Read the rest
more cache misses. A large number will be linearly slower because of all the time spent in memmove. Benchmarking shows the ideal number is in the ballpark of 100-200, depending on CPU and some specifics of the benchmark itself. Cache misses are extremely expensive. Storing only a single character at each node (like the SGI C++ rope structure does) makes it run several times slower. (!!) Code: https://github.com/josephg/librope This is the constant to change if you want to experiment yourself: https://github.com/josephg/librope/blob/81e1938e45561b0856d4... In my opinion, hash tables, btrees and the like in the standard library should probably swap to flat lists internally when the number of items in the collection is small. I'm surprised more libraries don't do that.
In Rust is now overall faster than C in benchmarks
I made one of those in C, using skip lists instead of trees so it wouldn't need rebalancing: https://github.com/josephg/librope It could happily do 5M random single character edits / second on my old laptop. Its wild what you can pull off with C. Much more memory efficient too (it uses about 4 pointers of overhead per 180 characters). I'd love to see a version which supported traversal using more methods though - that library needs to support searching by line as well as character count. I tried porting it to Rust a few times but unfortunately couldn't figure out how to port it without introducing indirection everywhere. Modern 'C replacement' languages don't let you do the same funky memory management tricks. (Like using a dynamically sized array at the end of a struct allocated in the same block.)
In Lessons learned from implementing a text editor related to front-end development
Finger trees are very cool. I have an efficient rope implementation in C based on skip lists here: https://github.com/josephg/librope I'm proud to say that the only bugs AFL found in my implementation were related to my (documented) lack of UTF8 validation. And my skip list implementation beats the performance of the SGI C++ STL rope implementation by about 20x while being several times smaller. (It comfortably performs in the millions of random operations/second on documents up to 1M in size, and it has a smooth logarithmic decline in performance after that). Unfortunately in C its quite awkward to generically control what aggregate information is cached at internal nodes in the tree. You need control over that to be able to efficiently implement lots of the operations you need in a normal text editor. For example converting between line
Read the rest
/character positions and offset positions. I can't just hardcode a lot of those translations into the data type because the bookkeeping is expensive and it kills cache coherence. Its a cost you only want to pay when you need it. I'm curious to try porting the skip list code to unsafe rust to see if I can add that abstraction capacity in while maintaining the current performance profile. Data structures are fun!
In Design and Implementation of a Win32 Text Editor (2005)

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.