Linked lists are out of the question, as you need to go from link to link making accessing characters and/or lines slower than using an array. So, dynamic arrays I think are better (even if you have to reallocate or move around stuff - but this can be mitigated in some of the options below).
This is primarily a source code editor and a line-based editor, so having the text split into lines I think is ideal
Currently, the data structure is a dynamic array of lines, each line pointing to a dynamic array of characters.
Some ways this could be improved:
Use a gap buffer for the dynamic array of lines
This will allow quicker insertion of lines without having to move (memmove or memcpy) as many lines around
I'm unsure if it would be worth it to also use a gap buffer for the characters dynamic array of each line.
Current Potential Problems:
A line with many many lines may crash the program due to using too much memory. This is from two things:
The full file is loaded into memory. If you're trying to open a file bigger than the amount of RAM you currently have available, you'll have problems. Could be fixed by detecting how big a file is and only loading part of it, then swapping out "parts" when you get to the edge of one "part".
Each line has it's own data that stores the capacity and length of the character buffer rather than this being for the entire file. This means each line has two integers rather than just the buffer (file) having two integers.
Modifying a very very long line may be slow
This could potentially be mitigated by using a gap buffer for each line, but not sure if it's worth it to do this for a code editor because it's unlikely a code file will have very very long lines.
Gap Buffers aren't very optimized with multiple cursors. Since this is a line editor that's not visual - like Emacs, Vim, modern editors, etc. - I may not need to implement this. If I do, I'll have to think about how it would even work with the type of editor this is first. This article shows how text editors that use gap buffers make multiple cursors work: Gap Buffers Are Not Optimized for Multiple Cursors
Something to note, the way lines are implemented (each line has it's own buffer) will help with multiple cursors that are on different lines.
Currently, the data structure is a dynamic array of lines, each line pointing to a dynamic array of characters.
Some ways this could be improved:
Current Potential Problems: