Skip to content

Instantly share code, notes, and snippets.

@lf94
Created May 14, 2015 03:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lf94/2726757d6b15151a83bc to your computer and use it in GitHub Desktop.
Save lf94/2726757d6b15151a83bc to your computer and use it in GitHub Desktop.
GNOME GtkTextView/GtkTextBuffer's buffer data management
void
_gtk_text_btree_insert (GtkTextIter *iter,
const gchar *text,
gint len)
{
GtkTextLineSegment *prev_seg; /* The segment just before the first
* new segment (NULL means new segment
* is at beginning of line). */
GtkTextLineSegment *cur_seg; /* Current segment; new characters
* are inserted just after this one.
* NULL means insert at beginning of
* line. */
GtkTextLine *line; /* Current line (new segments are
* added to this line). */
GtkTextLineSegment *seg;
GtkTextLine *newline;
int chunk_len; /* # characters in current chunk. */
gint sol; /* start of line */
gint eol; /* Pointer to character just after last
* one in current chunk.
*/
gint delim; /* index of paragraph delimiter */
int line_count_delta; /* Counts change to total number of
* lines in file.
*/
int char_count_delta; /* change to number of chars */
GtkTextBTree *tree;
gint start_byte_index;
GtkTextLine *start_line;
g_return_if_fail (text != NULL);
g_return_if_fail (iter != NULL);
if (len < 0)
len = strlen (text);
/* extract iterator info */
tree = _gtk_text_iter_get_btree (iter);
line = _gtk_text_iter_get_text_line (iter);
start_line = line;
start_byte_index = gtk_text_iter_get_line_index (iter);
/* Get our insertion segment split. Note this assumes line allows
* char insertions, which isn't true of the "last" line. But iter
* should not be on that line, as we assert here.
*/
g_assert (!_gtk_text_line_is_last (line, tree));
prev_seg = gtk_text_line_segment_split (iter);
cur_seg = prev_seg;
/* Invalidate all iterators */
chars_changed (tree);
segments_changed (tree);
/*
* Chop the text up into lines and create a new segment for
* each line, plus a new line for the leftovers from the
* previous line.
*/
eol = 0;
sol = 0;
line_count_delta = 0;
char_count_delta = 0;
while (eol < len)
{
sol = eol;
pango_find_paragraph_boundary (text + sol,
len - sol,
&delim,
&eol);
/* make these relative to the start of the text */
delim += sol;
eol += sol;
g_assert (eol >= sol);
g_assert (delim >= sol);
g_assert (eol >= delim);
g_assert (sol >= 0);
g_assert (eol <= len);
chunk_len = eol - sol;
g_assert (g_utf8_validate (&text[sol], chunk_len, NULL));
seg = _gtk_char_segment_new (&text[sol], chunk_len);
char_count_delta += seg->char_count;
if (cur_seg == NULL)
{
seg->next = line->segments;
line->segments = seg;
}
else
{
seg->next = cur_seg->next;
cur_seg->next = seg;
}
if (delim == eol)
{
/* chunk didn't end with a paragraph separator */
g_assert (eol == len);
break;
}
/*
* The chunk ended with a newline, so create a new GtkTextLine
* and move the remainder of the old line to it.
*/
newline = gtk_text_line_new ();
gtk_text_line_set_parent (newline, line->parent);
newline->next = line->next;
line->next = newline;
newline->segments = seg->next;
seg->next = NULL;
line = newline;
cur_seg = NULL;
line_count_delta++;
}
/*
* Cleanup the starting line for the insertion, plus the ending
* line if it's different.
*/
cleanup_line (start_line);
if (line != start_line)
{
cleanup_line (line);
}
post_insert_fixup (tree, line, line_count_delta, char_count_delta);
/* Invalidate our region, and reset the iterator the user
passed in to point to the end of the inserted text. */
{
GtkTextIter start;
GtkTextIter end;
_gtk_text_btree_get_iter_at_line (tree,
&start,
start_line,
start_byte_index);
end = start;
/* We could almost certainly be more efficient here
by saving the information from the insertion loop
above. FIXME */
gtk_text_iter_forward_chars (&end, char_count_delta);
DV (g_print ("invalidating due to inserting some text (%s)\n", G_STRLOC));
_gtk_text_btree_invalidate_region (tree, &start, &end, FALSE);
/* Convenience for the user */
*iter = end;
gtk_text_btree_resolve_bidi (&start, &end);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment