Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to implement a buffer for a text edit control?

Tags:

c++

winapi

So i am making a custom edit control. In order to keep track of the contents of the edit control, I'm using a dynamically allocated char array.

  • Now, I know that I need to insert in the middle of the array in certain situations, such as when the user clicks on a particular point. So, I was thinking, instead of a character array, I may use std::vector, so i would be able to use the .insert function, and also wouldn't have to care much about the memory management.
  • I was also thinking maybe to directly store the input stream into an array/vector of words(Without keeping a continuous buffer), since my whole purpose with this is to implement syntax highlighting.

Which would be a better approach to go about things? And why?

like image 977
devjeetroy Avatar asked Nov 12 '11 06:11

devjeetroy


People also ask

What is a buffer in text editor?

A buffer is the basic unit of text being edited. It can be any size, from zero characters to the largest item that can be manipulated on the computer system. This limit on size is usually set by such factors as address space, amount of real and/or virtual memory, and mass storage capacity.

What data structure is appropriate for the edit buffer and why?

Gap Buffer is a data structure used for editing and storing text in an efficient manner that is being currently edited. It is also similar to an array but a gap is introduced in the array for handling multiple changes at the cursor.

What is gap buffer data structure?

The gap buffer data structure is commonly used by text editors for storing the files that are currently being edited. The data structure is simply an array that stores the contents of a file plus some extra empty space. This empty space is called the gap.


4 Answers

For a text buffer with today computers you can indeed just use a single contiguous buffer (e.g. a vector) because CPUs are fast enough to make insertion time (an o(n) operation with this naive approach) still a viable option.

In the past when computers were thousands times slower a common simple approach was instead to keep the text in a buffer but with an "hole" corresponding to the cursor position, to make insertion an o(1) operation and moving chars from one side of the hole to the other when cursor was moving in the text (basically making cursor movement an o(k) operation where k is the number of skipped chars).

For an editor designed for programmers the text is going to be subdivided in logical lines and therefore using an approach based on an array of pointers to lines seems appropriate. Even if this will make some cross-line operation somewhat annoying some of line-based operations will become easier... line numbering in display becomes a trivial problem, especially if you don't need to implement line wrap (horrible with code anyway) by going for truncation and horizontal scrolling instead.

like image 188
6502 Avatar answered Nov 15 '22 02:11

6502


The best approach is to start from the system edit or richedit control and adapt it to your needs. Writing your own edit control is way more work than you can possibly realise - including handling accessibility, IMEs for languages with complex alphabets, copy and paste, scroll bars, cursors, selections and lots more.

The two system controls provide lots of extension points that should allow you to achieve most goals. Unless you are really building a word process or source code editor, you should stick with the ones provided. And custom edit controls are a massive source of bugs. I seldom see one that works right just for the basic cases.

Martyn

like image 39
Martyn Lovell Avatar answered Nov 15 '22 04:11

Martyn Lovell


If you are considering something like a source code viewer (ref: "to implement syntax highlighting") with a mutable backing store, you may find std::list<std::string> a good starting point, and it may be overkill if the string is small.

With a contiguous buffer for your text (e.g. one big std::string or std::vector), you will have a lot of moving and resizing during editing, as well as a lot of scanning when repositioning. Those moves and resizes will result in many large, contiguous allocations, initialization of the buffer, moving, and freeing of old memory. It also restricts how you cache data (if that is important). Your lookup times will be slightly slower with a list, but your moves and mutations will be much faster than using a contiguous buffer for the entire file.

std::list<std::string> has some nice properties because it grows and mutates as a collection of strings (e.g. for each line or paragraph) nicely.

This overview details the list's strengths and compares it to other containers well: http://www.cplusplus.com/reference/stl/list/

If you want to associate some data to the string/line, then just create a list of these:

namespace MON {
class t_line {
public:
  /* ... */
private:
  std::string d_string;
  t_lexer_stuff d_lexerStuff;
};
}
like image 41
justin Avatar answered Nov 15 '22 04:11

justin


While searching for the same thin I came across two Wikipedia pages that where very helpfull:

Gap buffer for simple editing

Rope (data structure) for complex text editing

like image 32
SLC Avatar answered Nov 15 '22 04:11

SLC