From 7cb6832039a587bbf0b3912fb2c15072addc4a3b Mon Sep 17 00:00:00 2001 From: Nick Treleaven Date: Tue, 6 Mar 2007 16:57:09 +0000 Subject: [PATCH] Speed up loading multiple C-like files when existing documents are open (by ensuring documents are only colourised once). Add document_open_files(), document_colourise_new(). Add some missing function parameter names to document.h. git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@1369 ea778897-0a13-0410-b9d1-a72fbfd435f5 --- ChangeLog | 10 +++++ src/callbacks.c | 12 ++---- src/document.c | 107 +++++++++++++++++++++++++++++++++++++----------- src/document.h | 36 +++++++++------- src/keyfile.c | 2 +- src/main.c | 2 +- src/socket.c | 8 +++- src/win32.c | 5 ++- 8 files changed, 129 insertions(+), 53 deletions(-) diff --git a/ChangeLog b/ChangeLog index 72a08bbe..b8cb8244 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2007-03-06 Nick Treleaven + + * src/win32.c, src/callbacks.c, src/keyfile.c, src/document.c, + src/document.h, src/main.c, src/socket.c: + Speed up loading multiple C-like files when existing documents are + open (by ensuring documents are only colourised once). + Add document_open_files(), document_colourise_new(). + Add some missing function parameter names to document.h. + + 2007-03-05 Enrico Tröger * doc/geany.docbook: diff --git a/src/callbacks.c b/src/callbacks.c index ceba8919..bad11160 100644 --- a/src/callbacks.c +++ b/src/callbacks.c @@ -780,7 +780,6 @@ on_file_open_dialog_response (GtkDialog *dialog, if (response == GTK_RESPONSE_ACCEPT || response == GTK_RESPONSE_APPLY) { GSList *filelist; - GSList *flist; gint filetype_idx = gtk_combo_box_get_active(GTK_COMBO_BOX( lookup_widget(GTK_WIDGET(dialog), "filetype_combo"))); gint encoding_idx = gtk_combo_box_get_active(GTK_COMBO_BOX( @@ -794,15 +793,10 @@ on_file_open_dialog_response (GtkDialog *dialog, charset = encodings[encoding_idx].charset; filelist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(app->open_filesel)); - flist = filelist; - while (flist != NULL) + if (filelist != NULL) { - if (g_file_test((gchar*) flist->data, G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK)) - { - document_open_file(-1, (gchar*) flist->data, 0, ro, ft, charset); - } - g_free(flist->data); - flist = flist->next; + document_open_files(filelist, ro, ft, charset); + g_slist_foreach(filelist, (GFunc) g_free, NULL); // free filenames } g_slist_free(filelist); } diff --git a/src/document.c b/src/document.c index 8220404f..130c283a 100644 --- a/src/document.c +++ b/src/document.c @@ -711,9 +711,10 @@ static void set_cursor_position(gint idx, gint pos) /* To open a new file, set idx to -1; filename should be locale encoded. * To reload a file, set the idx for the document to be reloaded; filename should be NULL. * Returns: idx of the opened file or -1 if an error occurred. - */ -int document_open_file(gint idx, const gchar *filename, gint pos, gboolean readonly, filetype *ft, - const gchar *forced_enc) + * Note: If opening more than one file, document_delay_colourise() should be used before + * and document_colourise_new() after opening to avoid unnecessary recolourising. */ +gint document_open_file(gint idx, const gchar *filename, gint pos, gboolean readonly, + filetype *ft, const gchar *forced_enc) { gint editor_mode; gboolean reload = (idx == -1) ? FALSE : TRUE; @@ -859,6 +860,8 @@ void document_open_file_list(const gchar *data, gssize length) default: list = g_strsplit(data, "\n", 0); } + document_delay_colourise(); + for (i = 0; ; i++) { if (list[i] == NULL) break; @@ -867,11 +870,29 @@ void document_open_file_list(const gchar *data, gssize length) document_open_file(-1, filename, 0, FALSE, NULL, NULL); g_free(filename); } + document_colourise_new(); g_strfreev(list); } +/* Takes a linked list of filename URIs and opens each file, ensuring the newly opened + * documents and existing documents (if necessary) are only colourised once. */ +void document_open_files(const GSList *filenames, gboolean readonly, filetype *ft, + const gchar *forced_enc) +{ + const GSList *item; + + document_delay_colourise(); + + for (item = filenames; item != NULL; item = g_slist_next(item)) + { + document_open_file(-1, item->data, 0, readonly, ft, forced_enc); + } + document_colourise_new(); +} + + gint document_reload_file(gint idx, const gchar *forced_enc) { gint pos = 0; @@ -1264,7 +1285,7 @@ document_replace_range(gint idx, const gchar *find_text, const gchar *replace_te ttf.chrg.cpMin = start; ttf.chrg.cpMax = end; ttf.lpstrText = (gchar*)find_text; - + while (TRUE) { search_pos = sci_find_text(doc_list[idx].sci, flags, &ttf); @@ -1295,7 +1316,7 @@ document_replace_range(gint idx, const gchar *find_text, const gchar *replace_te { // scroll last match in view, will destroy the existing selection if (scroll_to_match) sci_goto_pos(doc_list[idx].sci, ttf.chrg.cpMin, TRUE); - + return end; } else @@ -1328,9 +1349,9 @@ void document_replace_sel(gint idx, const gchar *find_text, const gchar *replace if (selection_mode == SC_SEL_RECTANGLE && selected_lines > 1) { gint first_line, line, line_start, line_end, tmp; - + sci_start_undo_action(doc_list[idx].sci); - + first_line = sci_get_line_from_position(doc_list[idx].sci, selection_start); // Find the last line with chars selected (not EOL char) last_line = sci_get_line_from_position(doc_list[idx].sci, selection_end - 1); @@ -1339,7 +1360,7 @@ void document_replace_sel(gint idx, const gchar *find_text, const gchar *replace { line_start = sci_get_pos_at_line_sel_start(doc_list[idx].sci, line); line_end = sci_get_pos_at_line_sel_end(doc_list[idx].sci, line); - + // skip line if there is no selection if (line_start != INVALID_POSITION) { @@ -1348,7 +1369,7 @@ void document_replace_sel(gint idx, const gchar *find_text, const gchar *replace line_start, line_end, escaped_chars, FALSE); if (tmp != -1) { - replaced = TRUE; + replaced = TRUE; // this gets the greatest column within the selection after replacing max_column = MAX(max_column, tmp - sci_get_position_from_line(doc_list[idx].sci, line)); @@ -1364,15 +1385,15 @@ void document_replace_sel(gint idx, const gchar *find_text, const gchar *replace if (selection_end != -1) replaced = TRUE; } - + if (replaced) { // update the selection for the new endpoint - + if (selection_mode == SC_SEL_RECTANGLE && selected_lines > 1) { // now we can scroll to the selection and destroy it because we rebuild it later //sci_goto_pos(doc_list[idx].sci, selection_start, FALSE); - + // Note: the selection will be wrapped to last_line + 1 if max_column is greater than // the highest column on the last line. The wrapped selection is completely different // from the original one, so skip the selection at all @@ -1388,12 +1409,12 @@ void document_replace_sel(gint idx, const gchar *find_text, const gchar *replace sci_set_selection_mode(doc_list[idx].sci, selection_mode); } } - else + else { sci_set_selection_start(doc_list[idx].sci, selection_start); sci_set_selection_end(doc_list[idx].sci, selection_end); } - } + } else // no replacements utils_beep(); } @@ -1563,7 +1584,9 @@ void document_set_filetype(gint idx, filetype *type) document_update_tag_list(idx, TRUE); if (! delay_colourise) { - if (colourise && ! update_type_keywords(doc_list[idx].sci)) + /* Check if project typename keywords have changed. + * If they haven't, we may need to colourise the document. */ + if (! update_type_keywords(doc_list[idx].sci) && colourise) sci_colourise(doc_list[idx].sci, 0, -1); } } @@ -2069,31 +2092,67 @@ document *doc(gint idx) #endif +static GArray *doc_indexes = NULL; + +/* Cache the current document indexes and prevent any colourising until + * document_colourise_new() is called. */ void document_delay_colourise() { - g_return_if_fail(delay_colourise == FALSE); + gint n; + g_return_if_fail(delay_colourise == FALSE); + g_return_if_fail(doc_indexes == NULL); + + // make an array containing all the current document indexes + doc_indexes = g_array_new(FALSE, FALSE, sizeof(gint)); + for (n = 0; n < (gint) doc_array->len; n++) + { + if (DOC_IDX_VALID(n)) + g_array_append_val(doc_indexes, n); + } delay_colourise = TRUE; } -void document_colourise_all() +/* Colourise only newly opened documents and existing documents whose project typenames + * keywords have changed. + * document_delay_colourise() should already have been called. */ +void document_colourise_new() { - guint n; + guint n, i; + /* A bitset representing which docs need [re]colourising. + * (use gint8 to save memory because gboolean = gint) */ + gint8 *doc_set = g_newa(gint8, doc_array->len); + gboolean recolour = FALSE; // whether to recolourise existing typenames g_return_if_fail(delay_colourise == TRUE); + g_return_if_fail(doc_indexes != NULL); - // update typenames if necessary - update_type_keywords(NULL); + // first assume recolourising all docs + memset(doc_set, TRUE, doc_array->len * sizeof(gint8)); + // remove existing docs from the set if they don't use typenames or typenames haven't changed + recolour = update_type_keywords(NULL); + for (i = 0; i < doc_indexes->len; i++) + { + ScintillaObject *sci; + + n = g_array_index(doc_indexes, gint, i); + sci = doc_list[n].sci; + if (! recolour || (sci && sci_cb_lexer_get_type_keyword_idx(sci_get_lexer(sci)) == -1)) + { + doc_set[n] = FALSE; + } + } + // colourise all in the doc_set for (n = 0; n < doc_array->len; n++) { - ScintillaObject *sci = doc_list[n].sci; - - if (sci) - sci_colourise(sci, 0, -1); + if (doc_set[n] && doc_list[n].is_valid) + sci_colourise(doc_list[n].sci, 0, -1); } delay_colourise = FALSE; + g_array_free(doc_indexes, TRUE); + doc_indexes = NULL; } diff --git a/src/document.h b/src/document.h index 72272209..9053fd09 100644 --- a/src/document.h +++ b/src/document.h @@ -116,7 +116,7 @@ void document_init_doclist(); void document_finalize(); -void document_set_text_changed(gint); +void document_set_text_changed(gint idx); // Apply just the prefs that can change in the Preferences dialog @@ -134,19 +134,23 @@ gboolean document_remove(guint page_num); gint document_new_file(const gchar *filename, filetype *ft); -/* If idx is set to -1, it creates a new tab, opens the file from filename and - * set the cursor to pos. - * If idx is greater than -1, it reloads the file in the tab corresponding to - * idx and set the cursor to position 0. In this case, filename should be NULL - * It returns the idx of the opened file or -1 if an error occurred. - */ -gint document_open_file(gint, const gchar*, gint, gboolean, filetype*, const gchar*); - +/* To open a new file, set idx to -1; filename should be locale encoded. + * To reload a file, set the idx for the document to be reloaded; filename should be NULL. + * Returns: idx of the opened file or -1 if an error occurred. + * Note: If opening more than one file, document_delay_colourise() should be used before + * and document_colourise_new() after opening to avoid unnecessary recolourising. */ +gint document_open_file(gint idx, const gchar *filename, gint pos, gboolean readonly, + filetype *ft, const gchar *forced_enc); /* Takes a new line separated list of filename URIs and opens each file. * length is the length of the string or -1 if it should be detected */ void document_open_file_list(const gchar *data, gssize length); +/* Takes a linked list of filename URIs and opens each file, ensuring the newly opened + * documents and existing documents (if necessary) are only colourised once. */ +void document_open_files(const GSList *filenames, gboolean readonly, filetype *ft, + const gchar *forced_enc); + gint document_reload_file(gint idx, const gchar *forced_enc); @@ -170,15 +174,17 @@ gint document_replace_text(gint idx, const gchar *find_text, const gchar *replac gboolean document_replace_all(gint idx, const gchar *find_text, const gchar *replace_text, gint flags, gboolean escaped_chars); -void document_replace_sel(gint, const gchar*, const gchar*, gint, gboolean); +void document_replace_sel(gint idx, const gchar *find_text, const gchar *replace_text, gint flags, + gboolean escaped_chars); -void document_set_font(gint, const gchar*, gint); +void document_set_font(gint idx, const gchar *font_name, gint size); -void document_update_tag_list(gint, gboolean); +void document_update_tag_list(gint idx, gboolean update); -void document_set_filetype(gint, filetype*); +/* sets the filetype of the document (sets syntax highlighting and tagging) */ +void document_set_filetype(gint idx, filetype *type); -gchar *document_get_eol_mode(gint); +gchar *document_get_eol_mode(gint idx); void document_fold_all(gint idx); @@ -238,6 +244,6 @@ GdkColor *document_get_status(gint idx); void document_delay_colourise(); -void document_colourise_all(); +void document_colourise_new(); #endif diff --git a/src/keyfile.c b/src/keyfile.c index c5dd24ed..94eec470 100644 --- a/src/keyfile.c +++ b/src/keyfile.c @@ -574,7 +574,7 @@ gboolean configuration_open_files() if (i < 0) break; } } - document_colourise_all(); + document_colourise_new(); g_ptr_array_free(session_files, TRUE); if (failure) diff --git a/src/main.c b/src/main.c index 82947d78..8c7b5313 100644 --- a/src/main.c +++ b/src/main.c @@ -531,7 +531,7 @@ static gboolean open_cl_files(gint argc, gchar **argv) } g_free(filename); } - document_colourise_all(); + document_colourise_new(); return TRUE; } diff --git a/src/socket.c b/src/socket.c index c80be22e..31584823 100644 --- a/src/socket.c +++ b/src/socket.c @@ -409,6 +409,8 @@ gboolean socket_lock_input_cb(GIOChannel *source, GIOCondition condition, gpoint { if (strncmp(buf, "open", 4) == 0) { + document_delay_colourise(); + while (socket_fd_gets(sock, buf, sizeof(buf)) != -1 && *buf != '.') { g_strstrip(buf); // remove \n char @@ -426,6 +428,8 @@ gboolean socket_lock_input_cb(GIOChannel *source, GIOCondition condition, gpoint geany_debug("got data from socket, but it does not look like a filename"); } } + document_colourise_new(); + gtk_window_deiconify(GTK_WINDOW(app->window)); #ifdef G_OS_WIN32 gtk_window_present(GTK_WINDOW(app->window)); @@ -436,7 +440,7 @@ gboolean socket_lock_input_cb(GIOChannel *source, GIOCondition condition, gpoint while (socket_fd_gets(sock, buf, sizeof(buf)) != -1 && *buf != '.') { g_strstrip(buf); // remove \n char - // on any error we get 0 which should be save enough as fallback + // on any error we get 0 which should be safe enough as fallback cl_options.goto_line = atoi(buf); } } @@ -445,7 +449,7 @@ gboolean socket_lock_input_cb(GIOChannel *source, GIOCondition condition, gpoint while (socket_fd_gets(sock, buf, sizeof(buf)) != -1 && *buf != '.') { g_strstrip(buf); // remove \n char - // on any error we get 0 which should be save enough as fallback + // on any error we get 0 which should be safe enough as fallback cl_options.goto_column = atoi(buf); } } diff --git a/src/win32.c b/src/win32.c index ad2faade..acb88999 100644 --- a/src/win32.c +++ b/src/win32.c @@ -311,7 +311,9 @@ gboolean win32_show_file_dialog(gboolean file_open) document_open_file(-1, fname, 0, of.Flags & OFN_READONLY, NULL, NULL); } else - { // open mutiple files + { // open multiple files + document_delay_colourise(); + for (; ;) { if (! fname[x]) @@ -323,6 +325,7 @@ gboolean win32_show_file_dialog(gboolean file_open) } x++; } + document_colourise_new(); } } else