diff --git a/geanylua/.clang-format b/geanylua/.clang-format new file mode 100644 index 000000000..e822e233d --- /dev/null +++ b/geanylua/.clang-format @@ -0,0 +1,4 @@ +BasedOnStyle: LLVM +TabWidth: 3 +IndentWidth: 3 +UseTab: ForContinuationAndIndentation diff --git a/geanylua/docs/geanylua-intro.html b/geanylua/docs/geanylua-intro.html index 526a13a38..bb8acbb86 100644 --- a/geanylua/docs/geanylua-intro.html +++ b/geanylua/docs/geanylua-intro.html @@ -22,6 +22,7 @@ You can create additional scripts yourself, but all script files must have names that end with the .lua file extension.   The menu labels are generated from the filenames like this: +

  1. The  .lua  filename extension is removed.
  2. If the filename begins with two decimal digits, followed by a dot, @@ -59,23 +60,45 @@
    The special directory  ./plugins/geanylua/events/  can contain some scripts that will be invoked whenever the respective event is triggered by Geany. -

    -Currently, there are nine valid filenames for the event scripts: -

    -
    init.lua  
    -- Runs when the plugin is loaded.
    -
    cleanup.lua  
    -- Runs when the plugin is unloaded.
    +(See Plugin Signals for more information.) +

    saved.lua  
    -- Runs when an open document is saved.
    -
    created.lua  
    -- Runs when a new document is created.
    -
    opened.lua  
    -- Runs when an existing file is opened.
    -
    activated.lua
    -- Runs when switching documents (notebook tabs).
    +
    +
    init.lua
    +
    -- Runs when the GeanyLua plugin is loaded.
    +
    cleanup.lua
    +
    -- Runs when the GeanyLua plugin is unloaded.
    +
    -
    proj-opened.lua  
    -- Runs when a project is opened.
    -
    proj-saved.lua  
    -- Runs when a project is saved.
    -
    proj-closed.lua  
    -- Runs when a project is closed.
    +
    +
    build-start.lua
    +
    editor-notify.lua
    +
    geany-startup-complete.lua
    +
    key-press.lua
    +
    update-editor-menu.lua
    +
    +
    +
    document-activate.lua
    +
    document-before-save.lua
    +
    document-close.lua
    +
    document-filetype-set.lua
    +
    document-new.lua
    +
    document-open.lua
    +
    document-reload.lua
    +
    document-save.lua
    +
    +
    +
    project-before-close.lua
    +
    project-close.lua
    +
    project-dialog-close.lua
    +
    project-dialog-confirmed.lua
    +
    project-dialog-open.lua
    +
    project-open.lua
    +
    project-save.lua
    +

    -Note that if any of these nine files exists, it will be executed each time +Note that if any of these files exists, it will be executed each time its corresponding event occurs, which will result in some increase in disk activity. In particular, you might notice a delay in startup time with the  opened.lua  script when you open a bunch of files at once from the commmand line, etc. @@ -83,11 +106,10 @@

    Consult the reference page for documentation of the Geany-specific Lua functions.

    - A complete discussion of the Lua language is way beyond the scope of this plugin package, but there is plenty of information available on the net, For starters, you can check out: -

      +

    @@ -126,6 +148,5 @@ if this happens, the only way out is to kill the editor.

    - diff --git a/geanylua/geanylua.c b/geanylua/geanylua.c index e9a2f1aa8..6c5916987 100644 --- a/geanylua/geanylua.c +++ b/geanylua/geanylua.c @@ -78,7 +78,20 @@ static PluginCallback *glspi_geany_callbacks = NULL; and all is well... */ PLUGIN_EXPORT -PluginCallback plugin_callbacks[8] = { +PluginCallback plugin_callbacks[21] = { + {NULL, NULL, FALSE, NULL}, + {NULL, NULL, FALSE, NULL}, + {NULL, NULL, FALSE, NULL}, + {NULL, NULL, FALSE, NULL}, + {NULL, NULL, FALSE, NULL}, + {NULL, NULL, FALSE, NULL}, + {NULL, NULL, FALSE, NULL}, + {NULL, NULL, FALSE, NULL}, + {NULL, NULL, FALSE, NULL}, + {NULL, NULL, FALSE, NULL}, + {NULL, NULL, FALSE, NULL}, + {NULL, NULL, FALSE, NULL}, + {NULL, NULL, FALSE, NULL}, {NULL, NULL, FALSE, NULL}, {NULL, NULL, FALSE, NULL}, {NULL, NULL, FALSE, NULL}, diff --git a/geanylua/glspi.h b/geanylua/glspi.h index 9f172b8e2..e05415776 100644 --- a/geanylua/glspi.h +++ b/geanylua/glspi.h @@ -135,7 +135,7 @@ void glspi_init_mnu_funcs(lua_State *L); void glspi_init_sci_funcs(lua_State *L); /* custom dialogs module */ void glspi_init_gsdlg_module(lua_State *L, GsDlgRunHook hook, GtkWindow *toplevel); -void glspi_run_script(const gchar *script_file, gint caller, GKeyFile*proj, const gchar *script_dir); +void glspi_run_script(const gchar *script_file, gint caller, GKeyFile*proj, const gchar *script_dir, const gchar *script_cache); /* Pass TRUE to create hashes, FALSE to destroy them */ void glspi_set_sci_cmd_hash(gboolean create); diff --git a/geanylua/glspi_init.c b/geanylua/glspi_init.c index f48b86788..333f952e1 100644 --- a/geanylua/glspi_init.c +++ b/geanylua/glspi_init.c @@ -5,155 +5,276 @@ #include "glspi.h" +// This macro sets the script filename if it isn't already set. Since the +// filename is set only once, setting it to NULL afterwards disables the script. +#define SET_SCRIPT_FILENAME(_sc) \ + static gboolean script_checked = FALSE; \ + static gchar *script_fn = NULL; \ + if (!script_checked && !script_fn) { \ + script_fn = g_strconcat(geany->app->configdir, (_sc), NULL); \ + script_checked = TRUE; \ + } -#define DIR_SEP G_DIR_SEPARATOR_S - -#define USER_SCRIPT_FOLDER DIR_SEP "plugins" DIR_SEP "geanylua" - -#define EVENTS_FOLDER USER_SCRIPT_FOLDER DIR_SEP "events" DIR_SEP - -#define ON_SAVED_SCRIPT EVENTS_FOLDER "saved.lua" -#define ON_OPENED_SCRIPT EVENTS_FOLDER "opened.lua" -#define ON_CREATED_SCRIPT EVENTS_FOLDER "created.lua" -#define ON_ACTIVATED_SCRIPT EVENTS_FOLDER "activated.lua" - -#define ON_PROJ_OPENED_SCRIPT EVENTS_FOLDER "proj-opened.lua" -#define ON_PROJ_SAVED_SCRIPT EVENTS_FOLDER "proj-saved.lua" -#define ON_PROJ_CLOSED_SCRIPT EVENTS_FOLDER "proj-closed.lua" - -#define ON_INIT_SCRIPT EVENTS_FOLDER "init.lua" -#define ON_CLEANUP_SCRIPT EVENTS_FOLDER "cleanup.lua" -#define ON_CONFIGURE_SCRIPT EVENTS_FOLDER "configure.lua" +// This macro disables a script if the file doesn't exist. +#define DISABLE_SCRIPT_IF_NOT_EXIST() \ + do { \ + if (script_fn && !g_file_test(script_fn, G_FILE_TEST_IS_REGULAR)) { \ + g_free(script_fn); \ + script_fn = NULL; \ + } \ + } while (0) + +// This macro runs scripts without associating them with documents. +#define RUN_SCRIPT() \ + do { \ + if (script_fn && g_file_test(script_fn, G_FILE_TEST_IS_REGULAR)) { \ + glspi_run_script(script_fn, 0, NULL, SD, NULL); \ + } \ + } while (0) + +// This macro runs a script associated with a doc index. +#define RUN_SCRIPT_IDX() \ + do { \ + gint idx = doc->index; \ + if (script_fn && g_file_test(script_fn, G_FILE_TEST_IS_REGULAR)) { \ + glspi_run_script(script_fn, idx + 1, NULL, SD, NULL); \ + } \ + } while (0) + +// This macro caches and runs a script associated with a doc index. +// Its purpose is to improve performance on high-latency network devices. +#define CACHE_RUN_SCRIPT_IDX() \ + do { \ + static gchar *script_cache = NULL; \ + if (script_fn && !script_cache) { \ + gsize length = 0; \ + g_file_get_contents(script_fn, &script_cache, &length, NULL); \ + if (script_cache && length != strlen(script_cache)) { \ + g_free(script_cache); \ + script_cache = NULL; \ + g_free(script_fn); \ + script_fn = NULL; \ + } \ + } \ + gint idx = doc->index; \ + if (script_fn && script_cache) { \ + glspi_run_script(script_fn, idx + 1, NULL, SD, script_cache); \ + } \ + } while (0) + +// This macro caches and runs scripts without associating with documents. +#define CACHE_RUN_SCRIPT() \ + do { \ + static gchar *script_cache = NULL; \ + if (script_fn && !script_cache) { \ + gsize length = 0; \ + g_file_get_contents(script_fn, &script_cache, &length, NULL); \ + if (script_cache && length != strlen(script_cache)) { \ + g_free(script_cache); \ + script_cache = NULL; \ + } \ + } \ + if (script_cache) { \ + glspi_run_script(script_fn, 0, NULL, SD, script_cache); \ + } \ + } while (0) + +#define DIR_SEP G_DIR_SEPARATOR_S +#define USER_SCRIPT_FOLDER DIR_SEP "plugins" DIR_SEP "geanylua" +#define EVENTS_FOLDER USER_SCRIPT_FOLDER DIR_SEP "events" DIR_SEP + +#define ALLOW_DEPRECATED_SCRIPTS 1 +#ifdef ALLOW_DEPRECATED_SCRIPTS +// (Oct 2021): Use the old script if it exists and new one does not. +// TODO: Someday, show only the warning message. +// TODO: Eventually, stop checking for the old scripts entirely. +#define FIND_DEPRECATED_SCRIPT(_ns) \ + do { \ + gchar *tmp_script = NULL; \ + tmp_script = g_strconcat(geany->app->configdir, (_ns##_OLD), NULL); \ + if (!script_fn) { \ + script_fn = g_strconcat(geany->app->configdir, (_ns), NULL); \ + } \ + if (g_file_test(tmp_script, G_FILE_TEST_IS_REGULAR) && \ + !g_file_test(script_fn, G_FILE_TEST_IS_REGULAR)) { \ + g_free(script_fn); \ + script_fn = tmp_script; \ + msgwin_status_add("GeanyLua Warning: Found deprecated script " \ + "'%s%s'. Please switch to '%s%s'.", \ + geany->app->configdir, (_ns##_OLD), \ + geany->app->configdir, (_ns)); \ + } else { \ + g_free(tmp_script); \ + } \ + } while (0) + +#define ON_DOCUMENT_SAVE_SCRIPT_OLD EVENTS_FOLDER "saved.lua" +#define ON_DOCUMENT_OPEN_SCRIPT_OLD EVENTS_FOLDER "opened.lua" +#define ON_DOCUMENT_NEW_SCRIPT_OLD EVENTS_FOLDER "created.lua" +#define ON_DOCUMENT_ACTIVATE_SCRIPT_OLD EVENTS_FOLDER "activated.lua" +#define ON_PROJECT_OPEN_SCRIPT_OLD EVENTS_FOLDER "proj-opened.lua" +#define ON_PROJECT_SAVE_SCRIPT_OLD EVENTS_FOLDER "proj-saved.lua" +#define ON_PROJECT_CLOSE_SCRIPT_OLD EVENTS_FOLDER "proj-closed.lua" +#else +#define FIND_DEPRECATED_SCRIPT(_sv, _ns) +#endif // ALLOW_DEPRECATED_SCRIPTS + +// Scripts to respond to Geany signals +#define ON_DOCUMENT_ACTIVATE_SCRIPT EVENTS_FOLDER "document-activate.lua" +#define ON_DOCUMENT_BEFORE_SAVE_SCRIPT EVENTS_FOLDER "document-before-save.lua" +#define ON_DOCUMENT_CLOSE_SCRIPT EVENTS_FOLDER "document-close.lua" +#define ON_DOCUMENT_FILETYPE_SET_SCRIPT \ + EVENTS_FOLDER "document-filetype-set.lua" +#define ON_DOCUMENT_NEW_SCRIPT EVENTS_FOLDER "document-new.lua" +#define ON_DOCUMENT_OPEN_SCRIPT EVENTS_FOLDER "document-open.lua" +#define ON_DOCUMENT_RELOAD_SCRIPT EVENTS_FOLDER "document-reload.lua" +#define ON_DOCUMENT_SAVE_SCRIPT EVENTS_FOLDER "document-save.lua" + +#define ON_PROJECT_BEFORE_CLOSE_SCRIPT EVENTS_FOLDER "project-before-close.lua" +#define ON_PROJECT_CLOSE_SCRIPT EVENTS_FOLDER "project-close.lua" +#define ON_PROJECT_DIALOG_CLOSE_SCRIPT EVENTS_FOLDER "project-dialog-close.lua" +#define ON_PROJECT_DIALOG_CONFIRMED_SCRIPT \ + EVENTS_FOLDER "project-dialog-confirmed.lua" +#define ON_PROJECT_DIALOG_OPEN_SCRIPT EVENTS_FOLDER "project-dialog-open.lua" +#define ON_PROJECT_OPEN_SCRIPT EVENTS_FOLDER "project-open.lua" +#define ON_PROJECT_SAVE_SCRIPT EVENTS_FOLDER "project-save.lua" + +#define ON_BUILD_START_SCRIPT EVENTS_FOLDER "build-start.lua" +#define ON_EDITOR_NOTIFY_SCRIPT EVENTS_FOLDER "editor-notify.lua" +#define ON_GEANY_STARTUP_COMPLETE_SCRIPT \ + EVENTS_FOLDER "geany-startup-complete.lua" +#define ON_KEY_PRESS_SCRIPT EVENTS_FOLDER "key-press.lua" +#define ON_UPDATE_EDITOR_MENU_SCRIPT EVENTS_FOLDER "update-editor-menu.lua" + +#define ON_INIT_SCRIPT EVENTS_FOLDER "init.lua" +#define ON_CLEANUP_SCRIPT EVENTS_FOLDER "cleanup.lua" +#define ON_CONFIGURE_SCRIPT EVENTS_FOLDER "configure.lua" #define HOTKEYS_CFG DIR_SEP "hotkeys.cfg" #define MAX_HOT_KEYS 100 PLUGIN_EXPORT -const gchar* glspi_version = VERSION; +const gchar *glspi_version = VERSION; PLUGIN_EXPORT const guint glspi_abi = GEANY_ABI_VERSION; -GeanyData *glspi_geany_data=NULL; -GeanyPlugin *glspi_geany_plugin=NULL; +GeanyData *glspi_geany_data = NULL; +GeanyPlugin *glspi_geany_plugin = NULL; static struct { GtkWidget *menu_item; gchar *script_dir; - gchar *on_saved_script; - gchar *on_created_script; - gchar *on_opened_script; - gchar *on_activated_script; - gchar *on_init_script; - gchar *on_cleanup_script; - gchar *on_configure_script; - gchar *on_proj_opened_script; - gchar *on_proj_saved_script; - gchar *on_proj_closed_script; + GSList *script_list; GtkAccelGroup *acc_grp; GeanyKeyGroup *keybind_grp; gchar **keybind_scripts; } local_data; -#define SD local_data.script_dir +#define SD local_data.script_dir #define KG local_data.keybind_grp #define KS local_data.keybind_scripts - /* Called by Geany, run a script associated with a keybinding. */ -static void kb_activate(guint key_id) -{ - if ((key_idapp->debug_mode) { \ - g_printerr("%s: %s\n", PLUGIN_NAME, msg); \ -} \ -g_error_free(err); \ -g_key_file_free(kf); \ -kf=NULL; - +#define KEYFILE_FAIL(msg) \ + if (geany->app->debug_mode) { \ + g_printerr("%s: %s\n", PLUGIN_NAME, msg); \ + } \ + g_error_free(err); \ + g_key_file_free(kf); \ + kf = NULL; /* Initialize the interface to Geany's keybindings API */ -static void hotkey_init(void) -{ - gchar *hotkeys_cfg=g_strconcat(SD,HOTKEYS_CFG,NULL); +static void hotkey_init(void) { + gchar *hotkeys_cfg = g_strconcat(SD, HOTKEYS_CFG, NULL); hotkey_cleanup(); /* Make sure we are in initial state. */ - if (g_file_test(hotkeys_cfg,G_FILE_TEST_IS_REGULAR)) { - GError *err=NULL; - gchar*all=NULL; + if (g_file_test(hotkeys_cfg, G_FILE_TEST_IS_REGULAR)) { + GError *err = NULL; + gchar *all = NULL; gsize len; - if (g_file_get_contents(hotkeys_cfg,&all,&len,&err)) { - gchar**lines=g_strsplit(all, "\n", 0); + if (g_file_get_contents(hotkeys_cfg, &all, &len, &err)) { + gchar **lines = g_strsplit(all, "\n", 0); gint i; - gint n=0; + gint n = 0; g_free(all); - for (i=0; lines[i]; i++) { + for (i = 0; lines[i]; i++) { g_strstrip(lines[i]); - if ((lines[i][0]!='#')&&(lines[i][0]!='\0')) { + if ((lines[i][0] != '#') && (lines[i][0] != '\0')) { n++; - if (n==MAX_HOT_KEYS) { break; } + if (n == MAX_HOT_KEYS) { + break; + } } } - KS=g_new0(gchar*, n+1); - n=0; - for (i=0; lines[i]; i++) { - if ((lines[i][0]!='#')&&(lines[i][0]!='\0')) { + KS = g_new0(gchar *, n + 1); + n = 0; + for (i = 0; lines[i]; i++) { + if ((lines[i][0] != '#') && (lines[i][0] != '\0')) { if (g_path_is_absolute(lines[i])) { - KS[n]=g_strdup(lines[i]); + KS[n] = g_strdup(lines[i]); } else { - KS[n]=g_build_filename(SD, lines[i], NULL); + KS[n] = g_build_filename(SD, lines[i], NULL); } n++; - if (n==MAX_HOT_KEYS) { break; } + if (n == MAX_HOT_KEYS) { + break; + } } } g_strfreev(lines); - KG=plugin_set_key_group(glspi_geany_plugin, "lua_scripts", n, NULL); - for (i=0; iindex; - if (g_file_test(local_data.on_created_script,G_FILE_TEST_IS_REGULAR)) { - glspi_run_script(local_data.on_created_script,idx+1, NULL, SD); - } +/* + * Callbacks to run scripts + */ +static void on_build_start(GObject *obj, GeanyDocument *doc, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_BUILD_START_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT_IDX(); } +static void on_editor_notify(GObject *obj, GeanyDocument *doc, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_EDITOR_NOTIFY_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT_IDX(); +} -static void on_doc_save(GObject *obj, GeanyDocument *doc, gpointer user_data) -{ - gint idx = doc->index; - if (g_file_test(local_data.on_saved_script,G_FILE_TEST_IS_REGULAR)) { - glspi_run_script(local_data.on_saved_script,idx+1, NULL, SD); - } +static void on_geany_startup_complete(GObject *obj, GeanyDocument *doc, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_GEANY_STARTUP_COMPLETE_SCRIPT); + CACHE_RUN_SCRIPT(); } +static void on_key_press(GObject *obj, GeanyDocument *doc, gpointer user_data) { + SET_SCRIPT_FILENAME(ON_KEY_PRESS_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT_IDX(); +} +static void on_update_editor_menu(GObject *obj, GeanyDocument *doc, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_UPDATE_EDITOR_MENU_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT_IDX(); +} -static void on_doc_open(GObject *obj, GeanyDocument *doc, gpointer user_data) -{ - gint idx = doc->index; - if (g_file_test(local_data.on_opened_script,G_FILE_TEST_IS_REGULAR)) { - glspi_run_script(local_data.on_opened_script,idx+1, NULL, SD); - } +static void on_document_new(GObject *obj, GeanyDocument *doc, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_DOCUMENT_NEW_SCRIPT); + FIND_DEPRECATED_SCRIPT(ON_DOCUMENT_NEW_SCRIPT); + CACHE_RUN_SCRIPT_IDX(); } +static void on_document_open(GObject *obj, GeanyDocument *doc, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_DOCUMENT_OPEN_SCRIPT); + FIND_DEPRECATED_SCRIPT(ON_DOCUMENT_OPEN_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT_IDX(); +} +static void on_document_save(GObject *obj, GeanyDocument *doc, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_DOCUMENT_SAVE_SCRIPT); + FIND_DEPRECATED_SCRIPT(ON_DOCUMENT_SAVE_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT_IDX(); +} -static void on_doc_activate(GObject *obj, GeanyDocument *doc, gpointer user_data) -{ - gint idx = doc->index; - if (g_file_test(local_data.on_activated_script,G_FILE_TEST_IS_REGULAR)) { - glspi_run_script(local_data.on_activated_script,idx+1, NULL, SD); - } +static void on_document_activate(GObject *obj, GeanyDocument *doc, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_DOCUMENT_ACTIVATE_SCRIPT); + FIND_DEPRECATED_SCRIPT(ON_DOCUMENT_ACTIVATE_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT_IDX(); } +static void on_document_close(GObject *obj, GeanyDocument *doc, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_DOCUMENT_CLOSE_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT_IDX(); +} +static void on_document_before_save(GObject *obj, GeanyDocument *doc, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_DOCUMENT_BEFORE_SAVE_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT_IDX(); +} -static void on_proj_open(GObject *obj, GKeyFile *config, gpointer user_data) -{ - if (g_file_test(local_data.on_proj_opened_script,G_FILE_TEST_IS_REGULAR)) { - glspi_run_script(local_data.on_proj_opened_script,0,config, SD); - } +static void on_document_filetype_set(GObject *obj, GeanyDocument *doc, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_DOCUMENT_FILETYPE_SET_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT_IDX(); } +static void on_document_reload(GObject *obj, GeanyDocument *doc, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_DOCUMENT_RELOAD_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT_IDX(); +} +static void on_project_open(GObject *obj, GKeyFile *config, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_PROJECT_OPEN_SCRIPT); + FIND_DEPRECATED_SCRIPT(ON_PROJECT_OPEN_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT(); +} -static void on_proj_save(GObject *obj, GKeyFile *config, gpointer user_data) -{ - if (g_file_test(local_data.on_proj_saved_script,G_FILE_TEST_IS_REGULAR)) { - glspi_run_script(local_data.on_proj_saved_script,0,config, SD); - } +static void on_project_close(GObject *obj, GKeyFile *config, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_PROJECT_CLOSE_SCRIPT); + FIND_DEPRECATED_SCRIPT(ON_PROJECT_CLOSE_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT(); } +static void on_project_save(GObject *obj, GKeyFile *config, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_PROJECT_SAVE_SCRIPT); + FIND_DEPRECATED_SCRIPT(ON_PROJECT_SAVE_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT(); +} +static void on_project_before_close(GObject *obj, GKeyFile *config, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_PROJECT_BEFORE_CLOSE_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT(); +} +static void on_project_dialog_close(GObject *obj, GKeyFile *config, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_PROJECT_DIALOG_CLOSE_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT(); +} -static void on_proj_close(GObject *obj, gpointer user_data) -{ - if (g_file_test(local_data.on_proj_closed_script,G_FILE_TEST_IS_REGULAR)) { - glspi_run_script(local_data.on_proj_closed_script,0, NULL, SD); - } +static void on_project_dialog_confirmed(GObject *obj, GKeyFile *config, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_PROJECT_DIALOG_CONFIRMED_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT(); } +static void on_project_dialog_open(GObject *obj, GKeyFile *config, + gpointer user_data) { + SET_SCRIPT_FILENAME(ON_PROJECT_DIALOG_OPEN_SCRIPT); + DISABLE_SCRIPT_IF_NOT_EXIST(); + CACHE_RUN_SCRIPT(); +} PLUGIN_EXPORT -PluginCallback glspi_geany_callbacks[] = { - {"document-new", (GCallback) &on_doc_new, TRUE, NULL}, - {"document-open", (GCallback) &on_doc_open, TRUE, NULL}, - {"document-save", (GCallback) &on_doc_save, TRUE, NULL}, - {"document-activate", (GCallback) &on_doc_activate, TRUE, NULL}, - {"project-open", (GCallback) &on_proj_open, TRUE, NULL}, - {"project-save", (GCallback) &on_proj_save, TRUE, NULL}, - {"project-close", (GCallback) &on_proj_close, TRUE, NULL}, - {NULL, NULL, FALSE, NULL} -}; - - +PluginCallback glspi_geany_callbacks[] = { + {"build_start", (GCallback)&on_build_start, TRUE, NULL}, + {"editor_notify", (GCallback)&on_editor_notify, TRUE, NULL}, + {"geany_startup_complete", (GCallback)&on_geany_startup_complete, TRUE, + NULL}, + {"key_press", (GCallback)&on_key_press, TRUE, NULL}, + {"update_editor_menu", (GCallback)&on_update_editor_menu, TRUE, NULL}, + {"document_activate", (GCallback)&on_document_activate, TRUE, NULL}, + {"document_before_save", (GCallback)&on_document_before_save, TRUE, NULL}, + {"document_close", (GCallback)&on_document_close, TRUE, NULL}, + {"document_filetype_set", (GCallback)&on_document_filetype_set, TRUE, + NULL}, + {"document_new", (GCallback)&on_document_new, TRUE, NULL}, + {"document_open", (GCallback)&on_document_open, TRUE, NULL}, + {"document_reload", (GCallback)&on_document_reload, TRUE, NULL}, + {"document_save", (GCallback)&on_document_save, TRUE, NULL}, + {"project_before_close", (GCallback)&on_project_before_close, TRUE, NULL}, + {"project_close", (GCallback)&on_project_close, TRUE, NULL}, + {"project_dialog_close", (GCallback)&on_project_dialog_close, TRUE, NULL}, + {"project_dialog_confirmed", (GCallback)&on_project_dialog_confirmed, FALSE, + NULL}, + {"project_dialog_open", (GCallback)&on_project_dialog_open, TRUE, NULL}, + {"project_open", (GCallback)&on_project_open, TRUE, NULL}, + {"project_save", (GCallback)&on_project_save, TRUE, NULL}, + {NULL, NULL, FALSE, NULL}}; /* Callback when the menu item is clicked */ -static void menu_item_activate(GtkMenuItem * menuitem, gpointer gdata) -{ - glspi_run_script(gdata, 0,NULL, SD); +static void menu_item_activate(GtkMenuItem *menuitem, gpointer gdata) { + glspi_run_script(gdata, 0, NULL, SD, NULL); } - -#define is_blank(c) ( (c==32) || (c==9) ) - +#define is_blank(c) ((c == 32) || (c == 9)) /* Check if the script file begins with a special comment in the form: @@ -272,36 +481,42 @@ static void menu_item_activate(GtkMenuItem * menuitem, gpointer gdata) If we find one, parse it, and bind that key combo to its menu item. See gtk_accelerator_parse() doc for more info on accel syntax... */ -static void assign_accel(GtkWidget*w, char*fn) -{ - FILE*f=fopen(fn,"r"); +static void assign_accel(GtkWidget *w, char *fn) { + FILE *f = fopen(fn, "r"); gchar buf[512]; gint len; - if (!f) { return; } - len=fread(buf,1,sizeof(buf)-1,f); - if (len>0) { - gchar*p1=buf; - buf[len]='\0'; - while (*p1 && is_blank(*p1)) p1++; - if ( strncmp(p1,"--", 2) == 0 ) { - p1+=2; - while (*p1 && is_blank(*p1)) p1++; - if ( strncmp(p1,"@ACCEL@", 7) == 0 ) { - guint key=0; - GdkModifierType mods=0; - p1+=7; - while (*p1 && is_blank(*p1)) p1++; + if (!f) { + return; + } + len = fread(buf, 1, sizeof(buf) - 1, f); + if (len > 0) { + gchar *p1 = buf; + buf[len] = '\0'; + while (*p1 && is_blank(*p1)) + p1++; + if (strncmp(p1, "--", 2) == 0) { + p1 += 2; + while (*p1 && is_blank(*p1)) + p1++; + if (strncmp(p1, "@ACCEL@", 7) == 0) { + guint key = 0; + GdkModifierType mods = 0; + p1 += 7; + while (*p1 && is_blank(*p1)) + p1++; if (*p1) { - gchar*p2=p1; - while ( (*p2) && (!isspace(*p2)) ) { p2++; } - *p2='\0'; + gchar *p2 = p1; + while ((*p2) && (!isspace(*p2))) { + p2++; + } + *p2 = '\0'; gtk_accelerator_parse(p1, &key, &mods); - if ( key && mods ) { + if (key && mods) { if (!local_data.acc_grp) { - local_data.acc_grp=gtk_accel_group_new(); + local_data.acc_grp = gtk_accel_group_new(); } - gtk_widget_add_accelerator(w, - "activate",local_data.acc_grp,key,mods,GTK_ACCEL_VISIBLE); + gtk_widget_add_accelerator(w, "activate", local_data.acc_grp, + key, mods, GTK_ACCEL_VISIBLE); } } } @@ -310,40 +525,49 @@ static void assign_accel(GtkWidget*w, char*fn) fclose(f); } - - - -static GtkWidget* new_menu(GtkWidget *parent, const gchar* script_dir, const gchar*title); +static GtkWidget *new_menu(GtkWidget *parent, const gchar *script_dir, + const gchar *title); /* GSList "for each" callback to create a menu item for each found script */ -static void init_menu(gpointer data, gpointer user_data) -{ +static void init_menu(gpointer data, gpointer user_data) { g_return_if_fail(data && user_data); - if (g_file_test(data,G_FILE_TEST_IS_REGULAR)) { + if (g_file_test(data, G_FILE_TEST_IS_REGULAR)) { gchar *dot = strrchr(data, '.'); - if ( dot && (((gpointer)dot)>data) && (g_ascii_strcasecmp(dot, ".lua")==0) ) { + if (dot && (((gpointer)dot) > data) && + (g_ascii_strcasecmp(dot, ".lua") == 0)) { GtkWidget *item; - gchar*label=strrchr(data,DIR_SEP[0]); - gchar *tmp=NULL; - if (label) { label++; } else { label=data; } - tmp=g_malloc0(strlen(label)); - strncpy(tmp, label, dot-label); - label=tmp; - label=fixup_label(label); - if ('_'==*(dot-1)) { strcpy(strchr(label, '\0')-1, "..."); } + gchar *label = strrchr(data, DIR_SEP[0]); + gchar *tmp = NULL; + if (label) { + label++; + } else { + label = data; + } + tmp = g_malloc0(strlen(label)); + strncpy(tmp, label, dot - label); + label = tmp; + label = fixup_label(label); + if ('_' == *(dot - 1)) { + strcpy(strchr(label, '\0') - 1, "..."); + } item = gtk_menu_item_new_with_mnemonic(label); g_free(label); gtk_container_add(GTK_CONTAINER(user_data), item); g_signal_connect(G_OBJECT(item), "activate", - G_CALLBACK(menu_item_activate), data); + G_CALLBACK(menu_item_activate), data); assign_accel(item, data); } } else { - if (g_file_test(data,G_FILE_TEST_IS_DIR)) { - gchar*label=strrchr(data,DIR_SEP[0]); - if (label) { label++; } else { label=data; } - if ((g_ascii_strcasecmp(label,"events")!=0)&&(g_ascii_strcasecmp(label,"support")!=0)) { - label=g_strdup(label); + if (g_file_test(data, G_FILE_TEST_IS_DIR)) { + gchar *label = strrchr(data, DIR_SEP[0]); + if (label) { + label++; + } else { + label = data; + } + if ((g_ascii_strcasecmp(label, "events") != 0) && + (g_ascii_strcasecmp(label, "support") != 0)) { + label = g_strdup(label); fixup_label(label); new_menu(user_data, data, label); /* Recursive */ g_free(label); @@ -352,11 +576,10 @@ static void init_menu(gpointer data, gpointer user_data) } } - - -static GtkWidget* new_menu(GtkWidget *parent, const gchar* script_dir, const gchar*title) -{ - GSList *script_names=utils_get_file_list_full(script_dir, TRUE, TRUE, NULL); +static GtkWidget *new_menu(GtkWidget *parent, const gchar *script_dir, + const gchar *title) { + GSList *script_names = + utils_get_file_list_full(script_dir, TRUE, TRUE, NULL); if (script_names) { GtkWidget *menu = gtk_menu_new(); GtkWidget *menu_item = gtk_menu_item_new_with_mnemonic(title); @@ -364,36 +587,33 @@ static GtkWidget* new_menu(GtkWidget *parent, const gchar* script_dir, const gch gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), menu); gtk_container_add(GTK_CONTAINER(parent), menu_item); gtk_widget_show_all(menu_item); - local_data.script_list=g_slist_concat(local_data.script_list,script_names); + local_data.script_list = + g_slist_concat(local_data.script_list, script_names); return menu_item; } g_printerr("%s: No scripts found in %s\n", PLUGIN_NAME, script_dir); return NULL; } - - -static void build_menu(void) -{ +static void build_menu(void) { local_data.script_list = NULL; - local_data.acc_grp=NULL; - local_data.menu_item=new_menu(main_widgets->tools_menu, - local_data.script_dir, _("_Lua Scripts")); + local_data.acc_grp = NULL; + local_data.menu_item = new_menu(main_widgets->tools_menu, + local_data.script_dir, _("_Lua Scripts")); if (local_data.acc_grp) { - gtk_window_add_accel_group(GTK_WINDOW(main_widgets->window), local_data.acc_grp); + gtk_window_add_accel_group(GTK_WINDOW(main_widgets->window), + local_data.acc_grp); } } - -static gchar *get_data_dir(void) -{ +static gchar *get_data_dir(void) { #ifdef G_OS_WIN32 gchar *install_dir, *result; -# if GLIB_CHECK_VERSION(2, 16, 0) +#if GLIB_CHECK_VERSION(2, 16, 0) install_dir = g_win32_get_package_installation_directory_of_module(NULL); -# else +#else install_dir = g_win32_get_package_installation_directory(NULL, NULL); -# endif +#endif result = g_strconcat(install_dir, "\\share", NULL); g_free(install_dir); return result; @@ -402,98 +622,65 @@ static gchar *get_data_dir(void) #endif } - - /* Called by Geany to initialize the plugin */ PLUGIN_EXPORT -void glspi_init (GeanyData *data, GeanyPlugin *plugin) -{ +void glspi_init(GeanyData *data, GeanyPlugin *plugin) { glspi_geany_data = data; glspi_geany_plugin = plugin; local_data.script_dir = - g_strconcat(geany->app->configdir, USER_SCRIPT_FOLDER, NULL); + g_strconcat(geany->app->configdir, USER_SCRIPT_FOLDER, NULL); if (!g_file_test(local_data.script_dir, G_FILE_TEST_IS_DIR)) { gchar *datadir = get_data_dir(); g_free(local_data.script_dir); - local_data.script_dir = - g_build_path(G_DIR_SEPARATOR_S, datadir, "geany-plugins", "geanylua", NULL); + local_data.script_dir = g_build_path(G_DIR_SEPARATOR_S, datadir, + "geany-plugins", "geanylua", NULL); g_free(datadir); } if (geany->app->debug_mode) { - g_printerr(_(" ==>> %s: Building menu from '%s'\n"), - PLUGIN_NAME, local_data.script_dir); + g_printerr(_(" ==>> %s: Building menu from '%s'\n"), PLUGIN_NAME, + local_data.script_dir); } - local_data.on_saved_script = - g_strconcat(geany->app->configdir, ON_SAVED_SCRIPT, NULL); - local_data.on_opened_script = - g_strconcat(geany->app->configdir, ON_OPENED_SCRIPT, NULL); - local_data.on_created_script = - g_strconcat(geany->app->configdir, ON_CREATED_SCRIPT, NULL); - local_data.on_activated_script = - g_strconcat(geany->app->configdir, ON_ACTIVATED_SCRIPT, NULL); - local_data.on_init_script = - g_strconcat(geany->app->configdir, ON_INIT_SCRIPT, NULL); - local_data.on_cleanup_script = - g_strconcat(geany->app->configdir, ON_CLEANUP_SCRIPT, NULL); - local_data.on_configure_script = - g_strconcat(geany->app->configdir, ON_CONFIGURE_SCRIPT, NULL); - local_data.on_proj_opened_script = - g_strconcat(geany->app->configdir, ON_PROJ_OPENED_SCRIPT, NULL); - local_data.on_proj_saved_script = - g_strconcat(geany->app->configdir, ON_PROJ_SAVED_SCRIPT, NULL); - local_data.on_proj_closed_script = - g_strconcat(geany->app->configdir, ON_PROJ_CLOSED_SCRIPT, NULL); glspi_set_sci_cmd_hash(TRUE); glspi_set_key_cmd_hash(TRUE); build_menu(); hotkey_init(); - if (g_file_test(local_data.on_init_script,G_FILE_TEST_IS_REGULAR)) { - glspi_run_script(local_data.on_init_script,0,NULL, SD); - } -} - + SET_SCRIPT_FILENAME(ON_INIT_SCRIPT); + RUN_SCRIPT(); +} /* GSList "for each" callback to free our script list items */ -static void free_script_names(gpointer data, gpointer user_data) -{ - if (data) { g_free(data); } +static void free_script_names(gpointer data, gpointer user_data) { + if (data) { + g_free(data); + } } - -static void remove_menu(void) -{ - if (local_data.acc_grp) { g_object_unref(local_data.acc_grp); } - if (local_data.menu_item) { gtk_widget_destroy(local_data.menu_item); } +static void remove_menu(void) { + if (local_data.acc_grp) { + g_object_unref(local_data.acc_grp); + } + if (local_data.menu_item) { + gtk_widget_destroy(local_data.menu_item); + } } - -#define done(f) if (local_data.f) g_free(local_data.f) +#define done(f) \ + if (local_data.f) \ + g_free(local_data.f) /* Called by Geany when it is time to free the plugin's resources */ PLUGIN_EXPORT -void glspi_cleanup(void) -{ +void glspi_cleanup(void) { + SET_SCRIPT_FILENAME(ON_CLEANUP_SCRIPT); + RUN_SCRIPT(); - if (g_file_test(local_data.on_cleanup_script,G_FILE_TEST_IS_REGULAR)) { - glspi_run_script(local_data.on_cleanup_script,0,NULL, SD); - } remove_menu(); hotkey_cleanup(); done(script_dir); - done(on_saved_script); - done(on_created_script); - done(on_opened_script); - done(on_activated_script); - done(on_init_script); - done(on_cleanup_script); - done(on_configure_script); - done(on_proj_opened_script); - done(on_proj_saved_script); - done(on_proj_closed_script); if (local_data.script_list) { g_slist_foreach(local_data.script_list, free_script_names, NULL); @@ -501,50 +688,45 @@ void glspi_cleanup(void) } glspi_set_sci_cmd_hash(FALSE); glspi_set_key_cmd_hash(FALSE); - } - - - - /* Called by geany when user clicks preferences button in plugin manager dialog. */ PLUGIN_EXPORT -void glspi_configure(GtkWidget *parent) -{ - if (g_file_test(local_data.on_configure_script,G_FILE_TEST_IS_REGULAR)) { - glspi_run_script(local_data.on_configure_script,0,NULL, SD); +void glspi_configure(GtkWidget *parent) { + SET_SCRIPT_FILENAME(ON_CONFIGURE_SCRIPT); + + if (g_file_test(script_fn, G_FILE_TEST_IS_REGULAR)) { + glspi_run_script(script_fn, 0, NULL, SD, NULL); } else { - gint flags=GTK_DIALOG_DESTROY_WITH_PARENT|GTK_DIALOG_MODAL; - gint type=GTK_MESSAGE_INFO; - GtkWidget *dlg=gtk_message_dialog_new( - GTK_WINDOW(parent),flags,type,GTK_BUTTONS_OK,_("Nothing to configure!")); - gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dlg), - _("You can create the script:\n\n\"%s\"\n\n" + gint flags = GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL; + gint type = GTK_MESSAGE_INFO; + GtkWidget *dlg = + gtk_message_dialog_new(GTK_WINDOW(parent), flags, type, + GTK_BUTTONS_OK, _("Nothing to configure!")); + gtk_message_dialog_format_secondary_text( + GTK_MESSAGE_DIALOG(dlg), + _("You can create the script:\n\n\"%s\"\n\n" "to add your own custom configuration dialog."), - local_data.on_configure_script); - gtk_window_set_title(GTK_WINDOW(dlg),PLUGIN_NAME); + script_fn); + gtk_window_set_title(GTK_WINDOW(dlg), PLUGIN_NAME); gtk_dialog_run(GTK_DIALOG(dlg)); gtk_widget_destroy(dlg); } } -static gint glspi_rescan(lua_State* L) { +static gint glspi_rescan(lua_State *L) { remove_menu(); build_menu(); hotkey_init(); return 0; } -static const struct luaL_reg glspi_mnu_funcs[] = { - {"rescan", glspi_rescan}, - {NULL,NULL} -}; - +static const struct luaL_reg glspi_mnu_funcs[] = {{"rescan", glspi_rescan}, + {NULL, NULL}}; void glspi_init_mnu_funcs(lua_State *L) { - luaL_register(L, NULL,glspi_mnu_funcs); + luaL_register(L, NULL, glspi_mnu_funcs); } diff --git a/geanylua/glspi_run.c b/geanylua/glspi_run.c index f41bd23b4..1a67e9f63 100644 --- a/geanylua/glspi_run.c +++ b/geanylua/glspi_run.c @@ -428,7 +428,7 @@ gint luaopen_libgeanylua(lua_State *L) /* Load and run the script */ -void glspi_run_script(const gchar *script_file, gint caller, GKeyFile*proj, const gchar *script_dir) +void glspi_run_script(const gchar *script_file, gint caller, GKeyFile*proj, const gchar *script_dir, const gchar *script_cache) { gint status; lua_State *L = glspi_state_new(); @@ -436,7 +436,13 @@ void glspi_run_script(const gchar *script_file, gint caller, GKeyFile*proj, cons #if 0 while (gtk_events_pending()) { gtk_main_iteration(); } #endif - status = luaL_loadfile(L, script_file); + + if (!script_cache) { + status = luaL_loadfile(L, script_file); + } else { + status = luaL_loadstring(L, script_cache); + } + switch (status) { case 0: { gint base = lua_gettop(L); /* function index */ @@ -466,4 +472,3 @@ void glspi_run_script(const gchar *script_file, gint caller, GKeyFile*proj, cons } glspi_state_done(L); } -