/* Format->Comment Out Selection */ void action_comment_out_selection(GtkAction *action, I7Document *document) { GtkTextBuffer *buffer = GTK_TEXT_BUFFER(i7_document_get_buffer(document)); GtkTextIter start, end; if(!gtk_text_buffer_get_selection_bounds(buffer, &start, &end)) return; gchar *text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); /* Treat it as one single undo action */ gtk_text_buffer_begin_user_action(buffer); /* Delete the entire text and reinsert it inside brackets, in order to avoid excessively recalculating the syntax highlighting */ gtk_text_buffer_delete(buffer, &start, &end); gchar *newtext = g_strconcat("[", text, "]", NULL); GtkTextMark *tempmark = gtk_text_buffer_create_mark(buffer, NULL, &end, TRUE); gtk_text_buffer_insert(buffer, &end, newtext, -1); gtk_text_buffer_end_user_action(buffer); g_free(text); g_free(newtext); /* Select the text again, including [] */ gtk_text_buffer_get_iter_at_mark(buffer, &start, tempmark); gtk_text_buffer_select_range(buffer, &start, &end); gtk_text_buffer_delete_mark(buffer, tempmark); }
/* Format->Unindent */ void action_unindent(GtkAction *action, I7Document *document) { GtkTextBuffer *buffer = GTK_TEXT_BUFFER(i7_document_get_buffer(document)); /* Shift the selected lines in the buffer one tab to the left */ /* Adapted from gtksourceview.c */ GtkTextIter start, end; gtk_text_buffer_get_selection_bounds(buffer, &start, &end); /* Find out which lines to unindent */ gint start_line = gtk_text_iter_get_line(&start); gint end_line = gtk_text_iter_get_line(&end); gint i; /* if the end of the selection is before the first character on a line, don't unindent it */ if((gtk_text_iter_get_visible_line_offset(&end) == 0) && (end_line > start_line)) end_line--; /* Treat it as one single undo action */ gtk_text_buffer_begin_user_action(buffer); for(i = start_line; i <= end_line; i++) { GtkTextIter iter, iter2; gtk_text_buffer_get_iter_at_line(buffer, &iter, i); if(gtk_text_iter_get_char(&iter) == '\t') { iter2 = iter; gtk_text_iter_forward_char(&iter2); gtk_text_buffer_delete(buffer, &iter, &iter2); } } gtk_text_buffer_end_user_action(buffer); }
/* Format->Indent */ void action_indent(GtkAction *action, I7Document *document) { GtkTextBuffer *buffer = GTK_TEXT_BUFFER(i7_document_get_buffer(document)); /* Shift the selected lines in the buffer one tab to the right */ /* Adapted from gtksourceview.c */ GtkTextIter start, end; gtk_text_buffer_get_selection_bounds(buffer, &start, &end); /* Find out which lines to indent */ gint start_line = gtk_text_iter_get_line(&start); gint end_line = gtk_text_iter_get_line(&end); gint i; /* if the end of the selection is before the first character on a line, don't indent it */ if((gtk_text_iter_get_visible_line_offset(&end) == 0) && (end_line > start_line)) end_line--; /* Treat it as one single undo action */ gtk_text_buffer_begin_user_action(buffer); for(i = start_line; i <= end_line; i++) { GtkTextIter iter; gtk_text_buffer_get_iter_at_line(buffer, &iter, i); /* don't add indentation on empty lines */ if(gtk_text_iter_ends_line(&iter)) continue; gtk_text_buffer_insert(buffer, &iter, "\t", -1); } gtk_text_buffer_end_user_action(buffer); }
/* Edit->Redo */ void action_redo(GtkAction *action, I7Document *document) { GtkSourceBuffer *buffer = i7_document_get_buffer(document); if(gtk_source_buffer_can_redo(buffer)) gtk_source_buffer_redo(buffer); /* Update the "sensitive" state of the undo and redo actions */ gtk_action_set_sensitive(action, gtk_source_buffer_can_redo(buffer)); gtk_action_set_sensitive(document->undo, gtk_source_buffer_can_undo(buffer)); }
/* Search the project file for the string 'text' */ void i7_search_window_search_project(I7SearchWindow *self) { I7_SEARCH_WINDOW_USE_PRIVATE(self, priv); GtkTreeIter result; GtkTextIter search_from, match_start, match_end; GtkTextBuffer *buffer = GTK_TEXT_BUFFER(i7_document_get_buffer(priv->document)); gtk_text_buffer_get_start_iter(buffer, &search_from); start_spinner(self); while(find_no_wrap(&search_from, priv->text, TRUE, GTK_SOURCE_SEARCH_TEXT_ONLY | (priv->ignore_case? GTK_SOURCE_SEARCH_CASE_INSENSITIVE : 0), priv->algorithm, &match_start, &match_end)) { while(gtk_events_pending()) gtk_main_iteration(); search_from = match_end; /* Get the line number (counted from 0) */ guint lineno = gtk_text_iter_get_line(&match_start) + 1; gchar *context = extract_context(buffer, &match_start, &match_end); /* Make a sort string */ gchar *sort = g_strdup_printf("%04i", lineno); /* Put the full path to the project in */ GFile *file = i7_document_get_file(priv->document); gtk_list_store_append(priv->results, &result); gtk_list_store_set(priv->results, &result, I7_RESULT_CONTEXT_COLUMN, context, I7_RESULT_SORT_STRING_COLUMN, sort, I7_RESULT_FILE_COLUMN, file, I7_RESULT_RESULT_TYPE_COLUMN, I7_RESULT_TYPE_PROJECT, I7_RESULT_LINE_NUMBER_COLUMN, lineno, -1); g_free(context); g_free(sort); g_object_unref(file); } stop_spinner(self); }
/* Format->Uncomment Selection */ void action_uncomment_selection(GtkAction *action, I7Document *document) { GtkTextBuffer *buffer = GTK_TEXT_BUFFER(i7_document_get_buffer(document)); GtkTextIter start, end; if(!gtk_text_buffer_get_selection_bounds(buffer, &start, &end)) return; /* Find first [ from the beginning of the selection, then the last ] between there and the end of the selection */ if(gtk_text_iter_get_char(&start) != '[' && !gtk_text_iter_forward_find_char(&start, char_equals, GUINT_TO_POINTER('['), &end)) return; gtk_text_iter_backward_char(&end); if(gtk_text_iter_get_char(&end) != ']' && !gtk_text_iter_backward_find_char(&end, char_equals, GUINT_TO_POINTER(']'), &start)) return; gtk_text_iter_forward_char(&end); gchar *text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); /* Treat it as one single undo action */ gtk_text_buffer_begin_user_action(buffer); /* Delete the comment and re-insert it without brackets */ gtk_text_buffer_delete(buffer, &start, &end); gchar *newtext = g_strndup(text + 1, strlen(text) - 2); GtkTextMark *tempmark = gtk_text_buffer_create_mark(buffer, NULL, &end, TRUE); gtk_text_buffer_insert(buffer, &end, newtext, -1); gtk_text_buffer_end_user_action(buffer); g_free(text); g_free(newtext); /* Select only the uncommented text again */ gtk_text_buffer_get_iter_at_mark(buffer, &start, tempmark); gtk_text_buffer_select_range(buffer, &start, &end); gtk_text_buffer_delete_mark(buffer, tempmark); }
/* Callback for beginning the print operation, we give the printed pages our tab width from the preferences, and the margins from the page setup dialog. */ static void on_begin_print(GtkPrintOperation *print, GtkPrintContext *context, I7Document *document) { I7App *theapp = i7_app_get(); GSettings *prefs = i7_app_get_prefs(theapp); GtkSourcePrintCompositor *compositor = gtk_source_print_compositor_new(i7_document_get_buffer(document)); g_signal_connect(print, "draw-page", G_CALLBACK(on_draw_page), compositor); g_signal_connect(print, "end-print", G_CALLBACK(on_end_print), compositor); /* Design our printed page */ unsigned tabwidth = g_settings_get_uint(prefs, PREFS_TAB_WIDTH); if(tabwidth == 0) tabwidth = DEFAULT_TAB_WIDTH; gtk_source_print_compositor_set_tab_width(compositor, tabwidth); gtk_source_print_compositor_set_wrap_mode(compositor, GTK_WRAP_WORD_CHAR); PangoFontDescription *font = get_font_description(); gchar *fontstring = pango_font_description_to_string(font); pango_font_description_free(font); gtk_source_print_compositor_set_body_font_name(compositor, fontstring); g_free(fontstring); GtkPageSetup *setup = i7_app_get_page_setup(i7_app_get()); gtk_source_print_compositor_set_top_margin(compositor, gtk_page_setup_get_top_margin(setup, GTK_UNIT_MM), GTK_UNIT_MM); gtk_source_print_compositor_set_bottom_margin(compositor, gtk_page_setup_get_bottom_margin(setup, GTK_UNIT_MM), GTK_UNIT_MM); gtk_source_print_compositor_set_left_margin(compositor, gtk_page_setup_get_left_margin(setup, GTK_UNIT_MM), GTK_UNIT_MM); gtk_source_print_compositor_set_right_margin(compositor, gtk_page_setup_get_right_margin(setup, GTK_UNIT_MM), GTK_UNIT_MM); /* Display a notification in the status bar while paginating */ i7_document_display_status_message(document, _("Paginating..."), PRINT_OPERATIONS); while(!gtk_source_print_compositor_paginate(compositor, context)) { i7_document_display_progress_percentage(document, gtk_source_print_compositor_get_pagination_progress(compositor)); while(gtk_events_pending()) gtk_main_iteration(); } i7_document_display_progress_percentage(document, 0.0); i7_document_remove_status_message(document, PRINT_OPERATIONS); gtk_print_operation_set_n_pages(print, gtk_source_print_compositor_get_n_pages(compositor)); }
/* Format->Renumber All Sections */ void action_renumber_all_sections(GtkAction *action, I7Document *document) { GtkTextIter pos, end; int volume = 1, book = 1, part = 1, chapter = 1, section = 1; GtkTextBuffer *buffer = GTK_TEXT_BUFFER(i7_document_get_buffer(document)); gtk_text_buffer_get_start_iter(buffer, &pos); /* Renumbering sections counts as one action for Undo */ gtk_text_buffer_begin_user_action(buffer); while(gtk_text_iter_get_char(&pos) != 0) { if(gtk_text_iter_get_char(&pos) != '\n') { gtk_text_iter_forward_line(&pos); continue; } gtk_text_iter_forward_line(&pos); end = pos; gboolean not_last = gtk_text_iter_forward_line(&end); if(!not_last || gtk_text_iter_get_char(&end) == '\n') { /* Preceded and followed by a blank line, or only preceded by one and current line is last line */ /* Get the entire line and its line number, chop the \n */ gchar *text = gtk_text_iter_get_text(&pos, &end); gchar *lcase = g_utf8_strdown(text, -1); gchar *title = strchr(text, '-'); if(title && g_str_has_suffix(title, "\n")) *(strrchr(title, '\n')) = '\0'; /* remove trailing \n */ gchar *newtitle; if(g_str_has_prefix(lcase, "volume")) { newtitle = g_strdup_printf("Volume %d %s\n", volume++, title); gtk_text_buffer_delete(buffer, &pos, &end); gtk_text_buffer_insert(buffer, &pos, newtitle, -1); g_free(newtitle); book = part = chapter = section = 1; } else if(g_str_has_prefix(lcase, "book")) { newtitle = g_strdup_printf("Book %d %s\n", book++, title); gtk_text_buffer_delete(buffer, &pos, &end); gtk_text_buffer_insert(buffer, &pos, newtitle, -1); g_free(newtitle); part = chapter = section = 1; } else if(g_str_has_prefix(lcase, "part")) { newtitle = g_strdup_printf("Part %d %s\n", part++, title); gtk_text_buffer_delete(buffer, &pos, &end); gtk_text_buffer_insert(buffer, &pos, newtitle, -1); g_free(newtitle); chapter = section = 1; } else if(g_str_has_prefix(lcase, "chapter")) { newtitle = g_strdup_printf("Chapter %d %s\n", chapter++, title); gtk_text_buffer_delete(buffer, &pos, &end); gtk_text_buffer_insert(buffer, &pos, newtitle, -1); g_free(newtitle); section = 1; } else if(g_str_has_prefix(lcase, "section")) { newtitle = g_strdup_printf("Section %d %s\n", section++, title); gtk_text_buffer_delete(buffer, &pos, &end); gtk_text_buffer_insert(buffer, &pos, newtitle, -1); g_free(newtitle); } g_free(text); g_free(lcase); } } gtk_text_buffer_end_user_action(buffer); }