//================================================================ int GUI_msgwin_rmLast (MemObj *mo) { //================================================================ /// delete last textoutputline GtkTextIter iVon, iBis; GtkTextBuffer *TxBuf; Obj_Unknown *go; go = GUI_obj_pos (mo); if(!go) return 0; // get textBuffer from textView TxBuf = gtk_text_view_get_buffer (GTK_TEXT_VIEW(go->widget)); gtk_text_buffer_get_end_iter (TxBuf, &iBis); iVon = iBis; gtk_text_iter_backward_line (&iVon); gtk_text_buffer_delete (TxBuf, &iVon, &iBis); // printf("GUI_msgwin_rmLast\n"); // clear buffer in GUI_msgwin_prt GUI_msgwin_prt (mo, NULL); return 0; }
/* If the last char is a newline, remove it from the buffer (otherwise GtkTextView shows it as an empty line). See bug #324942. */ static void remove_ending_newline (GeditDocumentOutputStream *stream) { GtkTextIter end; GtkTextIter start; gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER (stream->priv->doc), &end); start = end; gtk_text_iter_set_line_offset (&start, 0); if (gtk_text_iter_ends_line (&start) && gtk_text_iter_backward_line (&start)) { if (!gtk_text_iter_ends_line (&start)) { gtk_text_iter_forward_to_line_end (&start); } /* Delete the empty line which is from 'start' to 'end' */ gtk_text_buffer_delete (GTK_TEXT_BUFFER (stream->priv->doc), &start, &end); } }
static void log_window_jump_to_error(LogWindow *logwin) { GtkTextIter iter; gtk_text_buffer_get_end_iter(logwin->buffer, &iter); if (!gtk_text_iter_backward_to_tag_toggle(&iter, logwin->error_tag)) return; gtk_text_iter_backward_line(&iter); gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(logwin->text), &iter, 0, TRUE, 0, 0); }
static gboolean smie_gtk_source_buffer_backward_line (gpointer data) { smie_gtk_source_buffer_context_t *context = data; return gtk_text_iter_backward_line (&context->iter); }
/** * gtk_source_iter_backward_search: * @iter: a #GtkTextIter where the search begins. * @str: search string. * @flags: bitmask of flags affecting the search. * @match_start: return location for start of match, or %%NULL. * @match_end: return location for end of match, or %%NULL. * @limit: location of last possible @match_start, or %%NULL for start of buffer. * * Same as gtk_text_iter_backward_search(), but supports case insensitive * searching. * * Return value: whether a match was found. **/ gboolean gtk_source_iter_backward_search (const GtkTextIter *iter, const gchar *str, GtkSourceSearchFlags flags, GtkTextIter *match_start, GtkTextIter *match_end, const GtkTextIter *limit) { gchar **lines = NULL; GtkTextIter match; gboolean retval = FALSE; GtkTextIter search; gboolean visible_only; gboolean slice; g_return_val_if_fail (iter != NULL, FALSE); g_return_val_if_fail (str != NULL, FALSE); if ((flags & GTK_SOURCE_SEARCH_CASE_INSENSITIVE) == 0) return gtk_text_iter_backward_search (iter, str, flags, match_start, match_end, limit); if (limit && gtk_text_iter_compare (iter, limit) <= 0) return FALSE; if (*str == '\0') { /* If we can move one char, return the empty string there */ match = *iter; if (gtk_text_iter_backward_char (&match)) { if (limit && gtk_text_iter_equal (&match, limit)) return FALSE; if (match_start) *match_start = match; if (match_end) *match_end = match; return TRUE; } else { return FALSE; } } visible_only = (flags & GTK_SOURCE_SEARCH_VISIBLE_ONLY) != 0; slice = (flags & GTK_SOURCE_SEARCH_TEXT_ONLY) == 0; /* locate all lines */ lines = strbreakup (str, "\n", -1); search = *iter; while (TRUE) { /* This loop has an inefficient worst-case, where * gtk_text_iter_get_text () is called repeatedly on * a single line. */ GtkTextIter end; if (limit && gtk_text_iter_compare (&search, limit) <= 0) break; if (backward_lines_match (&search, (const gchar**)lines, visible_only, slice, &match, &end)) { if (limit == NULL || (limit && gtk_text_iter_compare (&end, limit) > 0)) { retval = TRUE; if (match_start) *match_start = match; if (match_end) *match_end = end; } break; } if (gtk_text_iter_get_line_offset (&search) == 0) { if (!gtk_text_iter_backward_line (&search)) break; } else { gtk_text_iter_set_line_offset (&search, 0); } } g_strfreev ((gchar**)lines); return retval; }
static gboolean backward_lines_match (const GtkTextIter *start, const gchar **lines, gboolean visible_only, gboolean slice, GtkTextIter *match_start, GtkTextIter *match_end) { GtkTextIter line, next; gchar *line_text; const gchar *found; gint offset; if (*lines == NULL || **lines == '\0') { if (match_start) *match_start = *start; if (match_end) *match_end = *start; return TRUE; } line = next = *start; if (gtk_text_iter_get_line_offset (&next) == 0) { if (!gtk_text_iter_backward_line (&next)) return FALSE; } else gtk_text_iter_set_line_offset (&next, 0); if (slice) { if (visible_only) line_text = gtk_text_iter_get_visible_slice (&next, &line); else line_text = gtk_text_iter_get_slice (&next, &line); } else { if (visible_only) line_text = gtk_text_iter_get_visible_text (&next, &line); else line_text = gtk_text_iter_get_text (&next, &line); } if (match_start) /* if this is the first line we're matching */ { found = g_utf8_strrcasestr (line_text, *lines); } else { /* If it's not the first line, we have to match from the * start of the line. */ if (g_utf8_caselessnmatch (line_text, *lines, strlen (line_text), strlen (*lines))) found = line_text; else found = NULL; } if (found == NULL) { g_free (line_text); return FALSE; } /* Get offset to start of search string */ offset = g_utf8_strlen (line_text, found - line_text); forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE); /* If match start needs to be returned, set it to the * start of the search string. */ if (match_start) { *match_start = next; } /* Go to end of search string */ forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, !slice, TRUE); g_free (line_text); ++lines; if (match_end) *match_end = next; /* try to match the rest of the lines forward, passing NULL * for match_start so lines_match will try to match the entire * line */ return lines_match (&next, lines, visible_only, slice, NULL, match_end); }
/** * gail_text_util_get_text: * @textutil: A #GailTextUtil * @layout: A gpointer which is a PangoLayout, a GtkTreeView of NULL * @function: An enumeration specifying whether to return the text before, at, or * after the offset. * @boundary_type: The boundary type. * @offset: The offset of the text in the GailTextUtil * @start_offset: Address of location in which the start offset is returned * @end_offset: Address of location in which the end offset is returned * * This function gets the requested substring from the text in the GtkTextUtil. * The layout is used only for getting the text on a line. The value is NULL * for a GtkTextView which is not wrapped, is a GtkTextView for a GtkTextView * which is wrapped and is a PangoLayout otherwise. * * Returns: the substring requested **/ gchar* gail_text_util_get_text (GailTextUtil *textutil, gpointer layout, GailOffsetType function, AtkTextBoundary boundary_type, gint offset, gint *start_offset, gint *end_offset) { GtkTextIter start, end; gint line_number; GtkTextBuffer *buffer; g_return_val_if_fail (GAIL_IS_TEXT_UTIL (textutil), NULL); buffer = textutil->buffer; if (buffer == NULL) { *start_offset = 0; *end_offset = 0; return NULL; } if (!gtk_text_buffer_get_char_count (buffer)) { *start_offset = 0; *end_offset = 0; return g_strdup (""); } gtk_text_buffer_get_iter_at_offset (buffer, &start, offset); end = start; switch (function) { case GAIL_BEFORE_OFFSET: switch (boundary_type) { case ATK_TEXT_BOUNDARY_CHAR: gtk_text_iter_backward_char(&start); break; case ATK_TEXT_BOUNDARY_WORD_START: if (!gtk_text_iter_starts_word (&start)) gtk_text_iter_backward_word_start (&start); end = start; gtk_text_iter_backward_word_start(&start); break; case ATK_TEXT_BOUNDARY_WORD_END: if (gtk_text_iter_inside_word (&start) && !gtk_text_iter_starts_word (&start)) gtk_text_iter_backward_word_start (&start); while (!gtk_text_iter_ends_word (&start)) { if (!gtk_text_iter_backward_char (&start)) break; } end = start; gtk_text_iter_backward_word_start(&start); while (!gtk_text_iter_ends_word (&start)) { if (!gtk_text_iter_backward_char (&start)) break; } break; case ATK_TEXT_BOUNDARY_SENTENCE_START: if (!gtk_text_iter_starts_sentence (&start)) gtk_text_iter_backward_sentence_start (&start); end = start; gtk_text_iter_backward_sentence_start (&start); break; case ATK_TEXT_BOUNDARY_SENTENCE_END: if (gtk_text_iter_inside_sentence (&start) && !gtk_text_iter_starts_sentence (&start)) gtk_text_iter_backward_sentence_start (&start); while (!gtk_text_iter_ends_sentence (&start)) { if (!gtk_text_iter_backward_char (&start)) break; } end = start; gtk_text_iter_backward_sentence_start (&start); while (!gtk_text_iter_ends_sentence (&start)) { if (!gtk_text_iter_backward_char (&start)) break; } break; case ATK_TEXT_BOUNDARY_LINE_START: if (layout == NULL) { line_number = gtk_text_iter_get_line (&start); if (line_number == 0) { gtk_text_buffer_get_iter_at_offset (buffer, &start, 0); } else { gtk_text_iter_backward_line (&start); gtk_text_iter_forward_line (&start); } end = start; gtk_text_iter_backward_line (&start); } else if GTK_IS_TEXT_VIEW (layout) { GtkTextView *view = GTK_TEXT_VIEW (layout); gtk_text_view_backward_display_line_start (view, &start); end = start; gtk_text_view_backward_display_line (view, &start); } else if (PANGO_IS_LAYOUT (layout)) get_pango_text_offsets (PANGO_LAYOUT (layout), buffer, function, boundary_type, offset, start_offset, end_offset, &start, &end); break; case ATK_TEXT_BOUNDARY_LINE_END: if (layout == NULL) { line_number = gtk_text_iter_get_line (&start); if (line_number == 0) { gtk_text_buffer_get_iter_at_offset (buffer, &start, 0); end = start; } else { gtk_text_iter_backward_line (&start); end = start; while (!gtk_text_iter_ends_line (&start)) { if (!gtk_text_iter_backward_char (&start)) break; } gtk_text_iter_forward_to_line_end (&end); } } else if GTK_IS_TEXT_VIEW (layout) { GtkTextView *view = GTK_TEXT_VIEW (layout); gtk_text_view_backward_display_line_start (view, &start); if (!gtk_text_iter_is_start (&start)) { gtk_text_view_backward_display_line (view, &start); end = start; if (!gtk_text_iter_is_start (&start)) { gtk_text_view_backward_display_line (view, &start); gtk_text_view_forward_display_line_end (view, &start); } gtk_text_view_forward_display_line_end (view, &end); } else { end = start; } } else if (PANGO_IS_LAYOUT (layout)) get_pango_text_offsets (PANGO_LAYOUT (layout), buffer, function, boundary_type, offset, start_offset, end_offset, &start, &end); break; }
/** @brief Search backward from @a iter to try to find next match of @a str in textbuffer This is like gtk_text_iter_backward_search(), but supports case-insensitive and whole-word searching. See comments for e2_iter_forward_search(). @param iter a GtkTextIter where the search begins @param str search string, may include 1 or more \n @param flags bitmask of flags affecting the search @param match_start return location for start of match, or NULL @param match_end return location for end of match, or NULL @param limit lower bound of match end, or NULL for start of buffer @return TRUE if a match was found */ gboolean e2_iter_backward_search ( const GtkTextIter *iter, const gchar *str, E2TextSearchFlags flags, GtkTextIter *match_start, GtkTextIter *match_end, const GtkTextIter *limit) { gboolean visible_only, slice, retval; GtkTextIter search, match; g_return_val_if_fail (iter != NULL, FALSE); g_return_val_if_fail (str != NULL, FALSE); if (!(flags & E2_SEARCH_CASE_INSENSITIVE)) { search = *iter; rescan: retval = gtk_text_iter_backward_search (&search, str, flags, match_start, match_end, limit); if (retval && (flags & E2_SEARCH_WHOLE_WORD) && (!gtk_text_iter_starts_word (match_start) //see comment above re end-checking when highlighting || !gtk_text_iter_ends_word (match_end) )) { search = *match_start; if (gtk_text_iter_backward_char (&search)) goto rescan; retval = FALSE; } return retval; } if (limit != NULL && gtk_text_iter_compare (iter, limit) < 0) return FALSE; if (*str == '\0') //matching nothing { //if we can move one char, return that location for the match match = *iter; if (gtk_text_iter_backward_char (&match)) { if (limit == NULL || gtk_text_iter_compare (&match, limit) >= 0) { if (match_start != NULL) *match_start = match; if (match_end != NULL) *match_end = match; return TRUE; } } return FALSE; } //split search string into lines gchar **lines = e2_utils_str_breakup (str, "\n", -1); if (lines == NULL) return FALSE; //FIXME warn user about error visible_only = (flags & E2_SEARCH_VISIBLE_ONLY) != 0; slice = (flags & E2_SEARCH_TEXT_ONLY) == 0; retval = FALSE; search = *iter; while (TRUE) { /* This loop has an inefficient worst-case, where gtk_text_iter_get_text() is called repeatedly on each single line */ GtkTextIter end; rescan2: if (limit != NULL && gtk_text_iter_compare (&search, limit) < 0) break; if (_e2_textiter_backward_lines_match (&search, (const gchar**)lines, visible_only, slice, &match, &end)) { if (limit == NULL || gtk_text_iter_compare (&end, limit) >= 0) { if ((flags & E2_SEARCH_WHOLE_WORD) && (!gtk_text_iter_starts_word (&match) //see comment above re end-checking when highlighting || !gtk_text_iter_ends_word (&end) )) { search = match; if (gtk_text_iter_backward_char (&search)) goto rescan2; } else { retval = TRUE; if (match_start) *match_start = match; if (match_end) *match_end = end; } } break; } if (gtk_text_iter_get_line_offset (&search) == 0) //at start of line { if (!gtk_text_iter_backward_line (&search)) //can't move to start of previous line break; } else gtk_text_iter_set_line_offset (&search, 0); //go to start of current line and check again } g_strfreev (lines); return retval; }
/** @brief scan backwards from @a start for text which matches @a lines This performs line-by-line case-insensitive comparisons @param start pointer to textiter in buffer where the search is to commence @param lines array of \n-trailing line-strings, together comprising the search string @param visible_only TRUE to ignore hidden chars in the text @param slice TRUE to include "unknown" (0xFFFC) chars in the text @param match_start textiter to store the start of a matching string, or NULL when re-entering to parse lines after 1st @param match_end textiter store the start of a matching string, or NULL @return TRUE if a match was found */ static gboolean _e2_textiter_backward_lines_match ( const GtkTextIter *start, const gchar **lines, gboolean visible_only, gboolean slice, GtkTextIter *match_start, GtkTextIter *match_end) { GtkTextIter line, next; gchar *line_text; const gchar *found; gint offset; if (*lines == NULL || **lines == '\0') { //nothing to match, so everything matches if (match_start) *match_start = *start; if (match_end) *match_end = *start; return TRUE; } line = next = *start; if (gtk_text_iter_get_line_offset (&next) == 0) //CHECKME why break search into lines ? { if (!gtk_text_iter_backward_line (&next)) return FALSE; } else gtk_text_iter_set_line_offset (&next, 0); if (slice) { if (visible_only) line_text = gtk_text_iter_get_visible_slice (&next, &line); else line_text = gtk_text_iter_get_slice (&next, &line); } else { if (visible_only) line_text = gtk_text_iter_get_visible_text (&next, &line); else line_text = gtk_text_iter_get_text (&next, &line); } if (match_start != NULL) //if this is the first line we're matching { found = e2_utf8_strrcasestr (line_text, *lines); } else { //not the first line, we have to match from the start of the line if (e2_utf8_caseless_match (line_text, *lines, -1, -1)) found = line_text; else found = NULL; } if (found == NULL) { g_free (line_text); return FALSE; } //get offset to start of search string offset = g_utf8_strlen (line_text, found - line_text); _e2_textiter_forward_chars_with_skipping (&next, offset, visible_only, !slice, FALSE); //if match start needs to be returned, set it to the start of the search string if (match_start != NULL) { *match_start = next; } //go to end of search string _e2_textiter_forward_chars_with_skipping (&next, g_utf8_strlen (*lines, -1), visible_only, !slice, TRUE); g_free (line_text); ++lines; if (match_end != NULL) *match_end = next; /* try to match the rest of the lines forward, passing NULL for match_start so lines_match will try to match the entire line */ return _e2_textiter_forward_lines_match (&next, lines, visible_only, slice, NULL, match_end); }