Thread: Conceptual overview of a text editor/browser

  1. #1
    Registered User
    Join Date
    Jan 2016
    Posts
    35

    Conceptual overview of a text editor/browser

    Hi,

    I'm interested in integrating a text browser using the ncurses interface into my CLI app. This is largely intended to overcome the limitations of outputting to terminal/stdout.

    I'm looking for advice as to the fundamental principle involved in text editor (or text browser for that mater) design.

    This is what I want to do:

    * Add new strings to a text buffer.
    - What sort of a char* buffer should I be considering?
    - What is the approach to increment new strings or data to the buffer? Not using strncat or string.h. I could be wrong. A more direct 'low-level' approach is desired.

    * Read and display the buffer continuously as new content gets added to the buffer.

    The overall size of the content for the buffer would be comparable to a plain text file several megabytes large.

    All views greatly appreciated.

    Thanks
    Last edited by wiqxlzxsxj; 01-11-2016 at 05:37 PM.

  2. #2
    Registered User
    Join Date
    Jun 2015
    Posts
    1,643
    What exactly are your minimum specs?

    * Do you need to change/delete/add text?

    * Do you only need to add text at the "bottom" (end) of the buffer?

    * Is this basically so that you can scroll back and view what's
    been printed so far while allowing more to be added at the bottom?

    * Do you need to retain every line of output or only the last N lines?

    * Do you need to search for text?

    And have you read up on ncurses yet? Understanding that API will affect your design decisions.

  3. #3
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    One efficient approach is to split the buffer into chunks, for example
    Code:
    #define CHUNK_SIZE 16384
    
    struct chunk {
        struct chunk  *prev;
        struct chunk  *next;
        struct slines *cache; /* For ncurses stuff, explained below */
        size_t         lines;
        size_t         chars;
        unsigned char  data[CHUNK_SIZE];
    };
    Each chunk contains lines complete lines.
    You'll keep a pointer to the current chunk, as well as the number of lines prior to the current chunk. This way you only need to work on one chunk at a time.

    Another option is to use an array of lines.

    For ncurses, especially if you intend to do syntax highlighting (adding attributes like color to arbitrary characters), a combination of the two would work well. For the current chunk(s), you construct an array of ncurses attribute-and-character strings, one per line:
    Code:
    struct slines {
        struct chunk  *owner;
        size_t         lines;
        size_t        *line_offset;
        size_t        *line_length;
        size_t         cchars;
        cchar_t       *buffer;
    };
    Instead of allocating each line separately, the structure contains one common buffer, which each line references. (For syntax highlighting, each chunk may also need some kind of "state" cookie, which I omitted above, so that the highlighter only needs to examine the current chunk to produce the current ncurses highlighted buffer.)

    The line lengths are needed if you allow horizontal scrolling. (A line might be shorter than the current horizontal scrolling offset, in which case you don't print anything to that particular line.)

    When modifying data, you can either keep a separate buffer for the current line (or paragraph), or modify the display buffer (contents in the slines structure) directly. When the user moves the cursor, this buffer is then used to reconstruct the original chunk or chunks.

    These are the techniques we used when the machines had limited resources (memory and CPU power).

    Nowadays, you can easily get away with just
    Code:
    struct line {
        size_t        max_length;
        size_t        length;
        cchar_t       data[];
    };
    
    struct file {
        size_t        max_lines;
        size_t        num_lines;
        struct line **line;
    };
    When you read data from the file, you construct the character-and-attribute data for each line into a struct line, with a pointer to each struct stored in struct file.

    If you add a new line, you make sure you have room for one more line pointer in struct file, and use memmove() to move the following lines one down. You remove a line by freeing the pointer to its struct line, and using memmove() to move the following lines one up.

    If the contents are human-readable text, then the natural unit is not line, but a paragraph. Other than that, it's pretty much the same.

  4. #4
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,743
    Is it prohibited to name two common data structures used for text editing rather than describing them? E.g. Rope and Gap Buffer

  5. #5
    Registered User
    Join Date
    Jan 2016
    Posts
    35
    Fantastic! Thanks for the responses everyone. There is enough here to chew on.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Developer Editor With Class and Variable Browser
    By nathanpc in forum C Programming
    Replies: 26
    Last Post: 05-23-2010, 11:24 AM
  2. Insert text to browser's textbox
    By Ducky in forum Windows Programming
    Replies: 4
    Last Post: 05-01-2009, 11:56 PM
  3. project photo-browser/editor ...
    By foobar in forum Windows Programming
    Replies: 1
    Last Post: 11-24-2005, 04:03 AM
  4. create a text file with data using text editor
    By fried egg in forum C Programming
    Replies: 3
    Last Post: 03-14-2002, 09:11 PM