Branch: refs/heads/master Author: LarsGit223 lars_paulsen@web.de Committer: LarsGit223 lars_paulsen@web.de Date: Sun, 19 May 2019 16:45:04 UTC Commit: a4e68e67d14d4c7d710acd4ecc9d7c7a484968cf https://github.com/geany/geany-plugins/commit/a4e68e67d14d4c7d710acd4ecc9d7c...
Log Message: ----------- workbench: revised tag-manager control/usage
This commit moves all access to TMSourceFiles/the tagmanager API into a dedicated file 'tm_control.c'. Calls from the workbench plugin to the tag-manager API may now only appear in this file. Also all calls are synced using a idle-queue managed in 'idle_queue.c' (using 'plugin_idle_add()'). This way the file lists in the workbench projects is completely de-coupled of any TMSourceFile related data/references. Fixes #866.
(Calls to the tag-manager API were synced before also. But the implementation was not very clean and therefore contained errors/code where the tag-manager API was called directly - which could lead to crashes)
Modified Paths: -------------- workbench/src/Makefile.am workbench/src/idle_queue.c workbench/src/idle_queue.h workbench/src/plugin_main.c workbench/src/tm_control.c workbench/src/tm_control.h workbench/src/wb_project.c workbench/src/wb_project.h
Modified: workbench/src/Makefile.am 6 lines changed, 5 insertions(+), 1 deletions(-) =================================================================== @@ -22,7 +22,11 @@ workbench_la_SOURCES = \ sidebar.h \ sidebar.c \ utils.h \ - utils.c + utils.c \ + idle_queue.h \ + idle_queue.c \ + tm_control.h \ + tm_control.c
workbench_la_CPPFLAGS = $(AM_CPPFLAGS) \ -DG_LOG_DOMAIN="Workbench"
Modified: workbench/src/idle_queue.c 134 lines changed, 134 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,134 @@ +/* + * Copyright 2019 LarsGit223 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Code for the Workbench idle queue. + */ +#include <glib/gstdio.h> + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <geanyplugin.h> +#include "wb_globals.h" +#include "idle_queue.h" +#include "tm_control.h" + +extern GeanyData *geany_data; + +typedef struct +{ + WB_IDLE_QUEUE_ACTION_ID id; + gpointer param_a; +}WB_IDLE_QUEUE_ACTION; + +static GSList *s_idle_actions = NULL; + + +/* Clear idle queue */ +static void wb_idle_queue_clear(void) +{ + if (s_idle_actions == NULL) + { + return; + } + + g_slist_free_full(s_idle_actions, g_free); + s_idle_actions = NULL; +} + + +/* On-idle callback function. */ +static gboolean wb_idle_queue_callback(gpointer foo) +{ + static gboolean first = TRUE; + GSList *elem = NULL; + WB_IDLE_QUEUE_ACTION *action; + static GMutex mutex; + + if (first == TRUE) + { + first = FALSE; + g_mutex_init (&mutex); + } + + g_mutex_lock(&mutex); + + foreach_slist (elem, s_idle_actions) + { + action = elem->data; + switch (action->id) + { + case WB_IDLE_ACTION_ID_TM_SOURCE_FILES_NEW: + wb_tm_control_source_files_new(action->param_a); + break; + + case WB_IDLE_ACTION_ID_TM_SOURCE_FILE_ADD: + wb_tm_control_source_file_add(action->param_a); + break; + + case WB_IDLE_ACTION_ID_TM_SOURCE_FILE_REMOVE: + wb_tm_control_source_file_remove(action->param_a); + break; + + case WB_IDLE_ACTION_ID_TM_SOURCE_FILE_FREE: + wb_tm_control_source_file_free(action->param_a); + break; + + case WB_IDLE_ACTION_ID_TM_SOURCE_FILES_REMOVE: + wb_tm_control_source_files_remove(action->param_a); + break; + } + } + + wb_idle_queue_clear(); + + g_mutex_unlock(&mutex); + + return FALSE; +} + + +/** Add a new idle action to the list. + * + * The function allocates a new WB_IDLE_QUEUE_ACTION structure and fills + * in the values passed. On-idle Geany will then call wb_idle_queue_callback + * and that function will call the function related to the action ID + * and pass the relevant parameters to it. + * + * @param id The action to execute on-idle + * @param param_a Parameter A + * @param param_a Parameter B + * + **/ +void wb_idle_queue_add_action(WB_IDLE_QUEUE_ACTION_ID id, gpointer param_a) +{ + WB_IDLE_QUEUE_ACTION *action; + + action = g_new0(WB_IDLE_QUEUE_ACTION, 1); + action->id = id; + action->param_a = param_a; + + if (s_idle_actions == NULL) + { + plugin_idle_add(wb_globals.geany_plugin, (GSourceFunc)wb_idle_queue_callback, NULL); + } + + s_idle_actions = g_slist_prepend(s_idle_actions, action); +}
Modified: workbench/src/idle_queue.h 33 lines changed, 33 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,33 @@ +/* + * Copyright 2019 LarsGit223 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __WB_IDLE_QUEUE_H__ +#define __WB_IDLE_QUEUE_H__ + +typedef enum +{ + WB_IDLE_ACTION_ID_TM_SOURCE_FILE_ADD, + WB_IDLE_ACTION_ID_TM_SOURCE_FILE_REMOVE, + WB_IDLE_ACTION_ID_TM_SOURCE_FILE_FREE, + WB_IDLE_ACTION_ID_TM_SOURCE_FILES_NEW, + WB_IDLE_ACTION_ID_TM_SOURCE_FILES_REMOVE, +}WB_IDLE_QUEUE_ACTION_ID; + +void wb_idle_queue_add_action(WB_IDLE_QUEUE_ACTION_ID id, gpointer param_a); + +#endif
Modified: workbench/src/plugin_main.c 31 lines changed, 9 insertions(+), 22 deletions(-) =================================================================== @@ -31,6 +31,8 @@ #include "sidebar.h" #include "menu.h" #include "popup_menu.h" +#include "idle_queue.h" +#include "tm_control.h"
GeanyPlugin *geany_plugin; GeanyData *geany_data; @@ -39,40 +41,23 @@ GeanyData *geany_data; static void plugin_workbench_on_doc_open(G_GNUC_UNUSED GObject * obj, G_GNUC_UNUSED GeanyDocument * doc, G_GNUC_UNUSED gpointer user_data) { - WB_PROJECT *project; - g_return_if_fail(doc != NULL && doc->file_name != NULL);
- project = workbench_file_is_included(wb_globals.opened_wb, doc->file_name); - if (project != NULL) - { - wb_project_add_idle_action(WB_PROJECT_IDLE_ACTION_ID_REMOVE_SINGLE_TM_FILE, - project, g_strdup(doc->file_name)); - } + wb_idle_queue_add_action(WB_IDLE_ACTION_ID_TM_SOURCE_FILE_REMOVE, + g_strdup(doc->file_name)); }
/* Callback function for document close */ static void plugin_workbench_on_doc_close(G_GNUC_UNUSED GObject * obj, GeanyDocument * doc, G_GNUC_UNUSED gpointer user_data) { - WB_PROJECT *project; - - g_return_if_fail(doc != NULL); - - if (doc->file_name == NULL) - { - return; - } + g_return_if_fail(doc != NULL && doc->file_name != NULL);
/* tags of open files managed by geany - when the file gets closed, * we should take care of it */ - project = workbench_file_is_included(wb_globals.opened_wb, doc->file_name); - if (project != NULL) - { - wb_project_add_idle_action(WB_PROJECT_IDLE_ACTION_ID_ADD_SINGLE_TM_FILE, - project, g_strdup(doc->file_name)); - } + wb_idle_queue_add_action(WB_IDLE_ACTION_ID_TM_SOURCE_FILE_ADD, + g_strdup(doc->file_name)); }
@@ -88,6 +73,7 @@ static gboolean plugin_workbench_init(GeanyPlugin *plugin, G_GNUC_UNUSED gpointe menu_init(); sidebar_init(); popup_menu_init(); + wb_tm_control_init();
/* At start there is no workbench open: deactive save and close menu item and sidebar */ @@ -103,6 +89,7 @@ static void plugin_workbench_cleanup(G_GNUC_UNUSED GeanyPlugin *plugin, G_GNUC_U { menu_cleanup(); sidebar_cleanup(); + wb_tm_control_cleanup(); }
Modified: workbench/src/tm_control.c 243 lines changed, 243 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,243 @@ +/* + * Copyright 2017 LarsGit223 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Code for the Workbench internal tag-manager-control. + */ +#include <glib/gstdio.h> + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <geanyplugin.h> +#include "idle_queue.h" + +extern GeanyData *geany_data; +static GHashTable *wb_tm_file_table = NULL; + + +/* Callback function for freeing a file table entry. The entry must + be freed using the tag-manager in a syncronized way. So we do + not make the call here directly but use our idle-action-queue. */ +static void free_file_table_entry (gpointer data) +{ + wb_idle_queue_add_action(WB_IDLE_ACTION_ID_TM_SOURCE_FILE_FREE, data); +} + + +/** Initialize tm-control data. + **/ +void wb_tm_control_init (void) +{ + wb_tm_file_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GFreeFunc)free_file_table_entry); +} + + +/** Cleanup tm-control data. + **/ +void wb_tm_control_cleanup (void) +{ + wb_tm_file_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GFreeFunc)free_file_table_entry); +} + + +/** Add the file to the tm-workspace. + * + * @param filename Name of the file to add. + **/ +void wb_tm_control_source_file_add(gchar *filename) +{ + TMSourceFile *sf = g_hash_table_lookup(wb_tm_file_table, filename); + + if (sf != NULL && !document_find_by_filename(filename)) + { + tm_workspace_add_source_file(sf); + g_hash_table_insert (wb_tm_file_table, g_strdup(filename), sf); + } + g_free(filename); +} + + +/** Remove the file from the tm-workspace. + * + * @param filename Name of the file to add. + **/ +void wb_tm_control_source_file_remove(gchar *filename) +{ + TMSourceFile *sf = g_hash_table_lookup(wb_tm_file_table, filename); + if (sf != NULL) + { + tm_workspace_remove_source_file(sf); + g_hash_table_remove(wb_tm_file_table, filename); + } + g_free(filename); +} + + +/** Free a TMSourceFile + * + * @param source_file The file to be freed + **/ +void wb_tm_control_source_file_free(TMSourceFile *source_file) +{ + tm_source_file_free(source_file); +} + + +/** Remove the files from the tm-workspace. + * + * @param files GPtrArray of file names (gchar *) + **/ +void wb_tm_control_source_files_remove(GPtrArray *files) +{ + GPtrArray *source_files; + TMSourceFile *sf; + guint index; + + source_files = g_ptr_array_new(); + for (index = 0 ; index < files->len ; index++) + { + gchar *utf8_path = files->pdata[index]; + gchar *locale_path = utils_get_locale_from_utf8(utf8_path); + + sf = g_hash_table_lookup(wb_tm_file_table, locale_path); + if (sf != NULL) + { + g_ptr_array_add(source_files, sf); + g_hash_table_remove(wb_tm_file_table, locale_path); + } + + g_free(locale_path); + } + + tm_workspace_remove_source_files(files); + g_ptr_array_free(source_files, TRUE); + g_ptr_array_free(files, TRUE); +} + + +/* Check if filename matches filetpye patterns */ +static gboolean match_basename(gconstpointer pft, gconstpointer user_data) +{ + const GeanyFiletype *ft = pft; + const gchar *utf8_base_filename = user_data; + gint j; + gboolean ret = FALSE; + + if (G_UNLIKELY(ft->id == GEANY_FILETYPES_NONE)) + return FALSE; + + for (j = 0; ft->pattern[j] != NULL; j++) + { + GPatternSpec *pattern = g_pattern_spec_new(ft->pattern[j]); + + if (g_pattern_match_string(pattern, utf8_base_filename)) + { + ret = TRUE; + g_pattern_spec_free(pattern); + break; + } + g_pattern_spec_free(pattern); + } + return ret; +} + + +/* Stolen and modified version from Geany. The only difference is that Geany + * first looks at shebang inside the file and then, if it fails, checks the + * file extension. Opening every file is too expensive so instead check just + * extension and only if this fails, look at the shebang */ +static GeanyFiletype *filetypes_detect(const gchar *utf8_filename) +{ + struct stat s; + GeanyFiletype *ft = NULL; + gchar *locale_filename; + + locale_filename = utils_get_locale_from_utf8(utf8_filename); + if (g_stat(locale_filename, &s) != 0 || s.st_size > 10*1024*1024) + ft = filetypes[GEANY_FILETYPES_NONE]; + else + { + guint i; + gchar *utf8_base_filename; + + /* to match against the basename of the file (because of Makefile*) */ + utf8_base_filename = g_path_get_basename(utf8_filename); +#ifdef G_OS_WIN32 + /* use lower case basename */ + SETPTR(utf8_base_filename, g_utf8_strdown(utf8_base_filename, -1)); +#endif + + for (i = 0; i < geany_data->filetypes_array->len; i++) + { + GeanyFiletype *ftype = filetypes[i]; + + if (match_basename(ftype, utf8_base_filename)) + { + ft = ftype; + break; + } + } + + if (ft == NULL) + ft = filetypes_detect_from_file(utf8_filename); + + g_free(utf8_base_filename); + } + + g_free(locale_filename); + + return ft; +} + + +/** Add the files to the tm-workspace. + * + * @param files GPtrArray of file names (gchar *) + **/ +void wb_tm_control_source_files_new(GPtrArray *files) +{ + GPtrArray *source_files; + TMSourceFile *sf; + guint index; + + source_files = g_ptr_array_new(); + for (index = 0 ; index < files->len ; index++) + { + gchar *utf8_path = files->pdata[index]; + gchar *locale_path = utils_get_locale_from_utf8(utf8_path); + + sf = g_hash_table_lookup(wb_tm_file_table, locale_path); + if (sf == NULL) + { + sf = tm_source_file_new(locale_path, filetypes_detect(utf8_path)->name); + if (sf != NULL && !document_find_by_filename(utf8_path)) + { + g_ptr_array_add(source_files, sf); + g_hash_table_insert (wb_tm_file_table, g_strdup(locale_path), sf); + } + } + + g_free(locale_path); + } + + tm_workspace_add_source_files(source_files); + g_ptr_array_free(source_files, TRUE); + g_ptr_array_free(files, TRUE); +}
Modified: workbench/src/tm_control.h 31 lines changed, 31 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,31 @@ +/* + * Copyright 2017 LarsGit223 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __WB_TM_CONTROL_H__ +#define __WB_TM_CONTROL_H__ + +void wb_tm_control_init (void); +void wb_tm_control_cleanup (void); +void wb_tm_control_source_file_add(const gchar *filename); +void wb_tm_control_source_file_remove(const gchar *filename); +void wb_tm_control_source_files_remove(GPtrArray *files); +void wb_tm_control_source_files_new(GPtrArray *files); + +void wb_tm_control_source_file_free(TMSourceFile *source_file); + +#endif
Modified: workbench/src/wb_project.c 346 lines changed, 47 insertions(+), 299 deletions(-) =================================================================== @@ -31,6 +31,7 @@ #include "wb_project.h" #include "sidebar.h" #include "utils.h" +#include "idle_queue.h"
extern GeanyData *geany_data;
@@ -41,13 +42,6 @@ typedef enum WB_PROJECT_TAG_PREFS_NO, }WB_PROJECT_TAG_PREFS;
-typedef struct -{ - WB_PROJECT_IDLE_ACTION_ID id; - gpointer param_a; - gpointer param_b; -}WB_PROJECT_IDLE_ACTION; - typedef struct { GKeyFile *kf; @@ -63,7 +57,7 @@ struct S_WB_PROJECT_DIR gchar **ignored_file_patterns; guint file_count; guint subdir_count; - GHashTable *file_table; /* contains all file names within base_dir, maps file_name->TMSourceFile */ + GHashTable *file_table; /* contains all file names within base_dir */ gboolean is_prj_base_dir; };
@@ -72,8 +66,6 @@ struct S_WB_PROJECT gchar *filename; gchar *name; gboolean modified; - //GSList *s_idle_add_funcs; - //GSList *s_idle_remove_funcs; GSList *directories; /* list of WB_PROJECT_DIR; */ WB_PROJECT_TAG_PREFS generate_tag_prefs; GPtrArray *bookmarks; @@ -85,8 +77,6 @@ typedef struct const gchar *string; }WB_PROJECT_TEMP_DATA;
-static GSList *s_idle_actions = NULL; -static void wb_project_dir_update_tags(WB_PROJECT_DIR *root);
/** Set the projects modified marker. * @@ -200,46 +190,6 @@ GSList *wb_project_get_directories(WB_PROJECT *prj) }
-/* Check if filename matches filetpye patterns */ -static gboolean match_basename(gconstpointer pft, gconstpointer user_data) -{ - const GeanyFiletype *ft = pft; - const gchar *utf8_base_filename = user_data; - gint j; - gboolean ret = FALSE; - - if (G_UNLIKELY(ft->id == GEANY_FILETYPES_NONE)) - return FALSE; - - for (j = 0; ft->pattern[j] != NULL; j++) - { - GPatternSpec *pattern = g_pattern_spec_new(ft->pattern[j]); - - if (g_pattern_match_string(pattern, utf8_base_filename)) - { - ret = TRUE; - g_pattern_spec_free(pattern); - break; - } - g_pattern_spec_free(pattern); - } - return ret; -} - - -/* Clear idle queue */ -static void wb_project_clear_idle_queue(void) -{ - if (s_idle_actions == NULL) - { - return; - } - - g_slist_free_full(s_idle_actions, g_free); - s_idle_actions = NULL; -} - - /* Create a new project dir with base path "utf8_base_dir" */ static WB_PROJECT_DIR *wb_project_dir_new(WB_PROJECT *prj, const gchar *utf8_base_dir) { @@ -251,7 +201,7 @@ static WB_PROJECT_DIR *wb_project_dir_new(WB_PROJECT *prj, const gchar *utf8_bas } WB_PROJECT_DIR *dir = g_new0(WB_PROJECT_DIR, 1); dir->base_dir = g_strdup(utf8_base_dir); - dir->file_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GFreeFunc)tm_source_file_free); + dir->file_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
offset = strlen(dir->base_dir)-1; while (offset > 0 @@ -272,12 +222,10 @@ static WB_PROJECT_DIR *wb_project_dir_new(WB_PROJECT *prj, const gchar *utf8_bas
/* Collect source files */ -static void wb_project_dir_collect_source_files(G_GNUC_UNUSED gchar *filename, TMSourceFile *sf, gpointer user_data) +static void wb_project_dir_collect_source_files(G_GNUC_UNUSED gchar *filename, gpointer *value, gpointer user_data) { GPtrArray *array = user_data; - - if (sf != NULL) - g_ptr_array_add(array, sf); + g_ptr_array_add(array, g_strdup(filename)); }
@@ -470,12 +418,11 @@ gboolean wb_project_dir_set_ignored_file_patterns (WB_PROJECT_DIR *directory, gc /* Remove all files contained in the project dir from the tm-workspace */ static void wb_project_dir_remove_from_tm_workspace(WB_PROJECT_DIR *root) { - GPtrArray *source_files; + GPtrArray *files;
- source_files = g_ptr_array_new(); - g_hash_table_foreach(root->file_table, (GHFunc)wb_project_dir_collect_source_files, source_files); - tm_workspace_remove_source_files(source_files); - g_ptr_array_free(source_files, TRUE); + files = g_ptr_array_new(); + g_hash_table_foreach(root->file_table, (GHFunc)wb_project_dir_collect_source_files, files); + wb_idle_queue_add_action(WB_IDLE_ACTION_ID_TM_SOURCE_FILES_REMOVE, files); }
@@ -556,7 +503,7 @@ static guint wb_project_dir_rescan_int(WB_PROJECT *prj, WB_PROJECT_DIR *root)
if (path) { - g_hash_table_insert(root->file_table, g_strdup(path), NULL); + g_hash_table_add(root->file_table, g_strdup(path)); filenum++; } } @@ -590,7 +537,7 @@ static void wb_project_dir_add_file_int(WB_PROJECT *prj, WB_PROJECT_DIR *root, c }
/* Update file table and counters. */ - g_hash_table_insert(root->file_table, g_strdup(filepath), NULL); + g_hash_table_add(root->file_table, g_strdup(filepath)); if (g_file_test(filepath, G_FILE_TEST_IS_DIR)) { root->subdir_count++; @@ -635,6 +582,32 @@ static void wb_project_dir_add_file_int(WB_PROJECT *prj, WB_PROJECT_DIR *root, c }
+/* Update tags for new files */ +static void wb_project_dir_update_tags(WB_PROJECT_DIR *root) +{ + GHashTableIter iter; + gpointer key, value; + GPtrArray *files; + + files = g_ptr_array_new_full(1, g_free); + g_hash_table_iter_init(&iter, root->file_table); + while (g_hash_table_iter_next(&iter, &key, &value)) + { + if (value == NULL) + { + gchar *utf8_path = key; + gchar *locale_path = utils_get_locale_from_utf8(utf8_path); + + g_ptr_array_add(files, g_strdup(key)); + g_hash_table_add(root->file_table, g_strdup(utf8_path)); + g_free(locale_path); + } + } + + wb_idle_queue_add_action(WB_IDLE_ACTION_ID_TM_SOURCE_FILES_NEW, files); +} + + /** Add a new file to the project directory and update the sidebar. * * The file is only added if it matches the pattern settings. @@ -647,17 +620,14 @@ static void wb_project_dir_add_file_int(WB_PROJECT *prj, WB_PROJECT_DIR *root, c void wb_project_dir_add_file(WB_PROJECT *prj, WB_PROJECT_DIR *root, const gchar *filepath) { wb_project_dir_add_file_int(prj, root, filepath); - wb_project_add_idle_action(WB_PROJECT_IDLE_ACTION_ID_UPDATE_TAGS, - root, NULL); - + wb_project_dir_update_tags(root); }
/* Check if the filepath is equal for the length of the directory path in px_temp */ static gboolean wb_project_dir_remove_child (gpointer key, gpointer value, gpointer user_data) { WB_PROJECT_TEMP_DATA *px_temp; - TMSourceFile *sf;
px_temp = user_data; if (strncmp(px_temp->string, key, px_temp->len) == 0) @@ -666,11 +636,7 @@ static gboolean wb_project_dir_remove_child (gpointer key, gpointer value, gpoin Remove it from the hash table. This will also free the tags. We do not need to update the sidebar as we already deleted the parent directory/node. */ - sf = value; - if (sf != NULL) - { - tm_workspace_remove_source_file(sf); - } + wb_idle_queue_add_action(WB_IDLE_ACTION_ID_TM_SOURCE_FILE_REMOVE, g_strdup(key)); return TRUE; } return FALSE; @@ -711,14 +677,10 @@ void wb_project_dir_remove_file(WB_PROJECT *prj, WB_PROJECT_DIR *root, const gch if (matches) { SIDEBAR_CONTEXT context; - TMSourceFile *sf;
/* Update file table and counters. */ - sf = g_hash_table_lookup (root->file_table, filepath); - if (sf != NULL) - { - tm_workspace_remove_source_file(sf); - } + wb_idle_queue_add_action(WB_IDLE_ACTION_ID_TM_SOURCE_FILE_REMOVE, + g_strdup(filepath)); g_hash_table_remove(root->file_table, filepath);
/* If the file already has been deleted, we cannot determine if it @@ -763,121 +725,31 @@ void wb_project_dir_remove_file(WB_PROJECT *prj, WB_PROJECT_DIR *root, const gch }
-/* Stolen and modified version from Geany. The only difference is that Geany - * first looks at shebang inside the file and then, if it fails, checks the - * file extension. Opening every file is too expensive so instead check just - * extension and only if this fails, look at the shebang */ -static GeanyFiletype *filetypes_detect(const gchar *utf8_filename) -{ - struct stat s; - GeanyFiletype *ft = NULL; - gchar *locale_filename; - - locale_filename = utils_get_locale_from_utf8(utf8_filename); - if (g_stat(locale_filename, &s) != 0 || s.st_size > 10*1024*1024) - ft = filetypes[GEANY_FILETYPES_NONE]; - else - { - guint i; - gchar *utf8_base_filename; - - /* to match against the basename of the file (because of Makefile*) */ - utf8_base_filename = g_path_get_basename(utf8_filename); -#ifdef G_OS_WIN32 - /* use lower case basename */ - SETPTR(utf8_base_filename, g_utf8_strdown(utf8_base_filename, -1)); -#endif - - for (i = 0; i < geany_data->filetypes_array->len; i++) - { - GeanyFiletype *ftype = filetypes[i]; - - if (match_basename(ftype, utf8_base_filename)) - { - ft = ftype; - break; - } - } - - if (ft == NULL) - ft = filetypes_detect_from_file(utf8_filename); - - g_free(utf8_base_filename); - } - - g_free(locale_filename); - - return ft; -} - - /* Regenerate tags */ static void wb_project_dir_regenerate_tags(WB_PROJECT_DIR *root, G_GNUC_UNUSED gpointer user_data) { GHashTableIter iter; gpointer key, value; - GPtrArray *source_files; + GPtrArray *files; GHashTable *file_table;
- source_files = g_ptr_array_new(); - file_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GFreeFunc)tm_source_file_free); + files = g_ptr_array_new_full (1, g_free); + file_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); g_hash_table_iter_init(&iter, root->file_table); while (g_hash_table_iter_next(&iter, &key, &value)) { - TMSourceFile *sf; - - sf = NULL; if (g_file_test(key, G_FILE_TEST_IS_REGULAR)) { - gchar *utf8_path = key; - gchar *locale_path = utils_get_locale_from_utf8(utf8_path); - - sf = tm_source_file_new(locale_path, filetypes_detect(utf8_path)->name); - if (sf && !document_find_by_filename(utf8_path)) - g_ptr_array_add(source_files, sf); - - g_free(locale_path); + g_ptr_array_add(files, g_strdup(key)); }
/* Add all files to the file-table (files and dirs)! */ - g_hash_table_insert(file_table, g_strdup(key), sf); + g_hash_table_add(file_table, g_strdup(key)); } g_hash_table_destroy(root->file_table); root->file_table = file_table;
- tm_workspace_add_source_files(source_files); - g_ptr_array_free(source_files, TRUE); -} - - -/* Update tags for new files */ -static void wb_project_dir_update_tags(WB_PROJECT_DIR *root) -{ - GHashTableIter iter; - gpointer key, value; - GPtrArray *source_files; - - source_files = g_ptr_array_new(); - g_hash_table_iter_init(&iter, root->file_table); - while (g_hash_table_iter_next(&iter, &key, &value)) - { - if (value == NULL) - { - TMSourceFile *sf; - gchar *utf8_path = key; - gchar *locale_path = utils_get_locale_from_utf8(utf8_path); - - sf = tm_source_file_new(locale_path, filetypes_detect(utf8_path)->name); - if (sf && !document_find_by_filename(utf8_path)) - g_ptr_array_add(source_files, sf); - - g_hash_table_insert(root->file_table, g_strdup(utf8_path), sf); - g_free(locale_path); - } - } - - tm_workspace_add_source_files(source_files); - g_ptr_array_free(source_files, TRUE); + wb_idle_queue_add_action(WB_IDLE_ACTION_ID_TM_SOURCE_FILES_NEW, files); }
@@ -918,8 +790,6 @@ void wb_project_rescan(WB_PROJECT *prj) return; }
- wb_project_clear_idle_queue(); - foreach_slist(elem, prj->directories) { filenum += wb_project_dir_rescan_int(prj, elem->data); @@ -1013,128 +883,6 @@ gboolean wb_project_file_is_included(WB_PROJECT *prj, const gchar *filename) }
-/* Add single tm file. Only to be called on-idle! */ -static void wb_project_add_single_tm_file(WB_PROJECT *prj, const gchar *filename) -{ - GSList *elem = NULL; - - foreach_slist (elem, prj->directories) - { - WB_PROJECT_DIR *dir = elem->data; - TMSourceFile *sf = g_hash_table_lookup(dir->file_table, filename); - - if (sf != NULL && !document_find_by_filename(filename)) - { - tm_workspace_add_source_file(sf); - break; /* single file representation in TM is enough */ - } - } -} - - -/* This function gets called when document is being opened by Geany and we need - * to remove the TMSourceFile from the tag manager because Geany inserts - * it for the newly open tab. Even though tag manager would handle two identical - * files, the file inserted by the plugin isn't updated automatically in TM - * so any changes wouldn't be reflected in the tags array (e.g. removed function - * from source file would still be found in TM) - * - * Additional problem: The document being opened may be caused - * by going to tag definition/declaration - tag processing is in progress - * when this function is called and if we remove the TmSourceFile now, line - * number for the searched tag won't be found. For this reason delay the tag - * TmSourceFile removal until idle */ -static void wb_project_remove_single_tm_file(WB_PROJECT *prj, const gchar *filename) -{ - GSList *elem = NULL; - - foreach_slist (elem, prj->directories) - { - WB_PROJECT_DIR *dir = elem->data; - TMSourceFile *sf = g_hash_table_lookup(dir->file_table, filename); - - if (sf != NULL) - { - tm_workspace_remove_source_file(sf); - } - } -} - - -/* On-idle callback function. */ -static gboolean wb_project_on_idle_callback(gpointer foo) -{ - GSList *elem = NULL; - WB_PROJECT_IDLE_ACTION *action; - - foreach_slist (elem, s_idle_actions) - { - action = elem->data; - switch (action->id) - { - case WB_PROJECT_IDLE_ACTION_ID_ADD_SINGLE_TM_FILE: - if (action->param_a != NULL && action->param_b != NULL) - { - wb_project_add_single_tm_file - (action->param_a, action->param_b); - g_free(action->param_b); - } - break; - - case WB_PROJECT_IDLE_ACTION_ID_REMOVE_SINGLE_TM_FILE: - if (action->param_a != NULL && action->param_b != NULL) - { - wb_project_remove_single_tm_file - (action->param_a, action->param_b); - g_free(action->param_b); - } - break; - - case WB_PROJECT_IDLE_ACTION_ID_UPDATE_TAGS: - if (action->param_a != NULL) - { - wb_project_dir_update_tags(action->param_a); - } - break; - } - } - - wb_project_clear_idle_queue(); - - return FALSE; -} - - -/** Add a new idle action to the list. - * - * The function allocates a new WB_PROJECT_IDLE_ACTION structure and fills - * in the values passed. On-idle genay will then call wb_project_on_idle_callback - * and that function will call the function related to the action ID - * and pass the relevant parameters to it. - * - * @param id The action to execute on-idle - * @param param_a Parameter A - * @param param_a Parameter B - * - **/ -void wb_project_add_idle_action(WB_PROJECT_IDLE_ACTION_ID id, gpointer param_a, gpointer param_b) -{ - WB_PROJECT_IDLE_ACTION *action; - - action = g_new0(WB_PROJECT_IDLE_ACTION, 1); - action->id = id; - action->param_a = param_a; - action->param_b = param_b; - - if (s_idle_actions == NULL) - { - plugin_idle_add(wb_globals.geany_plugin, (GSourceFunc)wb_project_on_idle_callback, NULL); - } - - s_idle_actions = g_slist_prepend(s_idle_actions, action); -} - - /* Add a directory to the project */ static WB_PROJECT_DIR *wb_project_add_directory_int(WB_PROJECT *prj, const gchar *dirname, gboolean rescan) {
Modified: workbench/src/wb_project.h 9 lines changed, 0 insertions(+), 9 deletions(-) =================================================================== @@ -21,13 +21,6 @@
#include <glib.h>
-typedef enum -{ - WB_PROJECT_IDLE_ACTION_ID_ADD_SINGLE_TM_FILE, - WB_PROJECT_IDLE_ACTION_ID_REMOVE_SINGLE_TM_FILE, - WB_PROJECT_IDLE_ACTION_ID_UPDATE_TAGS, -}WB_PROJECT_IDLE_ACTION_ID; - typedef struct S_WB_PROJECT WB_PROJECT; typedef struct S_WB_PROJECT_DIR WB_PROJECT_DIR;
@@ -75,6 +68,4 @@ gboolean wb_project_load(WB_PROJECT *prj, const gchar *filename, GError **error)
gchar *wb_project_get_info (WB_PROJECT *prj);
-void wb_project_add_idle_action(WB_PROJECT_IDLE_ACTION_ID id, gpointer param_a, gpointer param_b); - #endif
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).